hookehuyr

feat(news): 支持消息列表后端 title 字段

- 消息列表页优先使用 API 返回的 title 字段
- 保留 getItemTitle 作为降级方案
- 更新 API 文档以反映 title 字段
- 同步更新消息详情页
...@@ -75,17 +75,81 @@ paths: ...@@ -75,17 +75,81 @@ paths:
75 pk_id: 75 pk_id:
76 type: integer 76 type: integer
77 title: 计划书订单ID 77 title: 计划书订单ID
78 + proposal:
79 + type: object
80 + properties:
81 + id:
82 + type: integer
83 + customer_name:
84 + type: string
85 + title: 申请人
86 + product_name:
87 + type: string
88 + title: 产品名
89 + categories:
90 + type: array
91 + items:
92 + type: object
93 + properties:
94 + id:
95 + type: string
96 + title: 分类id
97 + name:
98 + type: string
99 + title: 分类名
100 + x-apifox-orders:
101 + - id
102 + - name
103 + title: 分类
104 + created_time:
105 + type: string
106 + title: 创建时间
107 + order_status:
108 + type: string
109 + title: 状态
110 + proposal_files:
111 + type: array
112 + items:
113 + type: object
114 + properties:
115 + file_name:
116 + type: string
117 + title: 名称
118 + file_url:
119 + type: string
120 + title: 地址
121 + id:
122 + type: integer
123 + required:
124 + - file_name
125 + - file_url
126 + x-apifox-orders:
127 + - id
128 + - file_url
129 + - file_name
130 + title: 生成的计划书
131 + x-apifox-orders:
132 + - id
133 + - customer_name
134 + - product_name
135 + - created_time
136 + - order_status
137 + - categories
138 + - proposal_files
139 + title: 计划书订单
78 x-apifox-orders: 140 x-apifox-orders:
79 - id 141 - id
80 - note 142 - note
81 - created_time 143 - created_time
82 - status 144 - status
83 - pk_id 145 - pk_id
146 + - proposal
84 required: 147 required:
85 - note 148 - note
86 - created_time 149 - created_time
87 - status 150 - status
88 - pk_id 151 - pk_id
152 + - proposal
89 required: 153 required:
90 - code 154 - code
91 - msg 155 - msg
......
...@@ -87,17 +87,22 @@ paths: ...@@ -87,17 +87,22 @@ paths:
87 pk_id: 87 pk_id:
88 type: integer 88 type: integer
89 title: 计划书订单ID 89 title: 计划书订单ID
90 + title:
91 + type: string
92 + title: 标题
90 x-apifox-orders: 93 x-apifox-orders:
91 - id 94 - id
92 - note 95 - note
93 - created_time 96 - created_time
94 - status 97 - status
95 - pk_id 98 - pk_id
99 + - title
96 required: 100 required:
97 - note 101 - note
98 - created_time 102 - created_time
99 - status 103 - status
100 - pk_id 104 - pk_id
105 + - title
101 total: 106 total:
102 type: integer 107 type: integer
103 x-apifox-orders: 108 x-apifox-orders:
......
...@@ -19,6 +19,22 @@ const Api = { ...@@ -19,6 +19,22 @@ const Api = {
19 created_time: string; // 发消息的时间 19 created_time: string; // 发消息的时间
20 status: string; // send=以发送未读取,read=已读取 20 status: string; // send=以发送未读取,read=已读取
21 pk_id: integer; // 计划书订单ID 21 pk_id: integer; // 计划书订单ID
22 + proposal: {
23 + id: integer; //
24 + customer_name: string; // 申请人
25 + product_name: string; // 产品名
26 + categories: Array<{
27 + id: string; // 分类id
28 + name: string; // 分类名
29 + }>;
30 + created_time: string; // 创建时间
31 + order_status: string; // 状态
32 + proposal_files: Array<{
33 + file_name: string; // 名称
34 + file_url: string; // 地址
35 + id: integer; //
36 + }>;
37 + };
22 * }; 38 * };
23 * }>} 39 * }>}
24 */ 40 */
...@@ -40,6 +56,7 @@ export const detailAPI = (params) => fn(fetch.get(Api.Detail, params)); ...@@ -40,6 +56,7 @@ export const detailAPI = (params) => fn(fetch.get(Api.Detail, params));
40 created_time: string; // 发消息的时间 56 created_time: string; // 发消息的时间
41 status: string; // send=以发送未读取,read=已读取 57 status: string; // send=以发送未读取,read=已读取
42 pk_id: integer; // 计划书订单ID 58 pk_id: integer; // 计划书订单ID
59 + title: string; // 标题
43 }>; 60 }>;
44 total: integer; // 61 total: integer; //
45 * }; 62 * };
......
...@@ -20,3 +20,9 @@ page { ...@@ -20,3 +20,9 @@ page {
20 20
21 background-color: #F9FAFB; 21 background-color: #F9FAFB;
22 } 22 }
23 +
24 +// 安全区域顶部适配(刘海屏等)
25 +.safe-area-top {
26 + padding-top: constant(safe-area-inset-top);
27 + padding-top: env(safe-area-inset-top);
28 +}
......
1 +/*
2 + * @Date: 2026-02-13 01:05:52
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2026-02-13 14:17:14
5 + * @FilePath: /manulife-weapp/src/config/app.js
6 + * @Description: 应用配置
7 + */
1 /** 8 /**
2 * 应用配置 9 * 应用配置
3 * 10 *
......
1 <!-- 1 <!--
2 * @Date:2026-02-08 2 * @Date:2026-02-08
3 * @Description: 我的消息页 - 使用 LoadMoreList 组件重构版本 3 * @Description: 我的消息页 - 使用 LoadMoreList 组件重构版本
4 + * @Update:2026-02-13 API 新增 title 字段,直接使用 API 返回的标题
4 --> 5 -->
5 <template> 6 <template>
6 <LoadMoreList 7 <LoadMoreList
...@@ -30,7 +31,9 @@ ...@@ -30,7 +31,9 @@
30 <!-- 顶部:标题与红点 --> 31 <!-- 顶部:标题与红点 -->
31 <view class="flex justify-between items-start mb-2"> 32 <view class="flex justify-between items-start mb-2">
32 <view class="flex-1 mr-2 relative"> 33 <view class="flex-1 mr-2 relative">
34 + <!-- 未读红点 -->
33 <view v-if="item.status === 'send'" class="absolute -left-2 top-1.5 w-1.5 h-1.5 bg-red-500 rounded-full"></view> 35 <view v-if="item.status === 'send'" class="absolute -left-2 top-1.5 w-1.5 h-1.5 bg-red-500 rounded-full"></view>
36 + <!-- 标题:优先使用 API 返回的 title,降级使用 note 第一行 -->
34 <text class="text-lg font-bold text-gray-900 line-clamp-1 leading-snug"> 37 <text class="text-lg font-bold text-gray-900 line-clamp-1 leading-snug">
35 {{ item.title || getItemTitle(item.note) }} 38 {{ item.title || getItemTitle(item.note) }}
36 </text> 39 </text>
...@@ -48,7 +51,7 @@ ...@@ -48,7 +51,7 @@
48 <!-- 中间:内容预览 --> 51 <!-- 中间:内容预览 -->
49 <view class="mb-4"> 52 <view class="mb-4">
50 <text class="text-sm text-gray-500 line-clamp-2 leading-relaxed"> 53 <text class="text-sm text-gray-500 line-clamp-2 leading-relaxed">
51 - {{ getItemPreview(item.note) || '点击查看详情' }} 54 + {{ getItemPreview(item.note) }}
52 </text> 55 </text>
53 </view> 56 </view>
54 57
...@@ -98,10 +101,17 @@ const loadingMore = ref(false) ...@@ -98,10 +101,17 @@ const loadingMore = ref(false)
98 const isFirstLoad = ref(true) 101 const isFirstLoad = ref(true)
99 102
100 /** 103 /**
101 - * 提取消息标题(第一行或截取) 104 + * 提取消息标题(降级方案:从 note 第一行提取)
102 * 105 *
106 + * @description 当 API 未返回 title 时,从 note 内容的第一行提取标题
103 * @param {string} note - 消息内容 107 * @param {string} note - 消息内容
104 * @returns {string} 标题 108 * @returns {string} 标题
109 + *
110 + * @example
111 + * // API 已返回 title
112 + * getItemTitle(note) // 不使用,直接显示 item.title
113 + * // API 未返回 title(降级)
114 + * getItemTitle('这是第一行标题\n这是内容') // 返回: '这是第一行标题'
105 */ 115 */
106 const getItemTitle = (note) => { 116 const getItemTitle = (note) => {
107 if (!note) return '暂无消息内容' 117 if (!note) return '暂无消息内容'
...@@ -112,28 +122,33 @@ const getItemTitle = (note) => { ...@@ -112,28 +122,33 @@ const getItemTitle = (note) => {
112 // 移除富文本标签(简单处理) 122 // 移除富文本标签(简单处理)
113 const textOnly = firstLine.replace(/<[^>]+>/g, '').trim() 123 const textOnly = firstLine.replace(/<[^>]+>/g, '').trim()
114 124
115 - // 如果第一行太长,截取前50个字符 125 + // 如果第一行太长,截取前 50 个字符
116 return textOnly.length > 50 ? textOnly.substring(0, 50) + '...' : textOnly 126 return textOnly.length > 50 ? textOnly.substring(0, 50) + '...' : textOnly
117 } 127 }
118 128
119 /** 129 /**
120 - * 提取消息预览(移除第一行后的内容) 130 + * 提取消息预览
121 * 131 *
132 + * @description 移除第一行标题后的内容作为预览
122 * @param {string} note - 消息内容 133 * @param {string} note - 消息内容
123 * @returns {string} 预览内容 134 * @returns {string} 预览内容
135 + *
136 + * @example
137 + * getItemPreview('标题\n内容第二行\n内容第三行') // 返回: '内容第二行\n内容第三行'
138 + * getItemPreview('只有单行内容') // 返回: '点击查看详情'
124 */ 139 */
125 const getItemPreview = (note) => { 140 const getItemPreview = (note) => {
126 - if (!note) return '' 141 + if (!note) return '点击查看详情'
127 142
128 - // 移除第一行(已标题显示) 143 + // 移除第一行(已作为标题显示)
129 const lines = note.split('\n') 144 const lines = note.split('\n')
130 if (lines.length > 1) { 145 if (lines.length > 1) {
131 // 移除富文本标签(简单处理) 146 // 移除富文本标签(简单处理)
132 const preview = lines.slice(1).join('\n').replace(/<[^>]+>/g, '').trim() 147 const preview = lines.slice(1).join('\n').replace(/<[^>]+>/g, '').trim()
133 - return preview.substring(0, 100) // 限制预览长度 148 + return preview || '点击查看详情'
134 } 149 }
135 150
136 - return '' // 只有一行时不显示预览 151 + return '点击查看详情' // 只有一行时
137 } 152 }
138 153
139 /** 154 /**
...@@ -167,11 +182,8 @@ const fetchMessageList = async (params = {}, isLoadMore = false) => { ...@@ -167,11 +182,8 @@ const fetchMessageList = async (params = {}, isLoadMore = false) => {
167 182
168 // 处理列表数据 183 // 处理列表数据
169 if (res.data.list?.length) { 184 if (res.data.list?.length) {
170 - // 模拟标题数据 185 + // 直接使用 API 返回的数据(title 字段由后端提供)
171 - const listData = res.data.list.map(item => ({ 186 + const listData = res.data.list
172 - ...item,
173 - title: item.title || '关于系统维护升级的通知公告' // 模拟标题
174 - }))
175 187
176 if (isLoadMore) { 188 if (isLoadMore) {
177 // 加载更多:追加数据 189 // 加载更多:追加数据
......