文件
yjyf/pages/message/message.vue
linda 4734724ed2 feat: 后端补齐前端所需模块 + 后台登录页品牌化重构
后端(补齐前端已入口但无接口的模块):
- Coupon 控制器:center 领券中心 / my 我的券(未使用·已使用·已过期+计数)/ receive 领取
  含库存与过期校验、重复领取拦截、领券后自动发消息
- Message 控制器:index 列表(分类筛选)/ read 单条已读 / readAll 全部已读 / unread 角标
  支持 user 与 master 两种归属

前端(对应页面,全部接真接口):
- pages/address/list  服务地址:列表 / 新增·编辑弹层 / 设为默认 / 删除
- pages/coupon/coupon 领券中心 + 我的券(双 Tab + 状态筛选 + 计数)
- pages/message/message 消息中心:分类 / 未读圆点 / 点开自动已读 / 全部已读 / 跳订单
- mine.vue 三个入口(地址·优惠券·消息)由「开发中」改为真实路由
- merchant/workbench 服务地址入口接真实路由
- 首页 TabBar「消息」接入消息中心
- api.js 新增 coupon/message 共 7 个接口

后台登录页(UI 与前端主色调统一):
- 左侧橙金渐变品牌区:logo 徽标 + 「优匠优服」立体字 + slogan + 460万+/99.9%/1762万 平台实力 + 保障条
- 右侧白色登录卡:橙色渐变按钮、圆角输入框、错误提示条
- 保留 FastAdmin 全部挂钩(token/验证码/keeplogin/@AdminLoginFormBegin 等 14 项)

验证:5 套用例 178 项断言全通过(47+65+27+24+15),配置自检 8/8
2026-10-28 16:51:45 +08:00

94 行
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>
</view>
</template>
<script setup>
import { ref } from '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: 20rpx; color: #B5B5B5; }
.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>