diff --git a/.cursor/cursorrules-frontend.md b/.cursor/cursorrules-frontend.md index 16f524be..ac63da55 100644 --- a/.cursor/cursorrules-frontend.md +++ b/.cursor/cursorrules-frontend.md @@ -809,3 +809,103 @@ export default defineConfig({ 1. **按钮规范**: 工具栏第一个新增按钮必须使用 `type="primary" plain`,其他按钮使用默认样式 2. **颜色系统**: 使用最新的 Art Design Pro 颜色变量 3. **文档同步**: 代码变更后必须同步更新相关文档 + +## 4. 附件管理统一规范(强制性) + +> 适用范围:所有使用 **Element Plus** + **Vue 3 + TS** 的前端页面(弹窗、新建、编辑、详情、预览等)涉及“附件/文件”功能的模块,必须遵循本规范,以保持 UI 及交互的一致性。 + +### 4.1 组件结构 + +| 组件 | 说明 | +|------|------| +| `` | 核心上传组件,拖拽 + 点击上传,**单文件最大 10 MB**,**最多 15 个文件** | +| 自定义 `#file` 模板 | 自绘「卡片样式」:缩略图 + 文件名 + 操作按钮组 | +| `` | 卡片底部操作按钮:下载(success)、删除(danger) | +| 自定义 CSS 类 | `.upload-file-card / thumb / name / actions` 等,详见样式规范 | + +### 4.2 功能实现 + +1. **上传 Upload** + - `auto-upload="true"` + 立即上传 + - `accept="image/*,video/*,.pdf,.doc,.docx,.txt"` + - 上传前 (`before-upload`) 校验大小 <10 MB + - 上传成功: + - 新建模式:将返回的 `id` 收集到 `tempAttachmentIds` + - 编辑模式:文件已自动关联到工单 + - 上传失败:Element Plus message 提示 + +2. **下载 Download (强制使用 fetch + blob)** + - 统一函数 `handleDownloadAttachment(file)` / `downloadAttachment(attachment)` + - 流程:`fetch(filePath) → blob → URL.createObjectURL → ` + - 使用 `ElLoading.service()` 显示 *正在下载文件…* + - 下载完成后 `revokeObjectURL` 释放内存 + - 解决浏览器对图片/PDF 默认预览导致无法下载的问题 + +3. **删除 Delete(延迟删除机制)** + - 点击删除 → `proxy.$modal.confirm()` 二次确认 + - 已上传文件:只把 `attachment.id` 放入 `pendingDeleteAttachmentIds`,**不立即调用后端** + - 表单保存时统一调用 `deleteAttachment` 批量删除 + - 新增未上传文件:直接从 `tempFileList` / `attachmentList` 移除 + +4. **预览 Preview** + - 判断 `fileType === 'image'` → 使用 `Element Plus ImageViewer` 预览 + - 其他类型文件 `window.open(filePath,'_blank')` + - 详情弹窗附件列表同样遵循该预览逻辑 + +### 4.3 样式规范(SCSS) + +```scss +/* 让附件卡片一行展示 4 个 */ +:deep(.el-upload-list--picture-card) { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 9px; + margin-top: 12px; + .el-upload-list__item { + width: 166px !important; + min-height: 180px !important; + border-radius: 6px; + overflow: hidden; + } +} + +/* 卡片整体布局 */ +.upload-file-card { + display: flex; + flex-direction: column; + min-height: 180px; +} +.upload-file-thumb { height: 120px; overflow: hidden; } +.upload-file-name { font-size: 12px; padding: 8px 4px 4px; text-align: center; overflow: hidden; } +.upload-file-card-actions { + padding: 6px 8px; + border-top: 1px solid #f0f0f0; + background: #fafafa; + display: flex; justify-content: center; +} +``` + +### 4.4 统一变量 & Hook + +```ts +const attachmentList = ref([]); // el-upload file-list +const tempFileList = ref([]); // 新建时未上传的本地文件 +const tempAttachmentIds = ref([]); // 新建时已上传待关联附件 id +const pendingDeleteAttachmentIds = ref([]); // 编辑时标记待删除附件 id +``` + +### 4.5 集成步骤(页面级) + +1. 在 `