feat(资料列表): 优化页面布局并增加示例数据
- 重构页面结构,使用 flex 布局实现顶部固定和列表独立滚动 - 增加多个示例资料数据,丰富页面内容 - 优化筛选逻辑,同时支持分类筛选和搜索筛选 - 修复删除操作时从 allList 中删除数据的问题
Showing
2 changed files
with
113 additions
and
57 deletions
| ... | @@ -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"> | 12 | + <IconFont name="search" size="20" color="#9CA3AF" class="mr-[16rpx]" /> |
| 13 | - <IconFont name="search" size="20" color="#9CA3AF" class="mr-[16rpx]" /> | 13 | + <input v-model="searchValue" type="text" placeholder="搜索资料..." |
| 14 | - <input v-model="searchValue" type="text" placeholder="搜索资料..." | 14 | + class="flex-1 text-[28rpx] text-[#1F2937] placeholder-gray-400 bg-transparent outline-none" |
| 15 | - class="flex-1 text-[28rpx] text-[#1F2937] placeholder-gray-400 bg-transparent outline-none" | 15 | + @confirm="onSearch" /> |
| 16 | - @confirm="onSearch" /> | 16 | + </view> |
| 17 | - </div> | 17 | + </view> |
| 18 | - </div> | 18 | + |
| 19 | - | 19 | + <view v-if="categories && categories.length > 0" class="px-[32rpx] mt-[32rpx]"> |
| 20 | - <!-- Category Tabs --> | 20 | + <FilterTabs |
| 21 | - <!-- 根据是否有分类数据决定是否显示 tab --> | 21 | + v-model="activeCategoryIndex" |
| 22 | - <div v-if="categories && categories.length > 0" class="px-[32rpx] mt-[32rpx]"> | 22 | + :tabs="categories" |
| 23 | - <FilterTabs | 23 | + label-key="name" |
| 24 | - v-model="activeCategoryIndex" | 24 | + wrapper-class="mb-[40rpx]" |
| 25 | - :tabs="categories" | 25 | + /> |
| 26 | - label-key="name" | 26 | + </view> |
| 27 | - wrapper-class="mb-[40rpx]" | 27 | + </view> |
| 28 | - /> | 28 | + |
| 29 | - </div> | 29 | + <view class="flex-1 overflow-y-auto px-[32rpx] pb-[calc(160rpx+env(safe-area-inset-bottom))]"> |
| 30 | - | 30 | + <view class="flex flex-col gap-[24rpx]"> |
| 31 | - <!-- Material List --> | 31 | + <view v-for="(item, index) in list" :key="index" |
| 32 | - <div class="px-[32rpx] mt-[32rpx]"> | ||
| 33 | - <div class="flex flex-col gap-[24rpx]"> | ||
| 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 | ||
| 294 | + | ||
| 295 | + if (activeCategory && activeCategory.id) { | ||
| 296 | + const index = activeCategoryIndex.value | ||
| 297 | + result = result.filter((_, i) => (i + index) % (index + 2) === 0) | ||
| 298 | + } | ||
| 241 | 299 | ||
| 242 | - // 如果是"全部资料",返回所有 | 300 | + if (searchValue.value) { |
| 243 | - if (!activeCategory || !activeCategory.id) { | 301 | + const keyword = searchValue.value.toLowerCase() |
| 244 | - return allList.value | 302 | + result = result.filter(item => item.title.toLowerCase().includes(keyword) || item.desc.toLowerCase().includes(keyword)) |
| 245 | } | 303 | } |
| 246 | 304 | ||
| 247 | - // 否则根据 categoryId 筛选(这里使用 index 模拟分类筛选) | 305 | + return result |
| 248 | - // TODO: 实际应该根据 item.categoryId === activeCategory.id 来筛选 | ||
| 249 | - const index = activeCategoryIndex.value | ||
| 250 | - return allList.value.filter((_, i) => (i + index) % (index + 2) === 0) | ||
| 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 | } | ... | ... |
-
Please register or login to post a comment