后端(补齐前端已入口但无接口的模块): - 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
115 行
3.5 KiB
PHP
115 行
3.5 KiB
PHP
<?php
|
||
|
||
namespace app\api\controller;
|
||
|
||
use think\Db;
|
||
|
||
/**
|
||
* 消息中心(用户 / 师傅共用)
|
||
*/
|
||
class Message extends Base
|
||
{
|
||
/**
|
||
* 消息列表
|
||
* @ApiParams (name="type", type="string", required=false, description="user|master,默认 user")
|
||
* @ApiParams (name="category", type="string", required=false, description="all|order|system|audit|remind")
|
||
*/
|
||
public function index()
|
||
{
|
||
$type = $this->request->param('type', 'user');
|
||
$type = $type === 'master' ? 'master' : 'user';
|
||
$category = $this->request->param('category', 'all');
|
||
$page = max(1, (int)$this->request->param('page', 1));
|
||
$limit = min(50, max(1, (int)$this->request->param('limit', 20)));
|
||
|
||
$receiveId = $this->receiveId($type);
|
||
|
||
$build = function () use ($type, $receiveId, $category) {
|
||
$q = Db::name('message')->where('receive_type', $type)->where('receive_id', $receiveId);
|
||
if ($category !== 'all' && $category !== '') {
|
||
$q->where('type', $category);
|
||
}
|
||
return $q;
|
||
};
|
||
|
||
$total = $build()->count();
|
||
$list = $build()->order('id desc')->page($page, $limit)->select();
|
||
|
||
foreach ($list as &$row) {
|
||
$row['time_text'] = date('m-d H:i', (int)$row['createtime']);
|
||
$row['is_read'] = (int)$row['is_read'];
|
||
}
|
||
unset($row);
|
||
|
||
$this->success('', [
|
||
'list' => $list,
|
||
'total' => (int)$total,
|
||
'unread' => $this->unreadCount($type, $receiveId),
|
||
'page' => $page,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 标记单条已读
|
||
* @ApiMethod (POST)
|
||
*/
|
||
public function read()
|
||
{
|
||
$id = (int)$this->request->post('id');
|
||
$type = $this->request->post('type', 'user') === 'master' ? 'master' : 'user';
|
||
$receiveId = $this->receiveId($type);
|
||
|
||
$row = Db::name('message')->where('id', $id)->where('receive_type', $type)->where('receive_id', $receiveId)->find();
|
||
if (!$row) {
|
||
$this->error('消息不存在');
|
||
}
|
||
Db::name('message')->where('id', $id)->update(['is_read' => 1]);
|
||
$this->success('已读');
|
||
}
|
||
|
||
/**
|
||
* 全部标记已读
|
||
* @ApiMethod (POST)
|
||
*/
|
||
public function readAll()
|
||
{
|
||
$type = $this->request->post('type', 'user') === 'master' ? 'master' : 'user';
|
||
$receiveId = $this->receiveId($type);
|
||
$affected = Db::name('message')
|
||
->where('receive_type', $type)->where('receive_id', $receiveId)->where('is_read', 0)
|
||
->update(['is_read' => 1]);
|
||
$this->success('已全部标记为已读', ['count' => (int)$affected]);
|
||
}
|
||
|
||
/**
|
||
* 未读数(供 Tab 角标)
|
||
*/
|
||
public function unread()
|
||
{
|
||
$type = $this->request->param('type', 'user') === 'master' ? 'master' : 'user';
|
||
$this->success('', ['unread' => $this->unreadCount($type, $this->receiveId($type))]);
|
||
}
|
||
|
||
/**
|
||
* 消息归属ID:用户=uid,师傅=master.id
|
||
*/
|
||
protected function receiveId($type)
|
||
{
|
||
if ($type === 'master') {
|
||
$master = $this->masterInfo();
|
||
return $master ? (int)$master['id'] : 0;
|
||
}
|
||
return $this->uid();
|
||
}
|
||
|
||
protected function unreadCount($type, $receiveId)
|
||
{
|
||
if (!$receiveId) {
|
||
return 0;
|
||
}
|
||
return (int)Db::name('message')
|
||
->where('receive_type', $type)->where('receive_id', $receiveId)->where('is_read', 0)
|
||
->count();
|
||
}
|
||
}
|