hookehuyr

feat(资料列表): 优化页面布局并增加示例数据

- 重构页面结构,使用 flex 布局实现顶部固定和列表独立滚动
- 增加多个示例资料数据,丰富页面内容
- 优化筛选逻辑,同时支持分类筛选和搜索筛选
- 修复删除操作时从 allList 中删除数据的问题
...@@ -77,6 +77,7 @@ src/ ...@@ -77,6 +77,7 @@ src/
77 ## 📄 页面说明 77 ## 📄 页面说明
78 78
79 - 计划书页面支持顶部搜索与标签固定,列表区域独立滚动,便于快速筛选和浏览 79 - 计划书页面支持顶部搜索与标签固定,列表区域独立滚动,便于快速筛选和浏览
80 +- 资料列表页面支持顶部搜索与分类固定,列表区域独立滚动,便于批量浏览与筛选
80 - 资料列表、知识库、收藏、计划书页面统一使用 FilterTabs 组件进行横向筛选 81 - 资料列表、知识库、收藏、计划书页面统一使用 FilterTabs 组件进行横向筛选
81 82
82 ## ✅ 优化建议 83 ## ✅ 优化建议
......
...@@ -3,50 +3,45 @@ ...@@ -3,50 +3,45 @@
3 * @Description: 资料列表页 3 * @Description: 资料列表页
4 --> 4 -->
5 <template> 5 <template>
6 - <div class="min-h-screen bg-[#F9FAFB] pb-[calc(160rpx+env(safe-area-inset-bottom))]"> 6 + <view class="h-screen bg-[#F9FAFB] flex flex-col">
7 - <!-- Navigation Header --> 7 + <view class="bg-[#F9FAFB]">
8 <NavHeader :title="pageTitle" /> 8 <NavHeader :title="pageTitle" />
9 9
10 - <!-- Search Bar --> 10 + <view class="px-[32rpx] mt-[32rpx]">
11 - <div class="px-[32rpx] mt-[32rpx]"> 11 + <view class="bg-white rounded-[20rpx] flex items-center px-[32rpx] py-[24rpx] shadow-sm border border-gray-50">
12 - <div class="bg-white rounded-[20rpx] flex items-center px-[32rpx] py-[24rpx] shadow-sm border border-gray-50">
13 <IconFont name="search" size="20" color="#9CA3AF" class="mr-[16rpx]" /> 12 <IconFont name="search" size="20" color="#9CA3AF" class="mr-[16rpx]" />
14 <input v-model="searchValue" type="text" placeholder="搜索资料..." 13 <input v-model="searchValue" type="text" placeholder="搜索资料..."
15 class="flex-1 text-[28rpx] text-[#1F2937] placeholder-gray-400 bg-transparent outline-none" 14 class="flex-1 text-[28rpx] text-[#1F2937] placeholder-gray-400 bg-transparent outline-none"
16 @confirm="onSearch" /> 15 @confirm="onSearch" />
17 - </div> 16 + </view>
18 - </div> 17 + </view>
19 18
20 - <!-- Category Tabs --> 19 + <view v-if="categories && categories.length > 0" class="px-[32rpx] mt-[32rpx]">
21 - <!-- 根据是否有分类数据决定是否显示 tab -->
22 - <div v-if="categories && categories.length > 0" class="px-[32rpx] mt-[32rpx]">
23 <FilterTabs 20 <FilterTabs
24 v-model="activeCategoryIndex" 21 v-model="activeCategoryIndex"
25 :tabs="categories" 22 :tabs="categories"
26 label-key="name" 23 label-key="name"
27 wrapper-class="mb-[40rpx]" 24 wrapper-class="mb-[40rpx]"
28 /> 25 />
29 - </div> 26 + </view>
27 + </view>
30 28
31 - <!-- Material List --> 29 + <view class="flex-1 overflow-y-auto px-[32rpx] pb-[calc(160rpx+env(safe-area-inset-bottom))]">
32 - <div class="px-[32rpx] mt-[32rpx]"> 30 + <view class="flex flex-col gap-[24rpx]">
33 - <div class="flex flex-col gap-[24rpx]"> 31 + <view v-for="(item, index) in list" :key="index"
34 - <div v-for="(item, index) in list" :key="index"
35 class="material-item bg-white rounded-[24rpx] p-[24rpx] shadow-sm transition-all duration-200 border border-gray-50 flex flex-row" 32 class="material-item bg-white rounded-[24rpx] p-[24rpx] shadow-sm transition-all duration-200 border border-gray-50 flex flex-row"
36 :style="{ animationDelay: `${index * 50}ms` }"> 33 :style="{ animationDelay: `${index * 50}ms` }">
37 34
38 - <!-- 左侧图标 --> 35 + <view
39 - <div
40 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 self-start"> 36 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 self-start">
41 <image 37 <image
42 :src="getDocumentIcon(item.fileName)" 38 :src="getDocumentIcon(item.fileName)"
43 class="w-[48rpx] h-[48rpx]" 39 class="w-[48rpx] h-[48rpx]"
44 mode="aspectFit" 40 mode="aspectFit"
45 /> 41 />
46 - </div> 42 + </view>
47 43
48 - <!-- 内容区域 --> 44 + <view class="flex-1 min-w-0">
49 - <div class="flex-1 min-w-0">
50 <h3 class="text-[#1F2937] text-[30rpx] font-bold leading-[1.4] line-clamp-2 mb-[8rpx]"> 45 <h3 class="text-[#1F2937] text-[30rpx] font-bold leading-[1.4] line-clamp-2 mb-[8rpx]">
51 {{ item.title }} 46 {{ item.title }}
52 </h3> 47 </h3>
...@@ -54,21 +49,18 @@ ...@@ -54,21 +49,18 @@
54 {{ item.desc }} 49 {{ item.desc }}
55 </p> 50 </p>
56 51
57 - <!-- 文件信息 --> 52 + <view class="flex items-center gap-[12rpx] mb-[20rpx]">
58 - <div class="flex items-center gap-[12rpx] mb-[20rpx]"> 53 + <view
59 - <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]"> 54 class="inline-flex items-center justify-center px-[12rpx] py-[4rpx] bg-gray-100 text-gray-500 text-[20rpx] font-medium rounded-[8rpx]">
61 {{ getDocumentLabel(item.fileName) }} 55 {{ getDocumentLabel(item.fileName) }}
62 - </span> 56 + </view>
63 - <span class="text-[#9CA3AF] text-[22rpx]"> 57 + <view class="text-[#9CA3AF] text-[22rpx]">
64 {{ item.size }} 58 {{ item.size }}
65 - </span> 59 + </view>
66 - </div> 60 + </view>
67 61
68 - <!-- 分割线 -->
69 <view class="h-[1rpx] bg-gray-100 my-[20rpx]"></view> 62 <view class="h-[1rpx] bg-gray-100 my-[20rpx]"></view>
70 63
71 - <!-- 操作按钮 -->
72 <ListItemActions 64 <ListItemActions
73 :viewable="true" 65 :viewable="true"
74 :collectable="true" 66 :collectable="true"
...@@ -77,14 +69,14 @@ ...@@ -77,14 +69,14 @@
77 @collect="toggleCollect(item)" 69 @collect="toggleCollect(item)"
78 @delete="onDelete(item)" 70 @delete="onDelete(item)"
79 /> 71 />
80 - </div> 72 + </view>
81 - </div> 73 + </view>
82 - </div> 74 + </view>
83 - </div> 75 + </view>
84 76
85 <!-- Tab Bar --> 77 <!-- Tab Bar -->
86 <!-- <TabBar /> --> 78 <!-- <TabBar /> -->
87 - </div> 79 + </view>
88 </template> 80 </template>
89 81
90 <script setup> 82 <script setup>
...@@ -228,6 +220,66 @@ const allList = ref([ ...@@ -228,6 +220,66 @@ const allList = ref([
228 collected: false, 220 collected: false,
229 fileName: '考场注意事项及答题技巧.pdf', 221 fileName: '考场注意事项及答题技巧.pdf',
230 downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/1_%E7%BE%8E4%B9%90%E7%88%B1%E8%A7%89%E6%95%99%E8%82%B22024%E9%A1%B9%E7%9B%AE%E5%9B%E5%BD%B1%E4%BB%8B%E7%BB%8D_.pdf' 222 downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/1_%E7%BE%8E4%B9%90%E7%88%B1%E8%A7%89%E6%95%99%E8%82%B22024%E9%A1%B9%E7%9B%AE%E5%9B%E5%BD%B1%E4%BB%8B%E7%BB%8D_.pdf'
223 + },
224 + {
225 + title: '2024产品手册-旗舰版.pptx',
226 + desc: '核心卖点与条款速览',
227 + size: '6.8MB',
228 + iconName: 'order',
229 + iconColor: '#EF4444',
230 + collected: false,
231 + fileName: '2024产品手册-旗舰版.pptx',
232 + downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/1_%E7%BE%8E4%B9%90%E7%88%B1%E8%A7%89%E6%95%99%E8%82%B22024%E9%A1%B9%E7%9B%AE%E5%9B%E5%BD%B1%E4%BB%8B%E7%BB%8D_.pdf'
233 + },
234 + {
235 + title: '新人成长训练营课程表.xlsx',
236 + desc: '培训计划与日程安排',
237 + size: '0.9MB',
238 + iconName: 'order',
239 + iconColor: '#EF4444',
240 + collected: true,
241 + fileName: '新人成长训练营课程表.xlsx',
242 + downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/1_%E7%BE%8E4%B9%90%E7%88%B1%E8%A7%82%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'
243 + },
244 + {
245 + title: '高客访谈案例集.docx',
246 + desc: '高净值客户沟通案例',
247 + size: '3.4MB',
248 + iconName: 'order',
249 + iconColor: '#EF4444',
250 + collected: false,
251 + fileName: '高客访谈案例集.docx',
252 + downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/1_%E7%BE%8E4%B9%90%E7%88%B1%E8%A7%82%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 + },
254 + {
255 + title: '合规操作指引2024.pdf',
256 + desc: '最新合规要点与流程',
257 + size: '2.6MB',
258 + iconName: 'order',
259 + iconColor: '#EF4444',
260 + collected: true,
261 + fileName: '合规操作指引2024.pdf',
262 + downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/1_%E7%BE%8E4%B9%90%E7%88%B1%E8%A7%82%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'
263 + },
264 + {
265 + title: '客户需求分析模板.xlsx',
266 + desc: '快速梳理家庭需求',
267 + size: '0.6MB',
268 + iconName: 'order',
269 + iconColor: '#EF4444',
270 + collected: false,
271 + fileName: '客户需求分析模板.xlsx',
272 + downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/1_%E7%BE%8E4%B9%90%E7%88%B1%E8%A7%82%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'
273 + },
274 + {
275 + title: '线上展业话术脚本.txt',
276 + desc: '直播场景话术与流程',
277 + size: '0.2MB',
278 + iconName: 'order',
279 + iconColor: '#EF4444',
280 + collected: false,
281 + fileName: '线上展业话术脚本.txt',
282 + downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/1_%E7%BE%8E4%B9%90%E7%88%B1%E8%A7%82%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'
231 } 283 }
232 ]) 284 ])
233 285
...@@ -238,16 +290,19 @@ const allList = ref([ ...@@ -238,16 +290,19 @@ const allList = ref([
238 */ 290 */
239 const list = computed(() => { 291 const list = computed(() => {
240 const activeCategory = categories.value[activeCategoryIndex.value] 292 const activeCategory = categories.value[activeCategoryIndex.value]
293 + let result = allList.value
241 294
242 - // 如果是"全部资料",返回所有 295 + if (activeCategory && activeCategory.id) {
243 - if (!activeCategory || !activeCategory.id) { 296 + const index = activeCategoryIndex.value
244 - return allList.value 297 + result = result.filter((_, i) => (i + index) % (index + 2) === 0)
245 } 298 }
246 299
247 - // 否则根据 categoryId 筛选(这里使用 index 模拟分类筛选) 300 + if (searchValue.value) {
248 - // TODO: 实际应该根据 item.categoryId === activeCategory.id 来筛选 301 + const keyword = searchValue.value.toLowerCase()
249 - const index = activeCategoryIndex.value 302 + result = result.filter(item => item.title.toLowerCase().includes(keyword) || item.desc.toLowerCase().includes(keyword))
250 - return allList.value.filter((_, i) => (i + index) % (index + 2) === 0) 303 + }
304 +
305 + return result
251 }) 306 })
252 307
253 /** 308 /**
...@@ -356,9 +411,9 @@ const onDelete = (item) => { ...@@ -356,9 +411,9 @@ const onDelete = (item) => {
356 content: '确定要删除该资料吗?', 411 content: '确定要删除该资料吗?',
357 success: (res) => { 412 success: (res) => {
358 if (res.confirm) { 413 if (res.confirm) {
359 - const index = list.value.findIndex(i => i.title === item.title) 414 + const index = allList.value.findIndex(i => i.title === item.title)
360 if (index !== -1) { 415 if (index !== -1) {
361 - list.value.splice(index, 1) 416 + allList.value.splice(index, 1)
362 Taro.showToast({ title: '已删除', icon: 'success' }) 417 Taro.showToast({ title: '已删除', icon: 'success' })
363 } 418 }
364 } 419 }
......