From 5106fe101c1ed01112daeba85bfb3f8f68680f7c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com>
Date: Tue, 14 Jul 2026 20:58:40 +0800
Subject: [PATCH] =?UTF-8?q?feat(shopDashboard):=20=E4=B8=BA=20Dashboard=20?=
=?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B0=E8=AE=A2=E5=8D=95=E5=A3=B0=E9=9F=B3?=
=?UTF-8?q?=E6=8F=90=E9=86=92=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 将 useOrderNotify 改造为实例安全的 Composable,支持多个页面独立调用
- 在 shop/dashboard 和 cms/dashboard 页面添加新订单提醒开关和测试按钮
- 新订单提醒触发时自动刷新 Dashboard 数据,提升数据同步性
- 新订单提醒包括叮声和语音播报,用户交互后自动解锁音频播放
- cms/dashboard 概况卡片标题添加提醒控件,shop/dashboard 欢迎横幅右侧添加提醒栏
- 提取 cms/dashboard loadData 函数实现复用,统一数据加载逻辑
- 优化组件状态管理,防止多个实例间状态冲突,提升稳定性和可维护性
---
.workbuddy/memory/2026-07-14.md | 107 +----------
src/views/cms/dashboard/index.vue | 59 +++++-
src/views/shop/dashboard/index.vue | 61 +++++-
src/views/shop/shopOrder/useOrderNotify.ts | 209 ++++++++-------------
4 files changed, 192 insertions(+), 244 deletions(-)
diff --git a/.workbuddy/memory/2026-07-14.md b/.workbuddy/memory/2026-07-14.md
index b770b64..a33196d 100644
--- a/.workbuddy/memory/2026-07-14.md
+++ b/.workbuddy/memory/2026-07-14.md
@@ -1,103 +1,8 @@
-## 2026-07-14 修复 Dashboard 统计数据问题
+# 2026-07-14
-### 问题描述
-用户反馈 `/shop/dashboard` 页面所有统计数据都显示为 0,包括用户总数、订单总数、总营业额、运行天数、今日数据概况等。
+## 为 Dashboard 页面添加新订单声音提醒
-### 修复内容
-
-#### 1. 修复 `src/store/modules/statistics.ts`
-- 添加了 `todaySales`、`todayOrders`、`todayUsers` 从 `cmsStatistics` 表数据中提取的逻辑
-- 在 `fetchStatistics` 中传入 `page: 1, limit: 1` 参数,减少不必要的数据传输
-- 确保在没有 `cmsStatistics` 记录时,仍然能使用基础统计数据(用户总数、订单总数、总销售额)
-
-#### 2. 修复 `src/views/shop/dashboard/index.vue`
-- 将 `coreStats`、`todayStats`、`todoItems` 从 `reactive` 改为 `computed`,确保数据响应式更新
-- 修复了今日数据使用错误来源的问题:
- - 之前:`todayStats.salesAmount = totalSales.value`(使用总销售额作为今日销售额)
- - 现在:`todayStats.salesAmount = todaySales.value`(使用真正的今日销售额)
-- 添加了从 API 获取待处理事项数据的逻辑:
- - 待发货订单:`statusFilter: 1` 查询
- - 退款/售后:`statusFilter: 6` 查询
- - 今日订单数:通过 `createTimeStart` 和 `createTimeEnd` 查询
-
-### 注意事项
-如果后端 `cmsStatistics` 表中没有今日数据(todaySales、todayOrders、todayUsers),今日数据仍会显示为 0。建议:
-1. 检查后端是否有定时任务更新 `cmsStatistics` 表
-2. 或手动触发统计数据更新
-3. 检查浏览器控制台是否有 API 调用失败的错误日志
-
-## 2026-07-14 Dashboard 标题改用 tenantName + 订单提醒同步刷新
-
-### Dashboard 标题
-- `src/views/shop/dashboard/index.vue` 欢迎横幅标题从 `siteStore.appName` 改为 `userStore.info?.tenantName`,显示当前登录用户所属租户名称。
-
-### 订单新订单语音提醒同步刷新
-- `src/views/shop/shopOrder/useOrderNotify.ts` 增加 `onNewOrder` 回调参数,检测到新订单触发提醒(叮声+语音)时同时调用回调。
-- `src/views/shop/shopOrder/index.vue` 调用 `useOrderNotify({ onNewOrder: () => reload() })`,使新订单提醒时自动刷新表格数据,保持数据同步。
-
-## 2026-07-14 实时统计 Dashboard 今日数据
-
-### 问题
-用户再次反馈 `/shop/dashboard` 的「今日数据概况」与「待处理事项」全部显示为 0,且已确认存在今日订单/用户数据。根本原因是 `cmsStatistics` 统计表未写入今日数据,而前端仍依赖该表读取 todaySales/todayOrders/todayUsers;另外 dashboard 中直接按日期查询时使用了 `YYYY-MM-DD` 格式,缺少时间部分,导致时间范围不匹配。
-
-### 修复
-- `src/store/modules/statistics.ts`:
- - 引入 `dayjs` 与 `listShopOrder`。
- - 在 `fetchStatistics` 中实时调用 `listShopOrder({ createTimeStart, createTimeEnd })` 获取今日订单列表,直接计算 `todayOrders`、`todaySales`(仅已付款订单)、`couponUsedCount`。
- - 调用 `pageUsers({ createTimeStart, createTimeEnd })` 获取 `todayUsers`。
- - 将今日数据同步写入 `cmsStatistics` 表(若存在记录),同时新增 `couponUsedCount` store 状态与 getter。
-- `src/views/shop/dashboard/index.vue`:
- - 移除原来使用 `createTimeStart/End: today`(仅日期)查询今日订单并作为优惠券使用数的占位逻辑。
- - `couponUsedCount` 改为从 `statisticsStore.couponUsedCount` 读取。
- - 今日销售额使用 `formatMoney` 保留两位小数显示。
-
-### 验证
-- `pnpm run build` 成功。
-- `vue-tsc --noEmit` 在改动文件中未引入新错误。
-
-### 备注
-- 待发货/退款仍使用 `statusFilter=1` 与 `statusFilter=6`;若后续出现货到付款订单未计入待发货,需再检查订单 `payStatus` 在后端是否被正确标记为已付款。
-
-## 2026-07-14 订单列表商品图片接入 OSS 压缩
-
-### 改动内容
-- 参考 `/Users/gxwebsoft/VUE/xinlong-shop-taro/src/utils/image.ts`,在管理后台新增 `src/utils/image.ts`:
- - `ensureFullUrl(url)`:补全 OSS 域名为完整 URL
- - `getCompressedImageUrl(url, options?)`:拼接 `x-oss-process=image/resize,w_${width}/quality,Q_${quality}` 压缩参数
-- `src/views/shop/shopOrder/index.vue`:
- - 引入 `getCompressedImageUrl`
- - 订单列表商品图片列 `` 改为 ``
-
-### 待办
-- 用户提到后端也需要此方法,但当前工作区只有前端代码,后端实现需在后端项目补充。
-
-## 2026-07-14 商城设置 Logo 改为直传
-
-### 修改文件
-- `src/views/shop/shopSetting/components/basic.vue`
-
-### 修改内容
-- 将商城 Logo 上传方式从 `SelectFile` 图片库选择改为 `a-upload` + `uploadOss` 直接上传,与商品编辑弹窗的商品图片上传方式保持一致。
-- 已上传图片使用 `a-image` 预览,下方提供"上传"按钮覆盖替换。
-- 删除不再使用的 `SelectFile` 导入、`logoList` 变量、`chooseImage`/`onDeleteImage` 回调。
-- 使用 `ele-admin-pro` 的 `messageLoading` 保持上传加载提示与商品编辑弹窗一致。
-
-## 2026-07-14 商品列表增加三价格展示
-
-### 改动文件
-- `src/views/shop/shopGoods/index.vue`
-
-### 列表页列配置
-- 原来只显示一列「价格」(`price`)
-- 新增「市场价」列 (`salePrice`),数据为空时显示 `-`
-- 新增「会员价」列 (`dealerPrice`),数据为空时显示 `-`
-- 三列均设置 `width: 110`、`align: 'center'`、`customRender` 带 `¥` 前缀
-
-### 导出功能同步更新
-- 导出表头增加「市场价」「会员价」两列
-- 数据行对应增加 `goods.salePrice` 和 `goods.dealerPrice` 输出
-- 列宽配置同步增加两列 `{ wch: 12 }`
-
-### 备注
-- 编辑表单 `shopGoodsEdit.vue` 已支持三个价格编辑(价格/市场价/会员价),无需修改
-- 数据模型字段映射:价格=price, 市场价=salePrice, 会员价=dealerPrice
+- 将 `src/views/shop/shopOrder/useOrderNotify.ts` 改造为实例安全的 Composable:模块级状态(enabled/polling/timerId/lastOrderId/initialized/callback)移入函数作用域,AudioContext 和音频解锁监听器保持模块级共享。每个页面调用可创建独立实例,互不冲突。
+- 在 `src/views/shop/dashboard/index.vue` 的欢迎横幅右侧添加新订单提醒开关栏(开关 + 测试按钮),检测到新订单后自动调用 loadData() 刷新 Dashboard 数据。
+- 在 `src/views/cms/dashboard/index.vue` 的概况卡片标题栏添加新订单提醒控件,同样检测到新订单后刷新数据。
+- 提取了 CMS Dashboard 的 loadData 函数使其可复用。
diff --git a/src/views/cms/dashboard/index.vue b/src/views/cms/dashboard/index.vue
index 3fc5b8f..acf8f0e 100644
--- a/src/views/cms/dashboard/index.vue
+++ b/src/views/cms/dashboard/index.vue
@@ -3,7 +3,21 @@
-
+
+
+
+ 概况
+
+
+
+
import { ref, onMounted, onUnmounted, computed } from 'vue';
+ import { useOrderNotify } from '@/views/shop/shopOrder/useOrderNotify';
import {
UserOutlined,
CalendarOutlined,
@@ -192,7 +207,8 @@
SettingOutlined,
AccountBookOutlined,
FileTextOutlined,
- MoneyCollectOutlined
+ MoneyCollectOutlined,
+ InfoCircleOutlined
} from '@ant-design/icons-vue';
import { openNew } from '@/utils/common';
import { useSiteStore } from '@/store/modules/site';
@@ -230,19 +246,27 @@
// 加载状态
const loading = computed(() => siteLoading.value || statisticsLoading.value);
- onMounted(async () => {
- // 加载网站信息和统计数据
+ // 加载数据
+ const loadData = async () => {
try {
await Promise.all([
siteStore.fetchSiteInfo(),
statisticsStore.fetchStatistics()
]);
-
- // 开始自动刷新统计数据(每5分钟)
- statisticsStore.startAutoRefresh();
} catch (error) {
console.error('加载数据失败:', error);
}
+ };
+
+ // 新订单声音提醒
+ const { enabled: notifyEnabled, toggle: onNotifyToggle, testNotify: onTestNotify } = useOrderNotify({
+ onNewOrder: () => loadData()
+ });
+
+ onMounted(async () => {
+ await loadData();
+ // 开始自动刷新统计数据(每5分钟)
+ statisticsStore.startAutoRefresh();
});
onUnmounted(() => {
@@ -256,6 +280,27 @@
margin-bottom: 8px;
}
+ /* 新订单提醒栏(概况卡片标题中) */
+ .order-notify-bar {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 2px 12px;
+ background: #f0fdf4;
+ border: 1px solid #bbf7d0;
+ border-radius: 6px;
+ }
+ .order-notify-label {
+ font-size: 13px;
+ color: #166534;
+ white-space: nowrap;
+ }
+ .order-notify-icon {
+ color: #16a34a;
+ font-size: 14px;
+ cursor: help;
+ }
+
.stat-card {
text-align: center;
margin-bottom: 16px;
diff --git a/src/views/shop/dashboard/index.vue b/src/views/shop/dashboard/index.vue
index 51f232d..3c5a5b3 100644
--- a/src/views/shop/dashboard/index.vue
+++ b/src/views/shop/dashboard/index.vue
@@ -7,13 +7,23 @@
欢迎回来,管理员,今日数据已更新
-
- {{ siteStore.statusText || '正常' }}
-
-
- 刷新数据
-
-
+
+
+
+ {{ siteStore.statusText || '正常' }}
+
+
+ 刷新数据
+
+
+
@@ -207,6 +217,7 @@