feat(docs): 实现文档图标系统并优化首页展示
## 主要更新 ### 新增 - 创建文档图标工具函数 (src/utils/documentIcons.js) - 根据文件扩展名自动匹配对应图标 (PDF/Word/Excel/PPT/图片/视频等) - 提供 getDocumentIcon() 和 getDocumentLabel() 工具函数 - 支持判断文件类型 (isPDF/isImage/isVideo) - 添加文档图标资源 (src/assets/images/icon/doc/) - 10 个 SVG 图标文件,覆盖常见文档类型 - 新增文档图标更新说明文档 (docs/DOCUMENT_ICONS_UPDATE.md) - 移动计划书开发指南到组件目录 (src/components/PlanSchemes/) ### 优化 - 更新首页"本周热门资料"展示 (src/pages/index/index.vue) - 使用真实文档图标替换通用图标 - 添加文件类型标签,位于标题下方 - Mock 不同类型文件数据 (PDF/Word/Excel) - 更新资料列表页 (src/pages/material-list/index.vue) - 集成文档图标系统 - 更新产品详情页 (src/pages/product-detail/index.vue) - 集成文档图标系统 ### 技术细节 - 使用 ES6 import 正确导入 SVG 资源 - 解决 Taro 小程序静态资源加载问题 - 统一文档类型识别逻辑 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Showing
17 changed files
with
523 additions
and
16 deletions
| 1 | +## [2026-01-31] - 优化首页热门资料展示 | ||
| 2 | + | ||
| 3 | +### 优化 | ||
| 4 | +- 优化首页"本周热门资料"栏目 (`src/pages/index/index.vue`) | ||
| 5 | + - 使用真实的文档图标系统,根据文件后缀自动显示对应图标 | ||
| 6 | + - 添加文件类型标签,显示在标题下方(蓝色背景突出显示) | ||
| 7 | + - 更新 Mock 数据,包含不同类型文件(PDF、Word、Excel) | ||
| 8 | + - 集成 `getDocumentIcon` 和 `getDocumentLabel` 工具函数 | ||
| 9 | + | ||
| 10 | +--- | ||
| 11 | + | ||
| 12 | +**详细信息**: | ||
| 13 | +- **影响文件**: src/pages/index/index.vue | ||
| 14 | +- **技术栈**: Vue 3, Taro, TailwindCSS | ||
| 15 | +- **测试状态**: 已通过 | ||
| 16 | +- **备注**: | ||
| 17 | + - 将 IconFont 图标替换为 image 标签,使用真实文档图标 | ||
| 18 | + - 文件类型标签更明显,提升用户体验 | ||
| 19 | + - 支持多种文件类型:PDF、Word、Excel、PPT、图片、视频等 | ||
| 20 | + | ||
| 21 | +--- | ||
| 22 | + | ||
| 23 | +## [2026-01-31] - 修复文档图标加载问题 | ||
| 24 | + | ||
| 25 | +### 修复 | ||
| 26 | +- 修复文档图标加载失败(500 错误)的问题 | ||
| 27 | + - 原因:使用字符串路径引用静态资源,Taro 构建工具无法正确处理 | ||
| 28 | + - 解决:使用 ES6 `import` 导入所有 SVG 图标资源 | ||
| 29 | + - 影响:`src/utils/documentIcons.js` 工具函数 | ||
| 30 | + | ||
| 31 | +--- | ||
| 32 | + | ||
| 33 | +**详细信息**: | ||
| 34 | +- **影响文件**: src/utils/documentIcons.js | ||
| 35 | +- **技术栈**: Vue 3, Taro, ES6 Modules | ||
| 36 | +- **测试状态**: 已通过 | ||
| 37 | +- **备注**: | ||
| 38 | + - 将字符串路径(如 `/assets/images/icon/doc/doc.svg`)改为导入变量(如 `docIcon`) | ||
| 39 | + - 确保所有 10 个 SVG 图标都正确导入和映射 | ||
| 40 | + - 在资料列表页和产品详情页中正确显示文件类型图标 | ||
| 41 | + | ||
| 42 | +--- | ||
| 43 | + | ||
| 1 | ## [2026-01-31] - 统一方案A样式实现模式 | 44 | ## [2026-01-31] - 统一方案A样式实现模式 |
| 2 | 45 | ||
| 3 | ### 优化 | 46 | ### 优化 | ... | ... |
docs/DOCUMENT_ICONS_UPDATE.md
0 → 100644
| 1 | +# 资料项图标更新总结 | ||
| 2 | + | ||
| 3 | +> **更新日期**: 2026-01-31 | ||
| 4 | +> **更新内容**: 根据文件后缀使用真实的文档图标 SVG | ||
| 5 | + | ||
| 6 | +## 更新内容 | ||
| 7 | + | ||
| 8 | +### 1. 创建文档图标工具函数 | ||
| 9 | + | ||
| 10 | +**文件**: `src/utils/documentIcons.js` | ||
| 11 | + | ||
| 12 | +提供了以下函数: | ||
| 13 | + | ||
| 14 | +#### `getDocumentIcon(fileName)` | ||
| 15 | +根据文件名返回对应的文档图标路径 | ||
| 16 | + | ||
| 17 | +```javascript | ||
| 18 | +import { getDocumentIcon } from '@/utils/documentIcons' | ||
| 19 | + | ||
| 20 | +getDocumentIcon('报告.pdf') // '/assets/images/icon/doc/doc.svg' | ||
| 21 | +getDocumentIcon('数据.xlsx') // '/assets/images/icon/doc/xls.svg' | ||
| 22 | +getDocumentIcon('图片.png') // '/assets/images/icon/doc/png.svg' | ||
| 23 | +getDocumentIcon('视频.mp4') // '/assets/images/icon/doc/mp4.svg' | ||
| 24 | +``` | ||
| 25 | + | ||
| 26 | +#### `getDocumentLabel(fileName)` | ||
| 27 | +根据文件名返回文件类型标签 | ||
| 28 | + | ||
| 29 | +```javascript | ||
| 30 | +import { getDocumentLabel } from '@/utils/documentIcons' | ||
| 31 | + | ||
| 32 | +getDocumentLabel('报告.pdf') // 'PDF' | ||
| 33 | +getDocumentLabel('数据.xlsx') // 'Excel' | ||
| 34 | +getDocumentLabel('图片.png') // 'PNG' | ||
| 35 | +``` | ||
| 36 | + | ||
| 37 | +#### 其他辅助函数 | ||
| 38 | +- `isPDF(fileName)` - 判断是否为 PDF 文件 | ||
| 39 | +- `isImage(fileName)` - 判断是否为图片文件 | ||
| 40 | +- `isVideo(fileName)` - 判断是否为视频文件 | ||
| 41 | + | ||
| 42 | +### 2. 支持的文件类型 | ||
| 43 | + | ||
| 44 | +| 文件类型 | 扩展名 | 图标文件 | 标签 | | ||
| 45 | +|---------|--------|---------|------| | ||
| 46 | +| **通用文档** | .pdf | doc.svg | PDF | | ||
| 47 | +| **Word** | .doc, .docx | word.svg | Word | | ||
| 48 | +| **Excel** | .xls, .xlsx | xls.svg | Excel | | ||
| 49 | +| **PPT** | .ppt, .pptx | ppt.svg | PPT | | ||
| 50 | +| **图片** | .jpg, .jpeg, .png, .gif, .webp | jpeg.svg, png.svg | JPG, PNG, GIF, WebP | | ||
| 51 | +| **视频** | .mp4, .mov, .avi, .mkv | mp4.svg | MP4, MOV, AVI, MKV | | ||
| 52 | +| **矢量图** | .svg | svg.svg | SVG | | ||
| 53 | +| **文本** | .txt, .md | txt.svg | TXT, MD | | ||
| 54 | +| **压缩包** | .zip, .rar, .7z | 其他文件.svg | ZIP, RAR, 7Z | | ||
| 55 | +| **其他** | - | 其他文件.svg | DOC | | ||
| 56 | + | ||
| 57 | +### 3. 更新的页面 | ||
| 58 | + | ||
| 59 | +#### 资料列表页 (`src/pages/material-list/index.vue`) | ||
| 60 | + | ||
| 61 | +**改动**: | ||
| 62 | +- ✅ 导入 `getDocumentIcon` 和 `getDocumentLabel` | ||
| 63 | +- ✅ 将 `IconFont` 图标改为 `image` 标签 | ||
| 64 | +- ✅ 动态显示文档图标(根据 `item.fileName`) | ||
| 65 | +- ✅ 动态显示文件类型标签(根据 `item.fileName`) | ||
| 66 | + | ||
| 67 | +**示例**: | ||
| 68 | +```vue | ||
| 69 | +<!-- 之前 --> | ||
| 70 | +<IconFont :name="item.iconName || 'order'" size="32" :color="item.iconColor || '#2563EB'" /> | ||
| 71 | + | ||
| 72 | +<!-- 现在 --> | ||
| 73 | +<image | ||
| 74 | + :src="getDocumentIcon(item.fileName)" | ||
| 75 | + class="w-[48rpx] h-[48rpx]" | ||
| 76 | + mode="aspectFit" | ||
| 77 | +/> | ||
| 78 | +``` | ||
| 79 | + | ||
| 80 | +#### 产品详情页 (`src/pages/product-detail/index.vue`) | ||
| 81 | + | ||
| 82 | +**改动**: | ||
| 83 | +- ✅ 导入 `getDocumentIcon` | ||
| 84 | +- ✅ 将 `IconFont` 图标改为 `image` 标签 | ||
| 85 | +- ✅ 动态显示文档图标(根据 `file.fileName`) | ||
| 86 | + | ||
| 87 | +**示例**: | ||
| 88 | +```vue | ||
| 89 | +<!-- 之前 --> | ||
| 90 | +<IconFont :name="file.iconName" size="24" :color="file.iconColor" /> | ||
| 91 | + | ||
| 92 | +<!-- 现在 --> | ||
| 93 | +<image | ||
| 94 | + :src="getDocumentIcon(file.fileName)" | ||
| 95 | + class="w-[48rpx] h-[48rpx]" | ||
| 96 | + mode="aspectFit" | ||
| 97 | +/> | ||
| 98 | +``` | ||
| 99 | + | ||
| 100 | +### 4. 图标展示规范 | ||
| 101 | + | ||
| 102 | +#### 尺寸规范 | ||
| 103 | +- **列表图标**: `w-[48rpx] h-[48rpx]` (24px × 24px) | ||
| 104 | +- **容器背景**: `w-[88rpx] h-[88rpx]`` (44px × 44px) | ||
| 105 | +- **背景样式**: 渐变背景 `bg-gradient-to-br from-blue-50 to-blue-100` | ||
| 106 | + | ||
| 107 | +#### 显示逻辑 | ||
| 108 | +```javascript | ||
| 109 | +// 自动根据文件扩展名匹配图标 | ||
| 110 | +// 找不到扩展名 → 使用 "其他文件.svg" | ||
| 111 | +// 特殊扩展名优先匹配(如 .docx → word.svg) | ||
| 112 | +``` | ||
| 113 | + | ||
| 114 | +## 图标文件位置 | ||
| 115 | + | ||
| 116 | +``` | ||
| 117 | +src/assets/images/icon/doc/ | ||
| 118 | +├── doc.svg # PDF 通用文档 | ||
| 119 | +├── jpeg.svg # JPG/JPEG 图片 | ||
| 120 | +├── mp4.svg # MP4 视频 | ||
| 121 | +├── png.svg # PNG 图片 | ||
| 122 | +├── ppt.svg # PPT 演示文稿 | ||
| 123 | +├── svg.svg # SVG 矢量图 | ||
| 124 | +├── txt.svg # TXT 文本 | ||
| 125 | +├── word.svg # Word 文档 | ||
| 126 | +├── xls.svg # Excel 表格 | ||
| 127 | +└── 其他文件.svg # 其他文件 | ||
| 128 | +``` | ||
| 129 | + | ||
| 130 | +## 使用示例 | ||
| 131 | + | ||
| 132 | +### 在新页面中使用 | ||
| 133 | + | ||
| 134 | +```vue | ||
| 135 | +<template> | ||
| 136 | + <view v-for="file in fileList" :key="file.id"> | ||
| 137 | + <image :src="getDocumentIcon(file.fileName)" class="doc-icon" /> | ||
| 138 | + <text>{{ getDocumentLabel(file.fileName) }}</text> | ||
| 139 | + </view> | ||
| 140 | +</template> | ||
| 141 | + | ||
| 142 | +<script setup> | ||
| 143 | +import { getDocumentIcon, getDocumentLabel } from '@/utils/documentIcons' | ||
| 144 | +</script> | ||
| 145 | +``` | ||
| 146 | + | ||
| 147 | +### 扩展新的文件类型 | ||
| 148 | + | ||
| 149 | +如果需要支持新的文件类型,在 `src/utils/documentIcons.js` 中添加: | ||
| 150 | + | ||
| 151 | +```javascript | ||
| 152 | +const EXTENSION_ICON_MAP = { | ||
| 153 | + 'newtype': '/assets/images/icon/doc/newtype.svg', | ||
| 154 | + // ... | ||
| 155 | +}; | ||
| 156 | +``` | ||
| 157 | + | ||
| 158 | +## 优势 | ||
| 159 | + | ||
| 160 | +### 之前的问题 | ||
| 161 | +- ❌ 使用通用图标,无法区分文件类型 | ||
| 162 | +- ❌ 硬编码 `iconName` 和 `iconColor`,维护困难 | ||
| 163 | +- ❌ 所有文档显示相同图标 | ||
| 164 | + | ||
| 165 | +### 现在的优势 | ||
| 166 | +- ✅ 根据文件后缀自动匹配对应图标 | ||
| 167 | +- ✅ 直观展示文件类型 | ||
| 168 | +- ✅ 无需手动维护图标信息 | ||
| 169 | +- ✅ 统一的图标管理 | ||
| 170 | +- ✅ 易于扩展新文件类型 | ||
| 171 | + | ||
| 172 | +## 待优化项 | ||
| 173 | + | ||
| 174 | +### 可选优化(未实施) | ||
| 175 | +- [ ] 收藏页面 (`src/pages/favorites/index.vue`) - 数据结构不包含 `fileName`,需要添加 | ||
| 176 | +- [ ] 首页资料展示 - 如有需要 | ||
| 177 | +- [ ] 图标懒加载优化 | ||
| 178 | +- [ ] 图标缓存机制 | ||
| 179 | + | ||
| 180 | +## 测试建议 | ||
| 181 | + | ||
| 182 | +### 测试文件类型 | ||
| 183 | +确保以下文件类型图标正确显示: | ||
| 184 | + | ||
| 185 | +**文档类**: | ||
| 186 | +- [ ] PDF 文件 | ||
| 187 | +- [ ] Word 文档 (.doc, .docx) | ||
| 188 | +- [ ] Excel 表格 (.xls, .xlsx) | ||
| 189 | +- [ ] PPT 演示文稿 (.ppt, .pptx) | ||
| 190 | + | ||
| 191 | +**图片类**: | ||
| 192 | +- [ ] JPG/JPEG | ||
| 193 | +- [ ] PNG | ||
| 194 | +- [ ] GIF | ||
| 195 | +- [ ] WebP | ||
| 196 | + | ||
| 197 | +**其他**: | ||
| 198 | +- [ ] TXT 文本 | ||
| 199 | +- [ ] MP4 视频 | ||
| 200 | +- [ ] SVG 矢量图 | ||
| 201 | +- [ ] 压缩包 | ||
| 202 | + | ||
| 203 | +### 测试方法 | ||
| 204 | +1. 在资料列表页查看不同文件的图标 | ||
| 205 | +2. 在产品详情页查看附件的图标 | ||
| 206 | +3. 确认图标与文件类型匹配 | ||
| 207 | +4. 确认图标显示清晰、大小合适 | ||
| 208 | + | ||
| 209 | +## 相关文件 | ||
| 210 | + | ||
| 211 | +- [文档图标工具函数](../src/utils/documentIcons.js) | ||
| 212 | +- [资料列表页](../src/pages/material-list/index.vue) | ||
| 213 | +- [产品详情页](../src/pages/product-detail/index.vue) | ||
| 214 | +- [图标目录](../src/assets/images/icon/doc/) |
src/assets/images/icon/doc/doc.svg
0 → 100644
| 1 | +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769839712653" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1430" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><path d="M219.424 18.304h530.272l201.152 219.424v768H219.424V18.304z" fill="#FFFFFF" p-id="1431"></path><path d="M733.696 253.728V50.304H251.424v923.424h667.424v-720h-185.152z m217.152-16v768H219.424V18.304h530.272l201.152 219.424z m-58.08-16l-127.04-138.624v138.624h127.04z" fill="#465F78" p-id="1432"></path><path d="M73.152 288a32 32 0 0 1 32-32h448a32 32 0 0 1 32 32v448a32 32 0 0 1-32 32h-448a32 32 0 0 1-32-32V288zM640 416h224v37.344h-224V416zM640 509.344h224v37.312h-224v-37.312zM640 602.656h224V640h-224v-37.344z" fill="#056EC4" p-id="1433"></path><path d="M224 384h101.44c22.88 0 40.32 1.76 52.32 5.248 16.128 4.768 29.92 13.184 41.44 25.312 11.488 12.128 20.224 27.008 26.24 44.64 5.984 17.472 8.992 39.104 8.992 64.864 0 22.624-2.816 42.112-8.448 58.496-6.848 20-16.672 36.16-29.44 48.576-9.6 9.376-22.624 16.672-38.976 21.92-12.256 3.872-28.64 5.824-49.12 5.824H224V384z m55.488 46.496v182.08h41.44c15.52 0 26.688-0.896 33.6-2.624 8.96-2.24 16.416-6.08 22.272-11.456 6.016-5.376 10.88-14.176 14.624-26.432 3.776-12.384 5.632-29.184 5.632-50.432s-1.856-37.568-5.632-48.96c-3.744-11.36-8.96-20.224-15.744-26.624a52.8 52.8 0 0 0-25.696-12.928c-7.744-1.76-22.912-2.624-45.536-2.624h-24.96z" fill="#FFFFFF" p-id="1434"></path></svg> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
src/assets/images/icon/doc/jpeg.svg
0 → 100644
| 1 | +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769839839712" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1602" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><path d="M219.424 18.304h530.272l201.152 219.424v768H219.424V18.304z" fill="#FFFFFF" p-id="1603"></path><path d="M733.696 253.728V50.304H251.424v923.424h667.424v-720h-185.152z m217.152-16v768H219.424V18.304h530.272l201.152 219.424z m-58.08-16l-127.04-138.624v138.624h127.04z" fill="#465F78" p-id="1604"></path><path d="M73.152 288a32 32 0 0 1 32-32h448a32 32 0 0 1 32 32v448a32 32 0 0 1-32 32h-448a32 32 0 0 1-32-32V288zM640 416h224v37.344h-224V416zM640 509.344h224v37.312h-224v-37.312zM640 602.656h224V640h-224v-37.344z" fill="#26B99A" p-id="1605"></path><path d="M344.576 384h55.296v174.016c0 22.72-1.984 40.224-5.984 52.48-5.376 16-15.136 28.864-29.248 38.624-14.144 9.6-32.768 14.432-55.904 14.432-27.104 0-48-7.552-62.624-22.688-14.624-15.232-21.984-37.568-22.112-66.912l52.32-6.016c0.64 15.744 2.944 26.88 6.944 33.376 5.984 9.888 15.104 14.816 27.36 14.816 12.384 0 21.12-3.52 26.24-10.496 5.12-7.136 7.68-21.824 7.68-44.064V384z" fill="#FFFFFF" p-id="1606"></path></svg> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
src/assets/images/icon/doc/mp4.svg
0 → 100644
| 1 | +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769839848193" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1776" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><path d="M219.424 18.304h530.272l201.152 219.424v768H219.424V18.304z" fill="#FFFFFF" p-id="1777"></path><path d="M733.696 253.728V50.304H251.424v923.424h667.424v-720h-185.152z m217.152-16v768H219.424V18.304h530.272l201.152 219.424z m-58.08-16l-127.04-138.624v138.624h127.04z" fill="#465F78" p-id="1778"></path><path d="M64 256m32 0l448 0q32 0 32 32l0 448q0 32-32 32l-448 0q-32 0-32-32l0-448q0-32 32-32Z" fill="#0092D3" p-id="1779"></path><path d="M640 416h224v37.344h-224V416zM640 509.344h224v37.312h-224v-37.312zM640 602.656h224V640h-224v-37.344z" fill="#0092D3" p-id="1780"></path><path d="M192 658.88V384h83.072l49.856 187.52L374.24 384h83.264v274.88h-51.584v-216.384L351.36 658.88H297.92l-54.368-216.384v216.384H192z" fill="#FFFFFF" p-id="1781"></path></svg> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
src/assets/images/icon/doc/png.svg
0 → 100644
| 1 | +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769839855719" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1947" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><path d="M219.424 18.304h530.272l201.152 219.424v768H219.424V18.304z" fill="#FFFFFF" p-id="1948"></path><path d="M733.696 253.728V50.304H251.424v923.424h667.424v-720h-185.152z m217.152-16v768H219.424V18.304h530.272l201.152 219.424z m-58.08-16l-127.04-138.624v138.624h127.04z" fill="#465F78" p-id="1949"></path><path d="M64 288a32 32 0 0 1 32-32h448a32 32 0 0 1 32 32v448a32 32 0 0 1-32 32H96a32 32 0 0 1-32-32V288zM640 416h224v37.344h-224V416zM640 509.344h224v37.312h-224v-37.312zM640 602.656h224V640h-224v-37.344z" fill="#88C057" p-id="1950"></path><path d="M224 384v279.264h59.04v-90.56h49.632c21.44 0 39.744-3.936 54.816-11.84a82.752 82.752 0 0 0 34.784-33.152c8-14.176 12-30.528 12-49.088 0-18.56-3.968-34.88-11.84-49.088a82.176 82.176 0 0 0-34.112-33.408c-14.912-8.096-32.96-12.128-54.144-12.128H224z m99.136 141.408H283.04v-93.12h39.808c11.456 0 20.928 1.92 28.384 5.856 7.456 3.84 12.992 9.216 16.64 16.224 3.712 6.912 5.6 15.008 5.6 24.256 0 9.184-1.888 17.344-5.6 24.416-3.648 7.008-9.184 12.48-16.64 16.512-7.36 3.904-16.736 5.856-28.096 5.856z" fill="#FFFFFF" p-id="1951"></path></svg> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
src/assets/images/icon/doc/ppt.svg
0 → 100644
| 1 | +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769839879259" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2637" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><path d="M219.424 18.304h530.272l201.152 219.424v768H219.424V18.304z" fill="#FFFFFF" p-id="2638"></path><path d="M733.696 253.728V50.304H251.424v923.424h667.424v-720h-185.152z m217.152-16v768H219.424V18.304h530.272l201.152 219.424z m-58.08-16l-127.04-138.624v138.624h127.04z" fill="#465F78" p-id="2639"></path><path d="M64 256m32 0l448 0q32 0 32 32l0 448q0 32-32 32l-448 0q-32 0-32-32l0-448q0-32 32-32Z" fill="#FF501A" p-id="2640"></path><path d="M640 416h224v37.344h-224V416zM640 509.344h224v37.312h-224v-37.312zM640 602.656h224V640h-224v-37.344z" fill="#FF501A" p-id="2641"></path><path d="M224 658.88V384h89.056c33.76 0 55.744 1.376 66.016 4.128 15.744 4.128 28.928 13.12 39.552 27.008 10.624 13.76 15.936 31.552 15.936 53.44 0 16.864-3.072 31.04-9.184 42.56-6.112 11.488-13.952 20.544-23.424 27.2a80.352 80.352 0 0 1-28.704 12.928c-13.248 2.624-32.448 3.936-57.568 3.936h-36.16v103.68H224z m55.488-228.384v78.016h30.4c21.856 0 36.48-1.44 43.84-4.32a36.576 36.576 0 0 0 23.616-34.88c0.032-10.016-2.88-18.24-8.768-24.736a38.4 38.4 0 0 0-22.336-12.192c-6.624-1.28-19.936-1.888-39.936-1.888h-26.816z" fill="#FFFFFF" p-id="2642"></path></svg> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
src/assets/images/icon/doc/svg.svg
0 → 100644
| 1 | +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769839895548" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3152" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><path d="M219.424 18.304h530.272l201.152 219.424v768H219.424V18.304z" fill="#FFFFFF" p-id="3153"></path><path d="M733.696 253.728V50.304H251.424v923.424h667.424v-720h-185.152z m217.152-16v768H219.424V18.304h530.272l201.152 219.424z m-58.08-16l-127.04-138.624v138.624h127.04z" fill="#465F78" p-id="3154"></path><path d="M73.152 288a32 32 0 0 1 32-32h448a32 32 0 0 1 32 32v448a32 32 0 0 1-32 32h-448a32 32 0 0 1-32-32V288zM640 416h224v37.344h-224V416zM640 509.344h224v37.312h-224v-37.312zM640 602.656h224V640h-224v-37.344z" fill="#FF527B" p-id="3155"></path><path d="M224 574.112l54.016-5.248c3.232 18.144 9.792 31.456 19.68 39.936 9.984 8.512 23.424 12.768 40.32 12.768 17.856 0 31.296-3.744 40.32-11.264 9.088-7.616 13.664-16.48 13.664-26.624a24.416 24.416 0 0 0-5.824-16.48c-3.744-4.64-10.368-8.64-19.84-12-6.528-2.24-21.344-6.272-44.48-12-29.76-7.36-50.592-16.448-62.592-27.2-16.896-15.136-25.312-33.568-25.312-55.328 0-13.984 3.936-27.04 11.808-39.168 8-12.256 19.424-21.568 34.304-27.936 15.008-6.4 33.056-9.568 54.176-9.568 34.496 0 60.448 7.552 77.824 22.688 17.504 15.136 26.688 35.328 27.552 60.576l-55.488 2.432c-2.368-14.144-7.488-24.256-15.36-30.4-7.776-6.24-19.456-9.376-35.072-9.376-16.128 0-28.768 3.328-37.888 9.952a20.032 20.032 0 0 0-8.8 17.056 21.12 21.12 0 0 0 8.256 16.704c6.976 5.856 24 12 50.976 18.368 27.008 6.4 46.944 12.992 59.84 19.872 12.992 6.752 23.104 16.064 30.368 27.936 7.36 11.744 11.04 26.304 11.04 43.68 0 15.776-4.352 30.496-13.12 44.256-8.736 13.76-21.12 24-37.12 30.752-16 6.624-35.936 9.92-59.84 9.92-34.72 0-61.408-8-80.032-24-18.624-16.096-29.76-39.552-33.376-70.304z" fill="#FFFFFF" p-id="3156"></path></svg> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
src/assets/images/icon/doc/txt.svg
0 → 100644
| 1 | +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769839860746" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2119" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><path d="M219.424 18.304h530.272l201.152 219.424v768H219.424V18.304z" fill="#FFFFFF" p-id="2120"></path><path d="M733.696 253.728V50.304H251.424v923.424h667.424v-720h-185.152z m217.152-16v768H219.424V18.304h530.272l201.152 219.424z m-58.08-16l-127.04-138.624v138.624h127.04z" fill="#465F78" p-id="2121"></path><path d="M64 256m32 0l448 0q32 0 32 32l0 448q0 32-32 32l-448 0q-32 0-32-32l0-448q0-32 32-32Z" fill="#A8A1A0" p-id="2122"></path><path d="M640 416h224v37.344h-224V416zM640 509.344h224v37.312h-224v-37.312zM640 602.656h224V640h-224v-37.344z" fill="#A8A1A0" p-id="2123"></path><path d="M291.648 672v-239.264H208V384h224v48.736h-83.456V672H291.648z" fill="#FFFFFF" p-id="2124"></path></svg> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
src/assets/images/icon/doc/word.svg
0 → 100644
| 1 | +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769839883657" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2810" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><path d="M219.424 18.304h530.272l201.152 219.424v768H219.424V18.304z" fill="#FFFFFF" p-id="2811"></path><path d="M733.696 253.728V50.304H251.424v923.424h667.424v-720h-185.152z m217.152-16v768H219.424V18.304h530.272l201.152 219.424z m-58.08-16l-127.04-138.624v138.624h127.04z" fill="#465F78" p-id="2812"></path><path d="M73.152 288a32 32 0 0 1 32-32h448a32 32 0 0 1 32 32v448a32 32 0 0 1-32 32h-448a32 32 0 0 1-32-32V288zM640 416h224v37.344h-224V416zM640 509.344h224v37.312h-224v-37.312zM640 602.656h224V640h-224v-37.344z" fill="#317BFF" p-id="2813"></path><path d="M221.952 640l-56.256-235.616H214.4l35.52 161.856 43.072-161.856h56.576l41.28 164.576 36.16-164.576h47.904L417.696 640h-50.464l-46.912-176.16L273.536 640H221.952z" fill="#FFFFFF" p-id="2814"></path></svg> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
src/assets/images/icon/doc/xls.svg
0 → 100644
| 1 | +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769839874756" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2465" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><path d="M219.424 18.304h530.272l201.152 219.424v768H219.424V18.304z" fill="#FFFFFF" p-id="2466"></path><path d="M733.696 253.728V50.304H251.424v923.424h667.424v-720h-185.152z m217.152-16v768H219.424V18.304h530.272l201.152 219.424z m-58.08-16l-127.04-138.624v138.624h127.04z" fill="#465F78" p-id="2467"></path><path d="M64 288a32 32 0 0 1 32-32h448a32 32 0 0 1 32 32v448a32 32 0 0 1-32 32H96a32 32 0 0 1-32-32V288zM640 416h224v37.344h-224V416zM640 509.344h224v37.312h-224v-37.312zM640 602.656h224V640h-224v-37.344z" fill="#47B347" p-id="2468"></path><path d="M192 658.88l93.952-143.456L200.832 384h64.864l55.104 88.32L374.816 384h64.32l-85.504 133.504 93.92 141.376h-66.912L319.68 563.84l-61.12 95.04H192z" fill="#FFFFFF" p-id="2469"></path></svg> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
src/assets/images/icon/doc/其他文件.svg
0 → 100644
| 1 | +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769839889608" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2980" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><path d="M219.424 18.304h530.272l201.152 219.424v768H219.424V18.304z" fill="#FFFFFF" p-id="2981"></path><path d="M733.696 253.728V50.304H251.424v923.424h667.424v-720h-185.152z m217.152-16v768H219.424V18.304h530.272l201.152 219.424z m-58.08-16l-127.04-138.624v138.624h127.04z" fill="#465F78" p-id="2982"></path><path d="M64 288a32 32 0 0 1 32-32h448a32 32 0 0 1 32 32v448a32 32 0 0 1-32 32H96a32 32 0 0 1-32-32V288zM640 416h224v37.344h-224V416zM640 509.344h224v37.312h-224v-37.312zM640 602.656h224V640h-224v-37.344z" fill="#B2B2B2" p-id="2983"></path><path d="M291.968 545.152c-8.064-60.288 73.728-73.728 73.728-110.976 0-23.424-18.432-36.48-48.768-36.48-23.424 0-42.624 10.752-61.44 30.336l-31.488-28.8C248.576 370.816 282.368 352 323.456 352c55.68 0 96.384 26.112 96.384 77.184 0 56.064-84.096 62.976-77.952 115.968h-49.92z m25.344 102.528c-19.968 0-34.176-14.208-34.176-34.176 0-19.968 14.592-33.792 34.176-33.792 19.2 0 33.792 13.824 33.792 33.792 0 19.968-14.592 34.176-33.792 34.176z" fill="#FFFFFF" p-id="2984"></path></svg> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| ... | @@ -130,10 +130,15 @@ | ... | @@ -130,10 +130,15 @@ |
| 130 | <!-- Item 1 --> | 130 | <!-- Item 1 --> |
| 131 | <view class="flex gap-[24rpx]" @tap="handleMaterialClick(hotMaterials[0])"> | 131 | <view class="flex gap-[24rpx]" @tap="handleMaterialClick(hotMaterials[0])"> |
| 132 | <view class="w-[80rpx] h-[88rpx] flex-shrink-0 flex items-center justify-center bg-blue-50 rounded-[12rpx]"> | 132 | <view class="w-[80rpx] h-[88rpx] flex-shrink-0 flex items-center justify-center bg-blue-50 rounded-[12rpx]"> |
| 133 | - <IconFont name="order" size="32" color="#EF4444" /> | 133 | + <image :src="getDocumentIcon(hotMaterials[0].fileName)" class="w-[48rpx] h-[48rpx]" mode="aspectFit" /> |
| 134 | </view> | 134 | </view> |
| 135 | <view class="flex-1 flex flex-col justify-between py-[4rpx]"> | 135 | <view class="flex-1 flex flex-col justify-between py-[4rpx]"> |
| 136 | - <text class="text-gray-800 text-[28rpx] leading-[40rpx] line-clamp-2">{{ hotMaterials[0].title }}</text> | 136 | + <text class="text-gray-800 text-[28rpx] leading-[40rpx] line-clamp-2 mb-1">{{ hotMaterials[0].title }}</text> |
| 137 | + <view class="flex items-center gap-2 mb-1"> | ||
| 138 | + <view class="bg-blue-50 rounded px-2 py-0.5"> | ||
| 139 | + <text class="text-blue-600 text-[22rpx]">{{ getDocumentLabel(hotMaterials[0].fileName) }}</text> | ||
| 140 | + </view> | ||
| 141 | + </view> | ||
| 137 | <view class="flex justify-between items-end"> | 142 | <view class="flex justify-between items-end"> |
| 138 | <text class="text-gray-400 text-[24rpx]">{{ hotMaterials[0].learners }}</text> | 143 | <text class="text-gray-400 text-[24rpx]">{{ hotMaterials[0].learners }}</text> |
| 139 | <text class="text-blue-600 text-[26rpx]">{{ hotMaterials[0].progress }}</text> | 144 | <text class="text-blue-600 text-[26rpx]">{{ hotMaterials[0].progress }}</text> |
| ... | @@ -144,10 +149,15 @@ | ... | @@ -144,10 +149,15 @@ |
| 144 | <!-- Item 2 --> | 149 | <!-- Item 2 --> |
| 145 | <view class="flex gap-[24rpx]" @tap="handleMaterialClick(hotMaterials[1])"> | 150 | <view class="flex gap-[24rpx]" @tap="handleMaterialClick(hotMaterials[1])"> |
| 146 | <view class="w-[80rpx] h-[88rpx] flex-shrink-0 flex items-center justify-center bg-blue-50 rounded-[12rpx]"> | 151 | <view class="w-[80rpx] h-[88rpx] flex-shrink-0 flex items-center justify-center bg-blue-50 rounded-[12rpx]"> |
| 147 | - <IconFont name="order" size="32" color="#3B82F6" /> | 152 | + <image :src="getDocumentIcon(hotMaterials[1].fileName)" class="w-[48rpx] h-[48rpx]" mode="aspectFit" /> |
| 148 | </view> | 153 | </view> |
| 149 | <view class="flex-1 flex flex-col justify-between py-[4rpx]"> | 154 | <view class="flex-1 flex flex-col justify-between py-[4rpx]"> |
| 150 | - <text class="text-gray-800 text-[28rpx] leading-[40rpx] line-clamp-2">{{ hotMaterials[1].title }}</text> | 155 | + <text class="text-gray-800 text-[28rpx] leading-[40rpx] line-clamp-2 mb-1">{{ hotMaterials[1].title }}</text> |
| 156 | + <view class="flex items-center gap-2 mb-1"> | ||
| 157 | + <view class="bg-blue-50 rounded px-2 py-0.5"> | ||
| 158 | + <text class="text-blue-600 text-[22rpx]">{{ getDocumentLabel(hotMaterials[1].fileName) }}</text> | ||
| 159 | + </view> | ||
| 160 | + </view> | ||
| 151 | <view class="flex justify-between items-end"> | 161 | <view class="flex justify-between items-end"> |
| 152 | <text class="text-gray-400 text-[24rpx]">{{ hotMaterials[1].learners }}</text> | 162 | <text class="text-gray-400 text-[24rpx]">{{ hotMaterials[1].learners }}</text> |
| 153 | <text class="text-blue-600 text-[26rpx]">{{ hotMaterials[1].progress }}</text> | 163 | <text class="text-blue-600 text-[26rpx]">{{ hotMaterials[1].progress }}</text> |
| ... | @@ -158,10 +168,15 @@ | ... | @@ -158,10 +168,15 @@ |
| 158 | <!-- Item 3 --> | 168 | <!-- Item 3 --> |
| 159 | <view class="flex gap-[24rpx]" @tap="handleMaterialClick(hotMaterials[2])"> | 169 | <view class="flex gap-[24rpx]" @tap="handleMaterialClick(hotMaterials[2])"> |
| 160 | <view class="w-[80rpx] h-[88rpx] flex-shrink-0 flex items-center justify-center bg-blue-50 rounded-[12rpx]"> | 170 | <view class="w-[80rpx] h-[88rpx] flex-shrink-0 flex items-center justify-center bg-blue-50 rounded-[12rpx]"> |
| 161 | - <IconFont name="order" size="32" color="#10B981" /> | 171 | + <image :src="getDocumentIcon(hotMaterials[2].fileName)" class="w-[48rpx] h-[48rpx]" mode="aspectFit" /> |
| 162 | </view> | 172 | </view> |
| 163 | <view class="flex-1 flex flex-col justify-between py-[4rpx]"> | 173 | <view class="flex-1 flex flex-col justify-between py-[4rpx]"> |
| 164 | - <text class="text-gray-800 text-[28rpx] leading-[40rpx] line-clamp-2">{{ hotMaterials[2].title }}</text> | 174 | + <text class="text-gray-800 text-[28rpx] leading-[40rpx] line-clamp-2 mb-1">{{ hotMaterials[2].title }}</text> |
| 175 | + <view class="flex items-center gap-2 mb-1"> | ||
| 176 | + <view class="bg-blue-50 rounded px-2 py-0.5"> | ||
| 177 | + <text class="text-blue-600 text-[22rpx]">{{ getDocumentLabel(hotMaterials[2].fileName) }}</text> | ||
| 178 | + </view> | ||
| 179 | + </view> | ||
| 165 | <view class="flex justify-between items-end"> | 180 | <view class="flex justify-between items-end"> |
| 166 | <text class="text-gray-400 text-[24rpx]">{{ hotMaterials[2].learners }}</text> | 181 | <text class="text-gray-400 text-[24rpx]">{{ hotMaterials[2].learners }}</text> |
| 167 | <text class="text-blue-600 text-[26rpx]">{{ hotMaterials[2].progress }}</text> | 182 | <text class="text-blue-600 text-[26rpx]">{{ hotMaterials[2].progress }}</text> |
| ... | @@ -196,6 +211,7 @@ import { ref, shallowRef } from 'vue'; | ... | @@ -196,6 +211,7 @@ import { ref, shallowRef } from 'vue'; |
| 196 | import Taro, { useShareAppMessage } from '@tarojs/taro'; | 211 | import Taro, { useShareAppMessage } from '@tarojs/taro'; |
| 197 | import { useGo } from '@/hooks/useGo'; | 212 | import { useGo } from '@/hooks/useGo'; |
| 198 | import { useListItemClick, ListType } from '@/composables/useListItemClick'; | 213 | import { useListItemClick, ListType } from '@/composables/useListItemClick'; |
| 214 | +import { getDocumentIcon, getDocumentLabel } from '@/utils/documentIcons'; | ||
| 199 | import TabBar from '@/components/TabBar.vue'; | 215 | import TabBar from '@/components/TabBar.vue'; |
| 200 | import IconFont from '@/components/IconFont.vue'; | 216 | import IconFont from '@/components/IconFont.vue'; |
| 201 | import PlanPopup from '@/components/PlanPopup/index.vue'; | 217 | import PlanPopup from '@/components/PlanPopup/index.vue'; |
| ... | @@ -233,29 +249,31 @@ const loopData0 = shallowRef([ | ... | @@ -233,29 +249,31 @@ const loopData0 = shallowRef([ |
| 233 | /** | 249 | /** |
| 234 | * 热门资料数据 | 250 | * 热门资料数据 |
| 235 | * | 251 | * |
| 236 | - * @description 本周热门资料列表数据,包含文件信息和下载地址 | 252 | + * @description 本周热门资料列表数据,包含不同类型的文件 |
| 237 | */ | 253 | */ |
| 238 | const hotMaterials = ref([ | 254 | const hotMaterials = ref([ |
| 239 | { | 255 | { |
| 240 | title: '2024年保险市场趋势分析报告', | 256 | title: '2024年保险市场趋势分析报告', |
| 241 | learners: '256人学习', | 257 | learners: '256人学习', |
| 242 | progress: '78%', | 258 | progress: '78%', |
| 243 | - // 文件信息(用于点击打开预览) | 259 | + // PDF 文件 |
| 244 | fileName: '2024年保险市场趋势分析报告.pdf', | 260 | fileName: '2024年保险市场趋势分析报告.pdf', |
| 245 | downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/1_%E7%BE%8E%E4%B9%90%E7%88%B1%E8%A7%89%E6%95%99%E8%82%B22024%E9%A1%B9%E7%9B%AE%E5%9B%BE%E5%BD%B1%E4%BB%8B%E7%BB%8D_.pdf' | 261 | downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/1_%E7%BE%8E%E4%B9%90%E7%88%B1%E8%A7%89%E6%95%99%E8%82%B22024%E9%A1%B9%E7%9B%AE%E5%9B%BE%E5%BD%B1%E4%BB%8B%E7%BB%8D_.pdf' |
| 246 | }, | 262 | }, |
| 247 | { | 263 | { |
| 248 | - title: '高净值客户需求分析与产品匹配', | 264 | + title: '高净值客户产品配置方案模板', |
| 249 | learners: '189人学习', | 265 | learners: '189人学习', |
| 250 | progress: '65%', | 266 | progress: '65%', |
| 251 | - fileName: '高净值客户需求分析与产品匹配.pdf', | 267 | + // Word 文件 |
| 268 | + fileName: '高净值客户产品配置方案模板.docx', | ||
| 252 | downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/1_%E7%BE%8E%E4%B9%90%E7%88%B1%E8%A7%89%E6%95%99%E8%82%B22024%E9%A1%B9%E7%9B%AE%E5%9B%BE%E5%BD%B1%E4%BB%8B%E7%BB%8D_.pdf' | 269 | downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/1_%E7%BE%8E%E4%B9%90%E7%88%B1%E8%A7%89%E6%95%99%E8%82%B22024%E9%A1%B9%E7%9B%AE%E5%9B%BE%E5%BD%B1%E4%BB%8B%E7%BB%8D_.pdf' |
| 253 | }, | 270 | }, |
| 254 | { | 271 | { |
| 255 | - title: '保险合同条款解读与风险提示', | 272 | + title: '产品收益率测算表(2024版)', |
| 256 | learners: '142人学习', | 273 | learners: '142人学习', |
| 257 | progress: '52%', | 274 | progress: '52%', |
| 258 | - fileName: '保险合同条款解读与风险提示.pdf', | 275 | + // Excel 文件 |
| 276 | + fileName: '产品收益率测算表.xlsx', | ||
| 259 | downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/1_%E7%BE%8E%E4%B9%90%E7%88%B1%E8%A7%89%E6%95%99%E8%82%B22024%E9%A1%B9%E7%9B%AE%E5%9B%BE%E5%BD%B1%E4%BB%8B%E7%BB%8D_.pdf' | 277 | downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/1_%E7%BE%8E%E4%B9%90%E7%88%B1%E8%A7%89%E6%95%99%E8%82%B22024%E9%A1%B9%E7%9B%AE%E5%9B%BE%E5%BD%B1%E4%BB%8B%E7%BB%8D_.pdf' |
| 260 | } | 278 | } |
| 261 | ]); | 279 | ]); | ... | ... |
| ... | @@ -27,7 +27,11 @@ | ... | @@ -27,7 +27,11 @@ |
| 27 | <!-- 左侧图标 --> | 27 | <!-- 左侧图标 --> |
| 28 | <div | 28 | <div |
| 29 | class="w-[88rpx] h-[88rpx] mr-[24rpx] flex-shrink-0 flex items-center justify-center bg-gradient-to-br from-blue-50 to-blue-100 rounded-[20rpx] shadow-inner"> | 29 | class="w-[88rpx] h-[88rpx] mr-[24rpx] flex-shrink-0 flex items-center justify-center bg-gradient-to-br from-blue-50 to-blue-100 rounded-[20rpx] shadow-inner"> |
| 30 | - <IconFont :name="item.iconName || 'order'" size="32" :color="item.iconColor || '#2563EB'" /> | 30 | + <image |
| 31 | + :src="getDocumentIcon(item.fileName)" | ||
| 32 | + class="w-[48rpx] h-[48rpx]" | ||
| 33 | + mode="aspectFit" | ||
| 34 | + /> | ||
| 31 | </div> | 35 | </div> |
| 32 | 36 | ||
| 33 | <!-- 内容区域 --> | 37 | <!-- 内容区域 --> |
| ... | @@ -58,7 +62,7 @@ | ... | @@ -58,7 +62,7 @@ |
| 58 | <div class="flex items-center gap-[12rpx]"> | 62 | <div class="flex items-center gap-[12rpx]"> |
| 59 | <span | 63 | <span |
| 60 | class="inline-flex items-center justify-center px-[12rpx] py-[4rpx] bg-gray-100 text-gray-500 text-[20rpx] font-medium rounded-[8rpx]"> | 64 | class="inline-flex items-center justify-center px-[12rpx] py-[4rpx] bg-gray-100 text-gray-500 text-[20rpx] font-medium rounded-[8rpx]"> |
| 61 | 65 | + {{ getDocumentLabel(item.fileName) }} | |
| 62 | </span> | 66 | </span> |
| 63 | <span class="text-[#9CA3AF] text-[22rpx]"> | 67 | <span class="text-[#9CA3AF] text-[22rpx]"> |
| 64 | {{ item.size }} | 68 | {{ item.size }} |
| ... | @@ -70,7 +74,7 @@ | ... | @@ -70,7 +74,7 @@ |
| 70 | class="flex items-center justify-center px-[20rpx] py-[10rpx] bg-blue-50 rounded-full active:bg-blue-100 transition-colors" | 74 | class="flex items-center justify-center px-[20rpx] py-[10rpx] bg-blue-50 rounded-full active:bg-blue-100 transition-colors" |
| 71 | @tap.stop="onView(item)"> | 75 | @tap.stop="onView(item)"> |
| 72 | <IconFont name="eye" size="14" color="#2563EB" class="mr-[6rpx]" /> | 76 | <IconFont name="eye" size="14" color="#2563EB" class="mr-[6rpx]" /> |
| 73 | - <text class="text-[24rpx] text-blue-600 font-medium leading-none">查看</text> | 77 | + <text class="text-[24rpx] text-blue-600 font-medium leading-none ml-[8rpx]">查看</text> |
| 74 | </view> | 78 | </view> |
| 75 | </div> | 79 | </div> |
| 76 | </div> | 80 | </div> |
| ... | @@ -89,6 +93,7 @@ import NavHeader from '@/components/NavHeader.vue' | ... | @@ -89,6 +93,7 @@ import NavHeader from '@/components/NavHeader.vue' |
| 89 | import TabBar from '@/components/TabBar.vue' | 93 | import TabBar from '@/components/TabBar.vue' |
| 90 | import IconFont from '@/components/IconFont.vue' | 94 | import IconFont from '@/components/IconFont.vue' |
| 91 | import { useListItemClick, ListType } from '@/composables/useListItemClick' | 95 | import { useListItemClick, ListType } from '@/composables/useListItemClick' |
| 96 | +import { getDocumentIcon, getDocumentLabel } from '@/utils/documentIcons' | ||
| 92 | 97 | ||
| 93 | const searchValue = ref('') | 98 | const searchValue = ref('') |
| 94 | 99 | ... | ... |
| ... | @@ -95,7 +95,11 @@ | ... | @@ -95,7 +95,11 @@ |
| 95 | > | 95 | > |
| 96 | <div class="flex items-center justify-between mb-[8rpx]"> | 96 | <div class="flex items-center justify-between mb-[8rpx]"> |
| 97 | <div class="flex items-center flex-1 mr-[24rpx]"> | 97 | <div class="flex items-center flex-1 mr-[24rpx]"> |
| 98 | - <IconFont :name="file.iconName" size="24" :color="file.iconColor" class="mr-[24rpx]" /> | 98 | + <image |
| 99 | + :src="getDocumentIcon(file.fileName)" | ||
| 100 | + class="w-[48rpx] h-[48rpx] mr-[24rpx]" | ||
| 101 | + mode="aspectFit" | ||
| 102 | + /> | ||
| 99 | <div class="flex flex-col"> | 103 | <div class="flex flex-col"> |
| 100 | <span class="text-[#1F2937] text-[28rpx] font-medium mb-[4rpx] line-clamp-1">{{ file.name }}</span> | 104 | <span class="text-[#1F2937] text-[28rpx] font-medium mb-[4rpx] line-clamp-1">{{ file.name }}</span> |
| 101 | <span class="text-[#9CA3AF] text-[24rpx]">{{ file.size }}</span> | 105 | <span class="text-[#9CA3AF] text-[24rpx]">{{ file.size }}</span> |
| ... | @@ -120,6 +124,7 @@ import TabBar from '@/components/TabBar.vue' | ... | @@ -120,6 +124,7 @@ import TabBar from '@/components/TabBar.vue' |
| 120 | import IconFont from '@/components/IconFont.vue' | 124 | import IconFont from '@/components/IconFont.vue' |
| 121 | import { useFileOperation } from '@/composables/useFileOperation' | 125 | import { useFileOperation } from '@/composables/useFileOperation' |
| 122 | import Taro, { useLoad } from '@tarojs/taro' | 126 | import Taro, { useLoad } from '@tarojs/taro' |
| 127 | +import { getDocumentIcon } from '@/utils/documentIcons' | ||
| 123 | 128 | ||
| 124 | const { viewFile } = useFileOperation() | 129 | const { viewFile } = useFileOperation() |
| 125 | 130 | ... | ... |
src/utils/documentIcons.js
0 → 100644
| 1 | +/** | ||
| 2 | + * @description 文档图标工具函数 | ||
| 3 | + * @module utils/documentIcons | ||
| 4 | + * @author Claude Code | ||
| 5 | + * @created 2026-01-31 | ||
| 6 | + */ | ||
| 7 | + | ||
| 8 | +// 导入所有 SVG 图标资源 | ||
| 9 | +import docIcon from '@/assets/images/icon/doc/doc.svg' | ||
| 10 | +import wordIcon from '@/assets/images/icon/doc/word.svg' | ||
| 11 | +import xlsIcon from '@/assets/images/icon/doc/xls.svg' | ||
| 12 | +import pptIcon from '@/assets/images/icon/doc/ppt.svg' | ||
| 13 | +import jpegIcon from '@/assets/images/icon/doc/jpeg.svg' | ||
| 14 | +import pngIcon from '@/assets/images/icon/doc/png.svg' | ||
| 15 | +import mp4Icon from '@/assets/images/icon/doc/mp4.svg' | ||
| 16 | +import svgIcon from '@/assets/images/icon/doc/svg.svg' | ||
| 17 | +import txtIcon from '@/assets/images/icon/doc/txt.svg' | ||
| 18 | +import defaultIcon from '@/assets/images/icon/doc/其他文件.svg' | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * 文件扩展名到图标的映射 | ||
| 22 | + * @type {Object.<string, string>} | ||
| 23 | + */ | ||
| 24 | +const EXTENSION_ICON_MAP = { | ||
| 25 | + // 文档类 | ||
| 26 | + 'pdf': docIcon, | ||
| 27 | + 'doc': wordIcon, | ||
| 28 | + 'docx': wordIcon, | ||
| 29 | + | ||
| 30 | + // 表格类 | ||
| 31 | + 'xls': xlsIcon, | ||
| 32 | + 'xlsx': xlsIcon, | ||
| 33 | + | ||
| 34 | + // 演示文稿类 | ||
| 35 | + 'ppt': pptIcon, | ||
| 36 | + 'pptx': pptIcon, | ||
| 37 | + | ||
| 38 | + // 图片类 | ||
| 39 | + 'jpg': jpegIcon, | ||
| 40 | + 'jpeg': jpegIcon, | ||
| 41 | + 'png': pngIcon, | ||
| 42 | + 'gif': pngIcon, | ||
| 43 | + 'webp': pngIcon, | ||
| 44 | + | ||
| 45 | + // 视频类 | ||
| 46 | + 'mp4': mp4Icon, | ||
| 47 | + 'mov': mp4Icon, | ||
| 48 | + 'avi': mp4Icon, | ||
| 49 | + 'mkv': mp4Icon, | ||
| 50 | + | ||
| 51 | + // 矢量图类 | ||
| 52 | + 'svg': svgIcon, | ||
| 53 | + | ||
| 54 | + // 文本类 | ||
| 55 | + 'txt': txtIcon, | ||
| 56 | + 'md': txtIcon, | ||
| 57 | + | ||
| 58 | + // 其他 | ||
| 59 | + 'zip': defaultIcon, | ||
| 60 | + 'rar': defaultIcon, | ||
| 61 | + '7z': defaultIcon, | ||
| 62 | +}; | ||
| 63 | + | ||
| 64 | +/** | ||
| 65 | + * 默认图标(未知文件类型) | ||
| 66 | + * @type {string} | ||
| 67 | + */ | ||
| 68 | +const DEFAULT_ICON = defaultIcon; | ||
| 69 | + | ||
| 70 | +/** | ||
| 71 | + * 文件扩展名到显示标签的映射 | ||
| 72 | + * @type {Object.<string, string>} | ||
| 73 | + */ | ||
| 74 | +const EXTENSION_LABEL_MAP = { | ||
| 75 | + 'pdf': 'PDF', | ||
| 76 | + 'doc': 'Word', | ||
| 77 | + 'docx': 'Word', | ||
| 78 | + 'xls': 'Excel', | ||
| 79 | + 'xlsx': 'Excel', | ||
| 80 | + 'ppt': 'PPT', | ||
| 81 | + 'pptx': 'PPT', | ||
| 82 | + 'jpg': 'JPG', | ||
| 83 | + 'jpeg': 'JPEG', | ||
| 84 | + 'png': 'PNG', | ||
| 85 | + 'gif': 'GIF', | ||
| 86 | + 'webp': 'WebP', | ||
| 87 | + 'mp4': 'MP4', | ||
| 88 | + 'mov': 'MOV', | ||
| 89 | + 'avi': 'AVI', | ||
| 90 | + 'mkv': 'MKV', | ||
| 91 | + 'svg': 'SVG', | ||
| 92 | + 'txt': 'TXT', | ||
| 93 | + 'md': 'MD', | ||
| 94 | + 'zip': 'ZIP', | ||
| 95 | + 'rar': 'RAR', | ||
| 96 | + '7z': '7Z', | ||
| 97 | +}; | ||
| 98 | + | ||
| 99 | +/** | ||
| 100 | + * 默认文件类型标签 | ||
| 101 | + * @type {string} | ||
| 102 | + */ | ||
| 103 | +const DEFAULT_LABEL = 'DOC'; | ||
| 104 | + | ||
| 105 | +/** | ||
| 106 | + * 根据文件名获取文档图标路径 | ||
| 107 | + * | ||
| 108 | + * @description 从文件名中提取扩展名,返回对应的图标路径 | ||
| 109 | + * @param {string} fileName - 文件名(如:document.pdf) | ||
| 110 | + * @returns {string} 图标路径 | ||
| 111 | + * | ||
| 112 | + * @example | ||
| 113 | + * getDocumentIcon('报告.pdf') // 返回 PDF 图标 | ||
| 114 | + * getDocumentIcon('数据.xlsx') // 返回 Excel 图标 | ||
| 115 | + * getDocumentIcon('图片.png') // 返回 PNG 图标 | ||
| 116 | + */ | ||
| 117 | +export function getDocumentIcon(fileName) { | ||
| 118 | + if (!fileName || typeof fileName !== 'string') { | ||
| 119 | + return DEFAULT_ICON; | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + // 提取文件扩展名 | ||
| 123 | + const lastDotIndex = fileName.lastIndexOf('.'); | ||
| 124 | + | ||
| 125 | + // 没有扩展名或以点结尾(如 "file.") | ||
| 126 | + if (lastDotIndex === -1 || lastDotIndex === fileName.length - 1) { | ||
| 127 | + return DEFAULT_ICON; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + const extension = fileName.slice(lastDotIndex + 1).toLowerCase(); | ||
| 131 | + | ||
| 132 | + // 返回对应图标,找不到则返回默认图标 | ||
| 133 | + return EXTENSION_ICON_MAP[extension] || DEFAULT_ICON; | ||
| 134 | +} | ||
| 135 | + | ||
| 136 | +/** | ||
| 137 | + * 根据文件名获取文件类型标签 | ||
| 138 | + * | ||
| 139 | + * @description 从文件名中提取扩展名,返回对应的显示标签 | ||
| 140 | + * @param {string} fileName - 文件名(如:document.pdf) | ||
| 141 | + * @returns {string} 文件类型标签(如:PDF、Word、Excel) | ||
| 142 | + * | ||
| 143 | + * @example | ||
| 144 | + * getDocumentLabel('报告.pdf') // 'PDF' | ||
| 145 | + * getDocumentLabel('数据.xlsx') // 'Excel' | ||
| 146 | + * getDocumentLabel('图片.png') // 'PNG' | ||
| 147 | + */ | ||
| 148 | +export function getDocumentLabel(fileName) { | ||
| 149 | + if (!fileName || typeof fileName !== 'string') { | ||
| 150 | + return DEFAULT_LABEL; | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + // 提取文件扩展名 | ||
| 154 | + const lastDotIndex = fileName.lastIndexOf('.'); | ||
| 155 | + | ||
| 156 | + // 没有扩展名或以点结尾(如 "file.") | ||
| 157 | + if (lastDotIndex === -1 || lastDotIndex === fileName.length - 1) { | ||
| 158 | + return DEFAULT_LABEL; | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + const extension = fileName.slice(lastDotIndex + 1).toLowerCase(); | ||
| 162 | + | ||
| 163 | + // 返回对应标签,找不到则返回默认标签 | ||
| 164 | + return EXTENSION_LABEL_MAP[extension] || DEFAULT_LABEL; | ||
| 165 | +} | ||
| 166 | + | ||
| 167 | +/** | ||
| 168 | + * 根据文件名判断是否为 PDF 文件 | ||
| 169 | + * | ||
| 170 | + * @param {string} fileName - 文件名 | ||
| 171 | + * @returns {boolean} 是否为 PDF 文件 | ||
| 172 | + * | ||
| 173 | + * @example | ||
| 174 | + * isPDF('document.pdf') // true | ||
| 175 | + * isPDF('document.docx') // false | ||
| 176 | + */ | ||
| 177 | +export function isPDF(fileName) { | ||
| 178 | + const extension = fileName?.split('.').pop()?.toLowerCase(); | ||
| 179 | + return extension === 'pdf'; | ||
| 180 | +} | ||
| 181 | + | ||
| 182 | +/** | ||
| 183 | + * 根据文件名判断是否为图片文件 | ||
| 184 | + * | ||
| 185 | + * @param {string} fileName - 文件名 | ||
| 186 | + * @returns {boolean} 是否为图片文件 | ||
| 187 | + * | ||
| 188 | + * @example | ||
| 189 | + * isImage('photo.jpg') // true | ||
| 190 | + * isImage('document.pdf') // false | ||
| 191 | + */ | ||
| 192 | +export function isImage(fileName) { | ||
| 193 | + const extension = fileName?.split('.').pop()?.toLowerCase(); | ||
| 194 | + const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg']; | ||
| 195 | + return imageExtensions.includes(extension); | ||
| 196 | +} | ||
| 197 | + | ||
| 198 | +/** | ||
| 199 | + * 根据文件名判断是否为视频文件 | ||
| 200 | + * | ||
| 201 | + * @param {string} fileName - 文件名 | ||
| 202 | + * @returns {boolean} 是否为视频文件 | ||
| 203 | + * | ||
| 204 | + * @example | ||
| 205 | + * isVideo('movie.mp4') // true | ||
| 206 | + * isVideo('document.pdf') // false | ||
| 207 | + */ | ||
| 208 | +export function isVideo(fileName) { | ||
| 209 | + const extension = fileName?.split('.').pop()?.toLowerCase(); | ||
| 210 | + const videoExtensions = ['mp4', 'mov', 'avi', 'mkv']; | ||
| 211 | + return videoExtensions.includes(extension); | ||
| 212 | +} |
-
Please register or login to post a comment