hookehuyr

feat(user): 更新消息列表和详情页以匹配API规范

......@@ -5,6 +5,18 @@
---
## [2026-02-12] - 优化消息列表卡片布局
### 优化
- 重构消息列表卡片布局,提升信息可读性
- 简化卡片结构:第一行展示消息内容,第二行左侧展示时间,右侧展示状态
- 调整标题、时间、状态的视觉层级
- 使用 `IconFont` 组件替换旧的图标实现
- 优化消息详情页布局:移除标题提取逻辑,仅展示“发送时间”(右上角)和完整内容,避免内容重复显示
- 增加未读消息红点提示
---
## [2026-02-12] - 修复结果页返回后表单未重置
### 修复
......
......@@ -8,7 +8,7 @@ info:
title: ''
version: 1.0.0
paths:
/:
/srv/:
get:
summary: 消息详情
deprecated: false
......@@ -41,7 +41,7 @@ paths:
in: query
description: 消息ID
required: true
example: '817677'
example: '834791'
schema:
type: string
responses:
......@@ -57,8 +57,6 @@ paths:
msg:
type: string
data:
type: array
items:
type: object
properties:
id:
......@@ -74,15 +72,20 @@ paths:
type: string
title: 状态
description: send=以发送未读取,read=已读取
pk_id:
type: integer
title: 计划书订单ID
x-apifox-orders:
- id
- note
- created_time
- status
- pk_id
required:
- note
- created_time
- status
- pk_id
required:
- code
- msg
......@@ -96,7 +99,7 @@ paths:
x-apifox-ordering: 0
security: []
x-apifox-folder: 消息
x-apifox-status: developing
x-apifox-status: testing
x-run-in-apifox: https://app.apifox.com/web/project/7792797/apis/api-413906673-run
components:
schemas: {}
......
......@@ -64,6 +64,9 @@ paths:
msg:
type: string
data:
type: object
properties:
list:
type: array
items:
type: object
......@@ -81,15 +84,28 @@ paths:
type: string
title: 状态
description: send=以发送未读取,read=已读取
pk_id:
type: integer
title: 计划书订单ID
x-apifox-orders:
- id
- note
- created_time
- status
- pk_id
required:
- note
- created_time
- status
- pk_id
total:
type: integer
x-apifox-orders:
- list
- total
required:
- list
- total
required:
- code
- msg
......@@ -103,7 +119,7 @@ paths:
x-apifox-ordering: 0
security: []
x-apifox-folder: 消息
x-apifox-status: developing
x-apifox-status: testing
x-run-in-apifox: https://app.apifox.com/web/project/7792797/apis/api-413906672-run
components:
schemas: {}
......
......@@ -13,12 +13,13 @@ const Api = {
* @returns {Promise<{
* code: number; // 状态码
* msg: string; // 消息
* data: Array<{
* data: {
id: integer; // 消息id
note: string; // 消息内容
created_time: string; // 发消息的时间
status: string; // send=以发送未读取,read=已读取
* }>;
pk_id: integer; // 计划书订单ID
* };
* }>}
*/
export const detailAPI = (params) => fn(fetch.get(Api.Detail, params));
......@@ -32,12 +33,16 @@ export const detailAPI = (params) => fn(fetch.get(Api.Detail, params));
* @returns {Promise<{
* code: number; // 状态码
* msg: string; // 消息
* data: Array<{
* data: {
list: Array<{
id: integer; // 消息id
note: string; // 消息内容
created_time: string; // 发消息的时间
status: string; // send=以发送未读取,read=已读取
* }>;
pk_id: integer; // 计划书订单ID
}>;
total: integer; //
* };
* }>}
*/
export const myListAPI = (params) => fn(fetch.get(Api.MyList, params));
......
<!--
* @Date: 2026-02-03 21:26:58
* @Date:2026-02-03 21:26:58
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2026-02-03 21:30:21
* @LastEditTime: 2026-02-12 18:24:35
* @FilePath: /manulife-weapp/src/pages/message-detail/index.vue
* @Description: 文件描述
* @Description: 消息详情页
-->
<template>
<view class="min-h-screen bg-white pb-safe">
<NavHeader title="消息详情" />
<view v-if="detail" class="p-5">
<!-- 标题 -->
<view class="text-xl font-bold text-gray-900 mb-3 leading-tight">
{{ detail.title }}
</view>
<!-- 元信息 -->
<view class="flex items-center text-xs text-gray-400 mb-6">
<text>{{ detail.create_time }}</text>
<text class="mx-2">·</text>
<text>Manulife</text>
</view>
<!-- 内容区域 -->
<view class="rich-text-content">
<rich-text :nodes="formattedContent" />
</view>
<!-- 顶部时间 -->
<view class="mt-4 text-right">
<text class="text-xs text-gray-400">{{ detail.created_time }}</text>
</view>
<!-- 关联计划书(可选) -->
<!-- <view v-if="detail.pk_id" class="mt-2 pt-4 border-t border-gray-200">
<view class="text-sm text-gray-500 mb-2">关联计划书</view>
<view class="text-xs text-gray-400">订单ID: {{ detail.pk_id }}</view>
</view> -->
</view>
<!-- 加载中 -->
......@@ -51,12 +51,15 @@ const loading = ref(true)
* @description 格式化富文本内容,处理图片宽度等问题
*/
const formattedContent = computed(() => {
if (!detail.value?.content) return ''
if (!detail.value?.note) return ''
// 简单的正则替换,确保图片宽度不超过容器
return detail.value.content.replace(
const content = detail.value.note.replace(
/<img/g,
'<img style="max-width:100%;height:auto;display:block;"'
)
return content
})
/**
......
<!--
* @Date: 2026-02-08
* @Date:2026-02-08
* @Description: 我的消息页 - 使用 LoadMoreList 组件重构版本
-->
<template>
......@@ -27,19 +27,26 @@
class="message-item bg-white rounded-xl p-4 mb-3 shadow-sm active:opacity-70 transition-opacity"
@tap="handleItemClick(item)"
>
<view class="flex justify-between items-start mb-2">
<view class="flex-1 mr-2">
<view class="text-base font-bold text-gray-900 line-clamp-1">
{{ item.title }}
<!-- 第一行:内容(带红点) -->
<view class="text-base font-bold text-gray-900 line-clamp-1 mb-3 flex items-center">
<view v-if="item.status === 'send'" class="w-2 h-2 bg-red-500 rounded-full mr-2 shrink-0"></view>
{{ getItemTitle(item.note) }}
</view>
<!-- 第二行:时间(左)与 状态(右) -->
<view class="flex justify-between items-center">
<!-- 左边:时间 -->
<text class="text-xs text-gray-400 font-medium">{{ item.created_time }}</text>
<!-- 右边:状态 -->
<view class="flex items-center">
<view v-if="item.status === 'send'" class="px-2 py-0.5 bg-red-50 text-red-500 rounded text-xs font-medium">
未读
</view>
<view v-else-if="item.status === 'read'" class="px-2 py-0.5 bg-gray-100 text-gray-400 rounded text-xs">
已读
</view>
<text class="text-xs text-gray-400 shrink-0 mt-1">
{{ item.create_time }}
</text>
</view>
<view class="text-sm text-gray-600 line-clamp-2 leading-relaxed">
{{ item.intro || item.content || '暂无简介' }}
</view>
</view>
</template>
......@@ -58,6 +65,7 @@ import { useLoad } from '@tarojs/taro'
import { useGo } from '@/hooks/useGo'
import LoadMoreList from '@/components/list/LoadMoreList'
import NavHeader from '@/components/navigation/NavHeader.vue'
import IconFont from '@/components/icons/IconFont.vue'
import { myListAPI } from '@/api/news'
import { mockMessageListAPI } from '@/utils/mockData'
......@@ -67,41 +75,52 @@ const USE_MOCK_DATA = false
const go = useGo()
/**
* 当前列表数据
* @type {Ref<Array<any>>}
*/
// 响应式状态
const currentList = ref([])
/**
* 当前页码(从0开始)
* @type {Ref<number>}
*/
const currentPage = ref(0)
/**
* 每页数量
* @type {number}
*/
const pageSize = 10
/**
* 是否还有更多数据
* @type {Ref<boolean>}
*/
const hasMore = ref(true)
const loading = ref(false)
const loadingMore = ref(false)
/**
* 首次加载状态
* @type {Ref<boolean>}
* 提取消息标题(第一行或截取)
*
* @param {string} note - 消息内容
* @returns {string} 标题
*/
const loading = ref(false)
const getItemTitle = (note) => {
if (!note) return '暂无消息内容'
// 提取第一行作为标题
const firstLine = note.split('\n')[0]
// 移除富文本标签(简单处理)
const textOnly = firstLine.replace(/<[^>]+>/g, '').trim()
// 如果第一行太长,截取前50个字符
return textOnly.length > 50 ? textOnly.substring(0, 50) + '...' : textOnly
}
/**
* 加载更多状态
* @type {Ref<boolean>}
* 提取消息预览(移除第一行后的内容)
*
* @param {string} note - 消息内容
* @returns {string} 预览内容
*/
const loadingMore = ref(false)
const getItemPreview = (note) => {
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 '' // 只有一行时不显示预览
}
/**
* 获取消息列表
......