From a284a83b8660af8417f6adda50f4c3366d9a2402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Sat, 1 Aug 2026 22:10:28 +0800 Subject: [PATCH] =?UTF-8?q?feat(dashboard):=20=E6=96=B0=E5=A2=9E=E5=90=8E?= =?UTF-8?q?=E5=8F=B0=E4=BB=8A=E6=97=A5=E6=95=B0=E6=8D=AE=E6=A6=82=E5=86=B5?= =?UTF-8?q?=E5=8F=8A=E4=BB=AA=E8=A1=A8=E7=9B=98=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 shopOrderTotalAll 和 shopOrderOverview 接口,支持含未支付口径数据统计 - 新增 ShopOrderOverview 类型定义,包含今日销售额、订单数、新增用户数和优惠券使用数 - 新增后台专用仪表盘页面,展示用户数、订单数、总营业额和系统运行天数等核心数据 - 仪表盘页面实现新订单提醒功能,支持声音和语音播报 - 提供待付款、待发货订单数和退款申请动态展示,带点击跳转功能 - 新增今日数据概况区域,显示销售额、订单数、新增用户和优惠券使用情况 - 集成订阅和续费功能,支持支付二维码扫码支付及状态轮询 - 基本信息展示系统版本、授权状态以及订阅到期提醒和续费入口 - 快速入口模块方便访问订单管理、商品管理、优惠券管理等功能页 - 实现数据自动刷新机制,包括统计数据和含未支付订单的特殊统计 - 优化了界面样式和交互体验,提升了后台管理的可用性和操作便捷性 --- .workbuddy/memory/2026-07-29.md | 16 + .workbuddy/memory/2026-08-01.md | 27 + src/api/shop/shopOrder/index.ts | 46 + .../shop/shopSetting/components/order.vue | 23 +- .../special/dashboard/components/search.vue | 71 ++ .../dashboard/components/websiteEdit.vue | 408 ++++++ src/views/special/dashboard/index.vue | 1127 +++++++++++++++++ 7 files changed, 1713 insertions(+), 5 deletions(-) create mode 100644 .workbuddy/memory/2026-07-29.md create mode 100644 .workbuddy/memory/2026-08-01.md create mode 100644 src/views/special/dashboard/components/search.vue create mode 100644 src/views/special/dashboard/components/websiteEdit.vue create mode 100644 src/views/special/dashboard/index.vue diff --git a/.workbuddy/memory/2026-07-29.md b/.workbuddy/memory/2026-07-29.md new file mode 100644 index 0000000..57f4895 --- /dev/null +++ b/.workbuddy/memory/2026-07-29.md @@ -0,0 +1,16 @@ +# 2026-07-29 + +## websopy-java:cms 模块数据源路由修复(重要跨项目) +- 报错:`cms-template/current` 报 `Table 'db_websopy.cms_website' doesn't exist`;jar 为 `websopy-api-1.5.0.jar`(= `/Users/gxwebsoft/JAVA/websopy-java`)。 +- 根因:websopy-java 原只有单一数据源,dev/prod/websopy 三个 profile 全指向 `db_websopy`;而 cms 模块(23 张 cms_* 表)实际在 `modules` 库。test profile 本就指向 `modules`(印证 cms 表在 modules)。 +- 已确认方案 B(用户选「独立库 db_websopy」):多数据源,websopy 自有数据留 `db_websopy`,仅 cms 包走 `modules`。 +- 改动(在 websopy-java): + 1. `pom.xml` 增加 `com.baomidou:dynamic-datasource-spring-boot-starter:3.4.1`(匹配 MP 3.4.3.3;**不要用 3.5.x**,其对 MP 3.5,运行期可能 NoSuchMethod)。 + 2. `application-dev/prod/websopy/test.yml` 的单一 `spring.datasource` 改为 `spring.datasource.dynamic`:`primary: websopy`(test 为 `modules`),`datasource.websopy` + `datasource.modules` 双库;modules 用库 `modules`、用户 `modules`、密码 `P7KsAyDXG8YdLnkA`(取自 test profile)。 + 3. 给 `com/gxwebsoft/cms/mapper` 下全部 23 个 Mapper 接口加 `@DS("modules")`(import `com.baomidou.dynamic.datasource.annotation.DS`),仅把 cms SQL 路由到 modules,不影响 websopy 自有表。 +- 调用链:`cms-template/current` → `CmsWebsiteServiceImpl.getByTenantId()` → `baseMapper.getByTenantId()`(已注解)→ modules。✅ +- 重新构建:websopy-java 本地无 mvn/docker,需在其环境 `mvn clean package` 或重 build docker 镜像后重启容器(prod profile `SPRING_PROFILES_ACTIVE=prod`)。 +- ⚠️ 遗留问题(未处理,需确认): + - `shop/mapper/xml/ShopGoodsMapper.xml` 第 9 行 `LEFT JOIN cms_navigation`(无 schema 前缀),该 shop 查询走默认 websopy → 若 `cms_navigation` 不在 `db_websopy` 会失败;dynamic-datasource 无法跨单条 SQL 双库,需把 cms_navigation 复制到 db_websopy 或改成 `modules.cms_navigation`/`gxwebsoft_core.cms_navigation` 前缀。 + - 前提假设:所有 cms_* 表都在 modules(依 test profile 整库连 modules 推断)。若实际只有部分 cms 表在 modules,应改为只给缺失的那几张 mapper 加 @DS。 + - 跨库写事务:cms 写操作经 @DS 走 modules 独立连接,与 websopy 事务不在一个事务里,写一致性需后续评估。 diff --git a/.workbuddy/memory/2026-08-01.md b/.workbuddy/memory/2026-08-01.md new file mode 100644 index 0000000..0dcae39 --- /dev/null +++ b/.workbuddy/memory/2026-08-01.md @@ -0,0 +1,27 @@ +# 2026-08-01 工作记录 + +## 订单自动取消改造:超时时间改为后台「订单设置」驱动 + +### 需求 +自动取消未付款订单的超时时间,需由管理后台「商城设置 → 订单设置 → 未付款自动关闭」控制;设置为 0 分钟 = 不自动取消。 + +### 改造要点(已全部落地) +- 后台设置存于 `ShopSetting` 表 `setting_key='shop_order'` 的 JSON 中,字段 `orderAutoCloseMins`(前端 order.vue 已支持保存)。 +- 新增 `ShopSettingService.getOrderAutoCloseMinutes()`:参照 `getSalesAccumulateType()` 写法,从 `getCategoryValues("order")` 读 `orderAutoCloseMins`;0=禁用(合法返回);负数/读取失败兜底 30(常量 `DEFAULT_AUTO_CLOSE_MINUTES=30`)。 +- `OrderAutoCancelTask.cancelExpiredOrders()`:先读 DB,`==0` 直接 return(全局禁用,含租户特殊配置 tenantConfigs 一起跳过);`>0` 用它替换原先 YAML 的 `defaultTimeoutMinutes` 传给 `findExpiredUnpaidOrders`。 +- `OrderConfigProperties.AutoCancel.defaultTimeoutMinutes` 标 `@Deprecated`,仅作兜底。 +- 前端 `order.vue`:`orderAutoCloseMins` 的 `min` 由 1 改 0,placeholder/文案/校验提示改为「0 表示不自动取消」。 + +### 设计决策(用户已确认) +1. DB 未配置/异常兜底 = 30 分钟(与历史默认一致) +2. 现状 YAML `tenantConfigs`(租户特殊超时)保留不做改造;0=全局禁用时 tenantConfigs 也不执行 +3. 不引入缓存,定时任务每次查一次 DB(开销极小),改后台 1~5 分钟内生效 +4. 前端交互全部调整(min=0 + 文案 + 校验) + +### 涉及文件 +- JAVA: `ShopSettingService.java`、`ShopSettingServiceImpl.java`、`task/OrderAutoCancelTask.java`、`config/OrderConfigProperties.java` +- 前端: `src/views/shop/shopSetting/components/order.vue` + +### 未做 +- 未编译验证(本地无 maven/mvnw 不可用);改动为标准增量,已逐文件核对语法。 +- SQL / 取消逻辑 / 库存回退 / 优惠券退还 / 销量回滚 全部未动。 diff --git a/src/api/shop/shopOrder/index.ts b/src/api/shop/shopOrder/index.ts index 0bd2ab3..6ec951a 100644 --- a/src/api/shop/shopOrder/index.ts +++ b/src/api/shop/shopOrder/index.ts @@ -173,3 +173,49 @@ export async function confirmOfflinePayment( } return Promise.reject(new Error(res.data.message)); } + +/** + * 后台今日数据概况(含未支付口径) + * 字段对齐后端 ShopOrderOverviewVo: + * - todaySales 今日销售额(元,含未支付,按 total_price 求和) + * - todayOrders 今日订单数(含未支付) + * - todayUsers 今日新增用户数 + * - couponUsedCount 今日使用优惠券的订单数 + */ +export interface ShopOrderOverview { + /** 今日销售额(元),含未支付,按订单面额 total_price 求和 */ + todaySales: number; + /** 今日订单数,含未支付 */ + todayOrders: number; + /** 今日新增用户数 */ + todayUsers: number; + /** 今日使用优惠券的订单数 */ + couponUsedCount: number; +} + +/** + * 统计订单总金额(含未支付,按订单面额 total_price 求和) + * 对标 /shop/shop-order/total,但不限制 pay_status,返回所有未删除订单的 total_price 之和 + */ +export async function shopOrderTotalAll() { + const res = await request.get>( + MODULES_API_URL + '/shop/shop-order/total-all' + ); + if (res.data.code === 0) { + return res.data.data ?? 0; + } + return Promise.reject(new Error(res.data.message)); +} + +/** + * 获取后台今日数据概况(含未支付口径) + */ +export async function shopOrderOverview() { + const res = await request.get>( + MODULES_API_URL + '/shop/shop-order/overview' + ); + if (res.data.code === 0 && res.data.data) { + return res.data.data; + } + return Promise.reject(new Error(res.data.message)); +} diff --git a/src/views/shop/shopSetting/components/order.vue b/src/views/shop/shopSetting/components/order.vue index 4043573..e31e70c 100644 --- a/src/views/shop/shopSetting/components/order.vue +++ b/src/views/shop/shopSetting/components/order.vue @@ -20,12 +20,12 @@ - 分钟 + 分钟(0 表示不自动取消) + + + 支付成功后累加(默认) + 下单成功后累加 + +
+ 支付累加:用户付款后才计入销量;下单累加:生成订单即计入销量(取消订单会回滚)。 +
+
保存 @@ -84,7 +93,8 @@ const { form, assignFields } = useFormData({ orderAutoCloseMins: 30, orderAutoCommentDays: 15, orderFreightFreeAmount: 0, - orderRefundEnabled: true + orderRefundEnabled: true, + salesAccumulateType: 10 }); const rules = reactive({ @@ -99,7 +109,7 @@ const rules = reactive({ orderAutoCloseMins: [ { required: true, - message: '请输入未付款自动关闭分钟数', + message: '请输入未付款自动关闭分钟数(0 表示不自动取消)', type: 'number', trigger: 'blur' } @@ -135,6 +145,9 @@ const load = async () => { if (values.orderFreightFreeAmount !== undefined) { form.orderFreightFreeAmount = Number(values.orderFreightFreeAmount); } + if (values.salesAccumulateType !== undefined) { + form.salesAccumulateType = Number(values.salesAccumulateType); + } } } catch (e: any) { // 未配置时忽略 diff --git a/src/views/special/dashboard/components/search.vue b/src/views/special/dashboard/components/search.vue new file mode 100644 index 0000000..8a76723 --- /dev/null +++ b/src/views/special/dashboard/components/search.vue @@ -0,0 +1,71 @@ + + + + diff --git a/src/views/special/dashboard/components/websiteEdit.vue b/src/views/special/dashboard/components/websiteEdit.vue new file mode 100644 index 0000000..386a863 --- /dev/null +++ b/src/views/special/dashboard/components/websiteEdit.vue @@ -0,0 +1,408 @@ + + + + diff --git a/src/views/special/dashboard/index.vue b/src/views/special/dashboard/index.vue new file mode 100644 index 0000000..5a29396 --- /dev/null +++ b/src/views/special/dashboard/index.vue @@ -0,0 +1,1127 @@ + + + + +