文件
yjyf/yjyf-app/pages/message/message.vue
YuanWen 7ab7429dee feat: 新增统一底部导航与全局样式系统,优化交互体验
新增全局 YjyfTabBar 组件,替换各页面自定义导航,实现一致的 tab 切换逻辑与图标样式
新增全局设计令牌与 SCSS 变量系统,统一色彩、间距、字阶、圆角与投影规范
新增 POST 请求防并发锁,避免重复提交
重构多个页面,添加骨架屏、空状态引导、点击反馈类,修复硬编码样式与假数据
删除废弃的后台入口文件与 nginx 配置,清理冗余代码
2026-11-02 14:00:19 +08:00

96 行
3.5 KiB
Vue

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<template>
<view class="page">
<view class="head">
<view class="cats">
<view v-for="c in cats" :key="c.key" class="cat" :class="{ on: category === c.key }" @tap="switchCat(c.key)">{{ c.name }}</view>
</view>
<text class="read-all" @tap="readAll">全部已读</text>
</view>
<view class="list">
<view class="msg" :class="{ unread: !m.is_read }" v-for="m in list" :key="m.id" @tap="open(m)">
<view class="msg-top">
<view class="dot" v-if="!m.is_read"></view>
<text class="title">{{ m.title }}</text>
<text class="time">{{ m.time_text }}</text>
</view>
<text class="content">{{ m.content }}</text>
<text class="go" v-if="m.order_id">查看订单 ›</text>
</view>
<view class="empty" v-if="!loading && !list.length">暂无消息</view>
</view>
<YjyfTabBar :current="2" />
</view>
</template>
<script setup>
import { ref } from 'vue';
import YjyfTabBar from '@/components/YjyfTabBar.vue';
import { onShow, onPullDownRefresh } from '@dcloudio/uni-app';
import api from '@/utils/api.js';
import { isLogin, toLogin } from '@/utils/request.js';
const list = ref([]);
const loading = ref(false);
const category = ref('all');
const cats = [
{ key: 'all', name: '全部' },
{ key: 'order', name: '订单' },
{ key: 'system', name: '系统' },
{ key: 'remind', name: '提醒' }
];
async function load() {
if (!isLogin()) { toLogin(); return; }
loading.value = true;
try {
const res = await api.messageList({ category: category.value, limit: 30 });
list.value = res.list || [];
} catch (e) {
} finally {
loading.value = false;
}
}
function switchCat(k) { category.value = k; load(); }
async function open(m) {
if (!m.is_read) {
try { await api.messageRead({ id: m.id }); m.is_read = 1; } catch (e) {}
}
if (m.order_id) {
uni.navigateTo({ url: '/pages/order/detail?id=' + m.order_id });
}
}
async function readAll() {
try {
const res = await api.messageReadAll({});
uni.showToast({ title: '已全部标记已读(' + res.count + ' 条)', icon: 'none' });
load();
} catch (e) {}
}
onShow(() => load());
onPullDownRefresh(() => { load().then(() => uni.stopPullDownRefresh()); });
</script>
<style scoped>
.page { min-height: 100vh; background: #F5F6F8; padding-bottom: 40rpx; }
.head { display: flex; align-items: center; background: #fff; padding: 20rpx 24rpx; box-shadow: 0 4rpx 12rpx rgba(0,0,0,.03); }
.cats { flex: 1; display: flex; }
.cat { margin-right: 14rpx; padding: 0 22rpx; line-height: 54rpx; border-radius: 27rpx; background: #F5F5F5; font-size: 24rpx; color: #666; }
.cat.on { background: #FFF3E6; color: #E36B0C; font-weight: 600; }
.read-all { font-size: 24rpx; color: #F0710D; }
.list { padding: 22rpx 28rpx; }
.msg { background: #fff; border-radius: 20rpx; padding: 22rpx 24rpx; margin-bottom: 18rpx; box-shadow: 0 6rpx 20rpx rgba(240,129,31,.06); }
.msg.unread { border-left: 6rpx solid #F0710D; }
.msg-top { display: flex; align-items: center; }
.dot { width: 12rpx; height: 12rpx; border-radius: 50%; background: #F0710D; margin-right: 10rpx; }
.title { flex: 1; min-width: 0; font-size: 28rpx; font-weight: 600; color: #1F1F1F; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.time { flex-shrink: 0; margin-left: 12rpx; font-size: 22rpx; color: #AAAAAA; }
.content { display: block; margin-top: 10rpx; font-size: 24rpx; color: #666; line-height: 34rpx; }
.go { display: block; margin-top: 10rpx; font-size: 22rpx; color: #4A7CFF; }
.empty { padding: 110rpx 0; text-align: center; font-size: 24rpx; color: #9A9A9A; }
</style>