Appearance
BizAttachmentList 附件组
附件组的展示与轻管理:list 列表 / grid 卡片网格双形态、扩展名图标映射(pdf / word / excel / ppt / 图片 / 压缩包 / 音视频)、元信息(大小 / 上传人 / 时间)、预览与下载入口、编辑态删除 + 拖拽排序、敏感项掩码、折叠展开与加载骨架。
补齐附件链路的「展示」一环:录入用 BizUploadFile,单文件在线预览用 BizFileViewer。适用于合同 / 工单 / 审批详情页附件区、版本历史附件、消息附件清单。
基础用法(列表形态)
PDF
采购合同-2026-华东.pdf
2.4 MB王敏2026-09-12
DOC
补充协议-v2.docx
180.0 KB李强2026-10-03
XLS
报价明细.xlsx
94.0 KB王敏2026-10-03
IMG
现场照片.jpg
3.3 MB赵静2026-10-08
图标按扩展名映射并按类型着色(pdf 红 / office 蓝 / excel 绿…),hover 显示预览与下载操作。
<script setup lang="ts">
/** 场景:合同详情页附件区——列表形态基础(图标 + 元信息 + 预览下载) */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { BizAttachmentList } from 'vue3-ep-biz-lib'
import type { BizAttachmentItem } from 'vue3-ep-biz-lib'
const items = ref<BizAttachmentItem[]>([
{ id: '1', name: '采购合同-2026-华东.pdf', url: '#', size: 2_483_712, uploader: '王敏', uploadedAt: '2026-09-12' },
{ id: '2', name: '补充协议-v2.docx', url: '#', size: 184_320, uploader: '李强', uploadedAt: '2026-10-03' },
{ id: '3', name: '报价明细.xlsx', url: '#', size: 96_256, uploader: '王敏', uploadedAt: '2026-10-03' },
{ id: '4', name: '现场照片.jpg', url: '#', size: 3_506_176, uploader: '赵静', uploadedAt: '2026-10-08' },
])
</script>
<template>
<BizAttachmentList
:items="items"
@preview="({ item }) => ElMessage.info(`预览:${item.name}`)"
@download="({ item }) => ElMessage.success(`开始下载:${item.name}`)"
/>
</template>
显示代码
卡片网格
DOC
需求说明书.docx
256.0 KB产品部
ZIP
UI 设计稿.zip
46.0 MB设计部
PDF
验收报告.pdf
1.1 MB质检部
PDF
操作手册.pdf
5.0 MB实施组
视频
培训视频.mp4
149.0 MB实施组
layout="grid":卡片网格形态,grid-item-width 控制单项宽度(自适应铺满容器)。<script setup lang="ts">
/** 场景:项目交付物——卡片网格形态 */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { BizAttachmentList } from 'vue3-ep-biz-lib'
import type { BizAttachmentItem } from 'vue3-ep-biz-lib'
const items = ref<BizAttachmentItem[]>([
{ id: '1', name: '需求说明书.docx', url: '#', size: 262_144, uploader: '产品部' },
{ id: '2', name: 'UI 设计稿.zip', url: '#', size: 48_234_496, uploader: '设计部' },
{ id: '3', name: '验收报告.pdf', url: '#', size: 1_204_224, uploader: '质检部' },
{ id: '4', name: '操作手册.pdf', url: '#', size: 5_242_880, uploader: '实施组' },
{ id: '5', name: '培训视频.mp4', url: '#', size: 156_237_824, uploader: '实施组' },
])
</script>
<template>
<BizAttachmentList
:items="items"
layout="grid"
:grid-item-width="180"
@download="({ item }) => ElMessage.success(`下载:${item.name}`)"
/>
</template>
显示代码
预览联动 BizFileViewer
IMG
工程蓝图.png
1.1 MB
PDF
产品说明.pdf
2.4 MB
XLS
预算表.xlsx
94.0 KB
preview 事件联动 BizFileViewer 在线预览;无法预览的类型业务侧自行决定兜底。<script setup lang="ts">
/** 场景:预览集成——preview 事件联动 BizFileViewer(图片 / pdf 直接在线预览) */
import { ref } from 'vue'
import { BizAttachmentList, BizFileViewer } from 'vue3-ep-biz-lib'
import type { BizAttachmentItem } from 'vue3-ep-biz-lib'
const items = ref<BizAttachmentItem[]>([
{ id: '1', name: '工程蓝图.png', url: 'https://dummyimage.com/900x500/409eff/ffffff&text=Blueprint', size: 1_204_224 },
{ id: '2', name: '产品说明.pdf', url: '/demo.pdf', size: 2_483_712 },
{ id: '3', name: '预算表.xlsx', url: '#', size: 96_256 },
])
const activeUrl = ref<string>('')
const activeName = ref<string>('')
const onPreview = ({ item }: { item: BizAttachmentItem }): void => {
if (!item.url) return
activeUrl.value = item.url
activeName.value = item.name
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px">
<BizAttachmentList :items="items" @preview="onPreview" />
<BizFileViewer v-if="activeUrl !== ''" :src="activeUrl" :name="activeName" :height="240" />
<span v-else style="font-size: 12px; color: var(--el-text-color-secondary)">点击附件的「预览」图标在线查看(pdf 为演示地址,图片直接可看)</span>
</div>
</template>
显示代码
编辑态(删除 + 拖拽排序)
IMG
身份证正面.jpg
1.4 MB张三
PDF
营业执照.pdf
2.4 MB张三
PDF
开户许可.pdf
500.0 KB李四
DOC
授权委托书.docx
86.0 KB李四
editable 显示删除按钮并开启拖拽排序(拖拽高亮 + 落点亮线);remove / reorder 事件回传,items 由业务侧受控更新。<script setup lang="ts">
/** 场景:编辑态——删除(二次确认)+ 拖拽排序,reorder 回传新顺序 */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { BizAttachmentList } from 'vue3-ep-biz-lib'
import type { BizAttachmentItem } from 'vue3-ep-biz-lib'
const items = ref<BizAttachmentItem[]>([
{ id: '1', name: '身份证正面.jpg', url: '#', size: 1_506_176, uploader: '张三' },
{ id: '2', name: '营业执照.pdf', url: '#', size: 2_483_712, uploader: '张三' },
{ id: '3', name: '开户许可.pdf', url: '#', size: 512_000, uploader: '李四' },
{ id: '4', name: '授权委托书.docx', url: '#', size: 88_064, uploader: '李四' },
])
const onRemove = (item: BizAttachmentItem): void => {
items.value = items.value.filter((row) => row.id !== item.id)
ElMessage.success(`已删除:${item.name}`)
}
const onReorder = (next: BizAttachmentItem[]): void => {
items.value = next
ElMessage.info(`新顺序:${next.map((row) => row.name).join(' → ')}`)
}
</script>
<template>
<BizAttachmentList :items="items" editable @remove="onRemove" @reorder="onReorder" />
</template>
显示代码
敏感附件
XLS
***.xlsx
94.0 KBHR
PDF
***.pdf
5.0 MB审计组
PDF
月度经营通报.pdf
1.1 MB经营部
sensitive: true 的附件:文件名掩码(***.xlsx)、隐藏预览 / 下载入口、不可删除(锁形提示)——薪酬、审计类文件。<script setup lang="ts">
/** 场景:敏感附件——薪酬 / 审计文件掩码展示,预览下载入口隐藏 */
import { ref } from 'vue'
import { BizAttachmentList } from 'vue3-ep-biz-lib'
import type { BizAttachmentItem } from 'vue3-ep-biz-lib'
const items = ref<BizAttachmentItem[]>([
{ id: '1', name: '部门薪酬表-2026Q3.xlsx', size: 96_256, sensitive: true, uploader: 'HR' },
{ id: '2', name: '审计底稿.pdf', size: 5_242_880, sensitive: true, uploader: '审计组' },
{ id: '3', name: '月度经营通报.pdf', url: '#', size: 1_204_224, uploader: '经营部' },
])
</script>
<template>
<BizAttachmentList :items="items" editable />
</template>
显示代码
折叠展开
ZIP
设计稿-v0.1.zip
12.0 MB设计部2026-09-10
ZIP
设计稿-v0.2.zip
12.0 MB前端组2026-09-11
ZIP
设计稿-v0.3.zip
12.0 MB设计部2026-09-12
collapse-after 超过 N 项折叠(版本历史只看最近几版),底部「展开其余 X 项 / 收起」。<script setup lang="ts">
/** 场景:版本历史附件——超过 3 项折叠,展开 / 收起切换 */
import { ref } from 'vue'
import { BizAttachmentList } from 'vue3-ep-biz-lib'
import type { BizAttachmentItem } from 'vue3-ep-biz-lib'
const items = ref<BizAttachmentItem[]>(
Array.from({ length: 7 }, (_, i) => ({
id: String(i + 1),
name: `设计稿-v0.${i + 1}.zip`,
url: '#',
size: 12_582_912 + i * 1024,
uploader: i % 2 === 0 ? '设计部' : '前端组',
uploadedAt: `2026-09-${String(10 + i).padStart(2, '0')}`,
}))
)
</script>
<template>
<BizAttachmentList :items="items" :collapse-after="3" />
</template>
显示代码
加载与空态
加载中
<script setup lang="ts">
/** 场景:加载与空态——loading 骨架屏 / 空附件引导 */
import { ref } from 'vue'
import { ElButton, ElSwitch } from 'element-plus'
import { BizAttachmentList } from 'vue3-ep-biz-lib'
import type { BizAttachmentItem } from 'vue3-ep-biz-lib'
const loading = ref(true)
const items = ref<BizAttachmentItem[]>([
{ id: '1', name: '巡检记录.pdf', url: '#', size: 812_544 },
])
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 14px">
<div style="display: flex; align-items: center; gap: 12px">
<ElSwitch v-model="loading" active-text="加载中" />
<ElButton size="small" @click="items = []">清空附件</ElButton>
</div>
<BizAttachmentList :items="items" :loading="loading" :skeleton-rows="3" empty-text="暂无附件,可从工单详情上传" />
</div>
</template>
显示代码
自定义大小格式
PDF
验收报告.pdf
2.37 MB
视频
现场视频.mp4
149.00 MB
size-formatter 接管大小文案(默认 KB / MB 自适应;示例统一 MB 两位小数)。<script setup lang="ts">
/** 场景:自定义大小格式——sizeFormatter 接管(如统一显示 MB 两位小数) */
import { ref } from 'vue'
import { BizAttachmentList } from 'vue3-ep-biz-lib'
import type { BizAttachmentItem } from 'vue3-ep-biz-lib'
const items = ref<BizAttachmentItem[]>([
{ id: '1', name: '验收报告.pdf', url: '#', size: 2_483_712 },
{ id: '2', name: '现场视频.mp4', url: '#', size: 156_237_824 },
])
const format = (bytes: number): string => `${(bytes / 1024 / 1024).toFixed(2)} MB`
</script>
<template>
<BizAttachmentList :items="items" :size-formatter="format" />
</template>
显示代码
与 BizUploadFile 成对(录入 → 展示闭环)
支持任意类型,最多 6 份
PDF
初始附件.pdf
500.0 KB系统
BizUploadFile 上传成功即进附件组;附件组内删除与排序——完整附件管理闭环。
<script setup lang="ts">
/** 场景:录入 → 展示成对——BizUploadFile 上传成功即进附件组,可删除可排序(完整闭环) */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { BizAttachmentList, BizUploadFile } from 'vue3-ep-biz-lib'
import type { BizAttachmentItem } from 'vue3-ep-biz-lib'
const items = ref<BizAttachmentItem[]>([
{ id: 'a1', name: '初始附件.pdf', url: '#', size: 512_000, uploader: '系统' },
])
/* 模拟上传:1.5s 后返回地址(真实业务为后端返回) */
const request = (file: File): Promise<string> =>
new Promise((resolve) => {
setTimeout(() => {
items.value = [
...items.value,
{ id: `u-${Date.now()}`, name: file.name, url: `https://cdn.example.com/${encodeURIComponent(file.name)}`, size: file.size, uploader: '当前用户' },
]
resolve('ok')
}, 1200)
})
const onRemove = (item: BizAttachmentItem): void => {
items.value = items.value.filter((row) => row.id !== item.id)
ElMessage.success(`已移除:${item.name}`)
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 16px; max-width: 640px">
<BizUploadFile :request="request" :limit="6" tip="支持任意类型,最多 6 份" />
<BizAttachmentList :items="items" editable @remove="onRemove" @reorder="(next) => (items = next)" />
</div>
</template>
显示代码
属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| items | BizAttachmentItem[] | [] | 附件列表 |
| layout | 'list' | 'grid' | 'list' | 列表 / 卡片网格 |
| collapse-after | number | 0 | 超过 N 项折叠(0 不折叠) |
| editable | boolean | false | 编辑态:删除按钮 + 拖拽排序 |
| confirm-delete | boolean | true | 删除前二次确认 |
| grid-item-width | number | 200 | grid 形态单项宽(px) |
| size-formatter | (bytes: number) => string | KB/MB 自适应 | 大小格式化 |
| empty-text | string | '暂无附件' | 空态文案 |
| loading | boolean | false | 骨架屏 |
| skeleton-rows | number | 3 | 骨架行数 |
ts
interface BizAttachmentItem {
id: string // 唯一标识
name: string // 文件名(扩展名决定图标)
url?: string // 地址(预览 / 下载;敏感项可不给)
size?: number // 字节
uploader?: string // 上传人
uploadedAt?: string // 上传时间(任意文案)
sensitive?: boolean // 敏感:掩码 + 受限访问
color?: string // 自定义图标色
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
事件
| 事件名 | 参数 | 说明 |
|---|---|---|
| preview | ({ item, index }) | 点击预览(敏感项 / 无 url 不触发) |
| download | ({ item, index }) | 点击下载(下载实现由业务侧接管) |
| remove | (item, index) | 确认删除后触发(items 由业务侧移除) |
| reorder | (items: BizAttachmentItem[]) | 拖拽排序后的新顺序(业务侧持久化) |
插槽
| 插槽名 | 说明 |
|---|---|
| — | 无插槽(形态固定,个性化建议直接自绘) |
Expose
| 名称 | 类型 | 说明 |
|---|---|---|
| isExpanded | () => boolean | 当前是否展开 |
| toggle | () => void | 切换展开 / 收起 |