hookehuyr

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

- 消息列表页优先使用 API 返回的 title 字段
- 保留 getItemTitle 作为降级方案
- 更新 API 文档以反映 title 字段
- 同步更新消息详情页
......@@ -75,17 +75,81 @@ paths:
pk_id:
type: integer
title: 计划书订单ID
proposal:
type: object
properties:
id:
type: integer
customer_name:
type: string
title: 申请人
product_name:
type: string
title: 产品名
categories:
type: array
items:
type: object
properties:
id:
type: string
title: 分类id
name:
type: string
title: 分类名
x-apifox-orders:
- id
- name
title: 分类
created_time:
type: string
title: 创建时间
order_status:
type: string
title: 状态
proposal_files:
type: array
items:
type: object
properties:
file_name:
type: string
title: 名称
file_url:
type: string
title: 地址
id:
type: integer
required:
- file_name
- file_url
x-apifox-orders:
- id
- file_url
- file_name
title: 生成的计划书
x-apifox-orders:
- id
- customer_name
- product_name
- created_time
- order_status
- categories
- proposal_files
title: 计划书订单
x-apifox-orders:
- id
- note
- created_time
- status
- pk_id
- proposal
required:
- note
- created_time
- status
- pk_id
- proposal
required:
- code
- msg
......
......@@ -87,17 +87,22 @@ paths:
pk_id:
type: integer
title: 计划书订单ID
title:
type: string
title: 标题
x-apifox-orders:
- id
- note
- created_time
- status
- pk_id
- title
required:
- note
- created_time
- status
- pk_id
- title
total:
type: integer
x-apifox-orders:
......
......@@ -19,6 +19,22 @@ const Api = {
created_time: string; // 发消息的时间
status: string; // send=以发送未读取,read=已读取
pk_id: integer; // 计划书订单ID
proposal: {
id: integer; //
customer_name: string; // 申请人
product_name: string; // 产品名
categories: Array<{
id: string; // 分类id
name: string; // 分类名
}>;
created_time: string; // 创建时间
order_status: string; // 状态
proposal_files: Array<{
file_name: string; // 名称
file_url: string; // 地址
id: integer; //
}>;
};
* };
* }>}
*/
......@@ -40,6 +56,7 @@ export const detailAPI = (params) => fn(fetch.get(Api.Detail, params));
created_time: string; // 发消息的时间
status: string; // send=以发送未读取,read=已读取
pk_id: integer; // 计划书订单ID
title: string; // 标题
}>;
total: integer; //
* };
......
......@@ -20,3 +20,9 @@ page {
background-color: #F9FAFB;
}
// 安全区域顶部适配(刘海屏等)
.safe-area-top {
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);
}
......
/*
* @Date: 2026-02-13 01:05:52
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2026-02-13 14:17:14
* @FilePath: /manulife-weapp/src/config/app.js
* @Description: 应用配置
*/
/**
* 应用配置
*
......
<!--
* @Date:2026-02-08
* @Description: 我的消息页 - 使用 LoadMoreList 组件重构版本
* @Update:2026-02-13 API 新增 title 字段,直接使用 API 返回的标题
-->
<template>
<LoadMoreList
......@@ -30,7 +31,9 @@
<!-- 顶部:标题与红点 -->
<view class="flex justify-between items-start mb-2">
<view class="flex-1 mr-2 relative">
<!-- 未读红点 -->
<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>
<!-- 标题:优先使用 API 返回的 title,降级使用 note 第一行 -->
<text class="text-lg font-bold text-gray-900 line-clamp-1 leading-snug">
{{ item.title || getItemTitle(item.note) }}
</text>
......@@ -48,7 +51,7 @@
<!-- 中间:内容预览 -->
<view class="mb-4">
<text class="text-sm text-gray-500 line-clamp-2 leading-relaxed">
{{ getItemPreview(item.note) || '点击查看详情' }}
{{ getItemPreview(item.note) }}
</text>
</view>
......@@ -98,10 +101,17 @@ const loadingMore = ref(false)
const isFirstLoad = ref(true)
/**
* 提取消息标题(第一行或截取)
* 提取消息标题(降级方案:从 note 第一行提取)
*
* @description 当 API 未返回 title 时,从 note 内容的第一行提取标题
* @param {string} note - 消息内容
* @returns {string} 标题
*
* @example
* // API 已返回 title
* getItemTitle(note) // 不使用,直接显示 item.title
* // API 未返回 title(降级)
* getItemTitle('这是第一行标题\n这是内容') // 返回: '这是第一行标题'
*/
const getItemTitle = (note) => {
if (!note) return '暂无消息内容'
......@@ -112,28 +122,33 @@ const getItemTitle = (note) => {
// 移除富文本标签(简单处理)
const textOnly = firstLine.replace(/<[^>]+>/g, '').trim()
// 如果第一行太长,截取前50个字符
// 如果第一行太长,截取前 50 个字符
return textOnly.length > 50 ? textOnly.substring(0, 50) + '...' : textOnly
}
/**
* 提取消息预览(移除第一行后的内容)
* 提取消息预览
*
* @description 移除第一行标题后的内容作为预览
* @param {string} note - 消息内容
* @returns {string} 预览内容
*
* @example
* getItemPreview('标题\n内容第二行\n内容第三行') // 返回: '内容第二行\n内容第三行'
* getItemPreview('只有单行内容') // 返回: '点击查看详情'
*/
const getItemPreview = (note) => {
if (!note) return ''
if (!note) return '点击查看详情'
// 移除第一行(已标题显示)
// 移除第一行(已作为标题显示)
const lines = note.split('\n')
if (lines.length > 1) {
// 移除富文本标签(简单处理)
const preview = lines.slice(1).join('\n').replace(/<[^>]+>/g, '').trim()
return preview.substring(0, 100) // 限制预览长度
return preview || '点击查看详情'
}
return '' // 只有一行时不显示预览
return '点击查看详情' // 只有一行时
}
/**
......@@ -167,11 +182,8 @@ const fetchMessageList = async (params = {}, isLoadMore = false) => {
// 处理列表数据
if (res.data.list?.length) {
// 模拟标题数据
const listData = res.data.list.map(item => ({
...item,
title: item.title || '关于系统维护升级的通知公告' // 模拟标题
}))
// 直接使用 API 返回的数据(title 字段由后端提供)
const listData = res.data.list
if (isLoadMore) {
// 加载更多:追加数据
......