Appearance
CpAttachment 附件管理
对齐旧系统 AttachmentMgt.ts(订单/单据附件弹窗)。列表复用 CpGrid(文件名 / 类别 / 大小 / 上传人 / 时间,checkbox 多选),工具栏含上传 / 批量上传 / 下载 / 删除 / 预览,支持附件类别、审核锁定、权限位。inline 切换内联块 / 弹窗形态。
基础用法
基础用法
内联形态直接嵌页面;顶部按钮以弹窗形态打开同一组件。上传前按类别选择(报关单类别带日期录入);勾选行后可下载/删除/预览;开「已审核」锁定上传与删除。「分享」是 actions 插槽自定义按钮。
<template>
<div class="demo-col">
<div class="demo-row">
<el-button type="primary" @click="dialogVisible = true">
弹窗形态:打开附件管理
</el-button>
<el-switch v-model="approved" active-text="已审核(锁上传/删除)" />
<span class="demo-value">{{ hint }}</span>
</div>
<!-- 内联形态 -->
<CpAttachment
inline
:files="files"
:categories="categories"
:upload="upload"
:remove="remove"
:preview="preview"
:load="load"
:approved="approved"
batch-upload
:height="260"
@upload-error="(f, e) => (hint = `上传失败 ${f.name}: ${e}`)"
>
<template #actions="{ selected }">
<el-button
size="small"
:disabled="!selected.length"
@click="onShare(selected)"
>
分享({{ selected.length }})
</el-button>
</template>
</CpAttachment>
<!-- 弹窗形态:同一组件,inline 不传 -->
<CpAttachment
v-model:visible="dialogVisible"
title="订单附件"
:files="files"
:categories="categories"
:upload="upload"
:remove="remove"
:preview="preview"
:load="load"
:approved="approved"
batch-upload
/>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import type {
AttachmentCategory,
AttachmentFile,
AttachmentUploadMeta,
} from "../../src/index";
const hint = ref("");
const approved = ref(false);
const dialogVisible = ref(false);
const categories: AttachmentCategory[] = [
{ label: "提单 BL", value: "BL" },
{ label: "发票 Invoice", value: "INV" },
{ label: "装箱单 Packing", value: "PKG" },
{ label: "报关单", value: "CUS", hasDate: true },
];
const catName = (v?: string) =>
categories.find((c) => c.value === v)?.label ?? v ?? "";
const files = ref<AttachmentFile[]>([
{
uid: 1,
name: "HBL-SHLA2407.pdf",
type: "BL",
typeName: "提单 BL",
size: 348_000,
uploader: "李单证",
uploadTime: "2026-07-20 10:12",
url: "https://example.com/HBL-SHLA2407.pdf",
},
{
uid: 2,
name: "Commercial-Invoice.xlsx",
type: "INV",
typeName: "发票 Invoice",
size: 52_400,
uploader: "王船务",
uploadTime: "2026-07-21 14:03",
},
]);
let nextUid = 3;
/** 假上传:真实项目在此接后端上传接口。demo 直接把文件塞进列表。 */
function upload(file: File, meta: AttachmentUploadMeta): Promise<void> {
return new Promise((resolve) => {
setTimeout(() => {
files.value.push({
uid: nextUid++,
name: file.name,
type: meta.type,
typeName: catName(meta.type) + (meta.date ? `(${meta.date})` : ""),
size: file.size,
uploader: "我",
uploadTime: new Date().toLocaleString("zh-CN", { hour12: false }),
});
resolve();
}, 400);
});
}
function remove(uids: (string | number)[]): Promise<void> {
return new Promise((resolve) => {
files.value = files.value.filter((f) => !uids.includes(f.uid));
resolve();
});
}
function preview(file: AttachmentFile): string | void {
if (file.url) return file.url;
hint.value = `预览 ${file.name}(此文件无 url,真实项目走 preview 接口取临时 URL)`;
}
function load() {
hint.value = `已刷新列表(当前 ${files.value.length} 个附件)`;
}
function onShare(selected: AttachmentFile[]) {
hint.value = `分享: ${selected.map((f) => f.name).join(", ")}`;
}
</script>显示代码 ▼
接口契约
组件不绑后端,上传 / 下载 / 删除 / 预览全走 props 契约,复用业务侧现有请求封装与鉴权:
ts
// 上传:接后端上传接口,成功后组件自动调 load 刷新
upload: (file: File, meta: { type?: string; date?: string }) => Promise<void>
// 删除:接后端删除接口
remove: (uids: (string | number)[]) => Promise<void>
// 下载:不传则按 file.url 直接下载
download?: (files: AttachmentFile[]) => void | Promise<void>
// 预览:返回 URL 则组件新窗口打开,或业务侧自行处理(对齐旧版 PreviewFile 取临时 URL)
preview?: (file: AttachmentFile) => void | string | Promise<void | string>
// 刷新列表(对齐旧版 GetFileList)
load?: () => void | Promise<void>类别 / 审核 / 权限
| 能力 | 说明(对齐旧项目) |
|---|---|
categories | 附件类别;上传前弹类别选择,hasDate 类别附带日期录入(旧版 have-date) |
approved | 已审核锁定:禁用上传 / 删除(旧版 approved 逻辑) |
permissions | 权限位 { upload, download, delete, preview } 按位显隐工具栏(旧版 CompanyAttach* 权限),不传视为全部允许 |
batch-upload | 允许多选文件批量上传 |
#actions 插槽 | 自定义工具栏按钮,作用域参数拿到 selected |
API
属性 Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
v-model:visible | — | boolean | false |
files | 附件列表(受控) | AttachmentFile[] | () => [] |
upload | 上传实现:接后端上传接口,成功后组件触发 refresh | Function | — |
remove | 删除实现:接后端删除接口 | Function | — |
download | 下载实现:不传则用 file.url 直接下载 | Function | — |
preview | 预览实现:返回 URL 则组件新窗口打开,或业务侧自行处理 | Function | — |
load | 上传 / 删除后重新拉列表(对齐旧版 GetFileList) | Function | — |
categories | 附件类别;非空时上传前弹类别选择 | AttachmentCategory[] | () => [] |
batch-upload | 允许批量上传(多选文件) | boolean | — |
approved | 已审核:禁用上传 / 删除 | boolean | — |
permissions | 权限位;不传视为全部允许 | AttachmentPermissions | — |
inline | 内联块形态(默认弹窗) | boolean | — |
title | — | string | "附件管理" |
width | — | string | number | 720 |
height | — | number | string | 360 |
事件 Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
@closed | 弹窗关闭动画结束 | — |
@upload-error | 上传失败 | (File) |
方法 Expose
| 方法(ref 调用) | 说明 |
|---|---|
getSelected | 当前多选行 |
gridRef | — |
插槽 Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
actions | — | selected |