# 2026-07-15

## 修复 shopOrder 页面默认待发货tab数据不正确

- 根因：`activeKey` 默认为 `'undelivered'`，但 `datasource` 函数只设了 `where.type = 0`，没有设 `statusFilter`。`statusFilter` 只在用户点击 tab 触发 `onTabs` 时才设置。所以页面初次加载时查的是全部订单而非待发货订单。
- 修复：提取 `getStatusFilterByTab(key)` 公共映射函数，在 `datasource` 中当 `where.statusFilter` 未设置时从 `activeKey` 自动推导。`onTabs` 也简化为复用同一函数。
- 文件：`src/views/shop/shopOrder/index.vue`

## Dashboard 订单总数点击跳转支持指定 tab

- Dashboard 中"订单总数"/"总营业额"跳转链接改为 `/shop/shopOrder?tab=all`，"待发货订单"改为 `?tab=undelivered`，"退款申请"改为 `?tab=refunded`。
- shopOrder 页面读取 `route.query.tab` 初始化 `activeKey`，无效值回退到 `'undelivered'`。
- 文件：`src/views/shop/dashboard/index.vue`、`src/views/shop/shopOrder/index.vue`

## Dashboard 待处理事项新增"待付款订单"

- 在待发货订单上方新增"待付款订单"统计项，使用 `statusFilter=0` 查询，点击跳转 `/shop/shopOrder?tab=unpaid`。
- shopOrder 页面取消注释"待付款"tab，`validTabs` 加入 `unpaid`。
- 新增 `dot-gold` 样式。
- 文件：`src/views/shop/dashboard/index.vue`、`src/views/shop/shopOrder/index.vue`

## Dashboard 引入 useTenantStore，创建时间读租户信息

- 引入 `useTenantStore`，`loadData` 中调用 `tenantStore.fetchTenantInfo()` 替代直接调用 `getTenantInfo()` API。
- 基本信息"创建时间"改为读取 `tenantStore.company?.createTime`。
- 运行天数也改为从 `tenantStore.company?.createTime` 计算，移除独立的 `tenantCreateTime` ref。
- 文件：`src/views/shop/dashboard/index.vue`

## Dashboard 欢迎横幅新增商城Logo

- 通过 `getShopSettingCategoryValues('basic')` 获取商城设置，读取 `shopLogo` 字段。
- 使用 `getCompressedImageUrl(shopLogo, { width: 200, quality: 90 })` 压缩图片。
- 在 welcome-banner 左侧用 `a-avatar` (64px, square) 展示，无 Logo 时不显示。
- 文件：`src/views/shop/dashboard/index.vue`

## 新增 useAppSubscriptionStore（websopy 应用订阅特殊接口）

- 新增 `src/api/app/appSubscription/model.ts`：AppSubscription 实体及参数/返回类型，对照后端 `com.gxwebsoft.app.entity.AppSubscription`。
- 新增 `src/api/app/appSubscription/index.ts`：封装 `AppSubscriptionController` 全部 14 个接口。
  - 特殊接口域名 `https://websopy-api.websoft.top/api`（与项目主 API 域名不同），复用 `@/utils/request`（共享登录态 token、401 处理），传绝对 URL。
  - 后端无 context-path；baseURL=`https://websopy-api.websoft.top/api`，接口路径用 `/app/subscription/xxx`。
  - 后端 `BaseController` 成功 code=0；`success(IPage)` 转成 `PageResult{list,count}`，与项目 `@/api` 的 PageResult 结构一致。
- 新增 `src/store/modules/appSubscription.ts`：`useAppSubscriptionStore`（Pinia Options API 风格，对齐 site.ts/statistics.ts），聚合列表/详情/支付状态/订阅管理方法。列表/详情缓存5分钟；`checkStatus`/`checkPurchased` 实时请求；订阅/支付/管理类操作成功后调 `invalidateCache()` 失效缓存。

## 确认线下收款新增上传凭证功能

- 背景：原"确认线下收款"用 `Modal.confirm` + `createVNode` 动态拼一个 input，只有备注，没有上传凭证。用户需要加凭证上传。
- 字段决策：新增 `paymentVoucher?: string` 字段（不复用 comments/merchantRemarks，因为凭证是图片URL非文本）。顺带修复 `buyerRemarks`/`merchantRemarks` 类型 bug（`undefined` → `string?`）。
- 重构为独立组件 `src/views/shop/shopOrder/components/OfflinePaymentModal.vue`：
  - 用 `<a-modal>` + `<a-form>` + `<a-upload list-type="picture-card">` 单张图片上传。
  - 上传走 `uploadOss`（`src/api/system/file`），存储返回的 `path`（与项目 `UploadCert` 组件约定一致），预览用 `getUrl(path)` 补全。
  - 凭证必填，备注可选；校验 jpg/png、≤10MB；支持点击预览大图。
- API `confirmOfflinePayment(id, remarks?, paymentVoucher?)` 新增第三参数，通过 query params 传给后端。
- `index.vue`：移除原 `Modal.confirm`/`createVNode` 逻辑，改为打开新组件（`v-model:visible` + `:data="current"` + `@done="reload"`），与 `DeliveryModal` 模式一致。
- 类型检查：新增 0 错误，顺带消掉原 `okType: 'success'` 的类型错误（antdv4 ButtonType 不含 success，新组件去掉了 ok-type）。
- 改动文件：`src/api/shop/shopOrder/model/index.ts`、`src/api/shop/shopOrder/index.ts`、`src/views/shop/shopOrder/components/OfflinePaymentModal.vue`（新增）、`src/views/shop/shopOrder/index.vue`
- 后端待办（已完成）：后端项目 `/Users/gxwebsoft/JAVA/guilixu-java`（MyBatis-Plus 3.4.3.3，无 Flyway/Liquibase，DDL 手动管理，SQL 脚本放 `sql/` 目录）：
  - `ShopOrder.java` 实体新增 `paymentVoucher` 字段（payTime 之后）。
  - `ShopOrderController.confirmOfflinePayment` 新增 `@RequestParam paymentVoucher`。
  - `ShopOrderService` 接口 + `ShopOrderServiceImpl` 实现方法签名加 `paymentVoucher` 参数，lambdaUpdate 加 `.set(paymentVoucher 非空, ShopOrder::getPaymentVoucher, paymentVoucher)`。
  - DDL 脚本 `sql/shop_order_payment_voucher.sql`：`ALTER TABLE shop_order ADD COLUMN payment_voucher VARCHAR(500) NULL ... AFTER pay_time`。
  - 注意：方法签名从 2 参变 3 参，全项目仅 Controller 一处调用，无断裂。

## Dashboard 到期时间显示订阅信息 + 立即订阅/扫码支付

- 改造 `src/views/shop/dashboard/index.vue` 基本信息「到期时间」行：三态渲染（active 显示 expireTime + 已激活 tag + ≤7天到期提醒；pending 显示待支付 + 去支付；无订阅显示立即订阅）。
- **productId 关联条件**：`app_product.tenantId = userStore.info.tenantId`（非 siteInfo.appId）。通过 `pageProducts({tenantId,current:1,size:1})` 取该租户应用。
- 新增 `src/api/app/appProduct/{model.ts,index.ts}`：AppProduct 类型 + `pageProducts` 接口（GET /api/app/product/page，分页参数 current/size，注意与项目 page/limit 不同）。
- 「立即订阅」流程：选 month/year → 免费应用调 `subscribe()` 直接激活；付费应用调 `generatePayQrcode()` 生成小程序码 → Modal 展示二维码 → 每 2.5s 轮询 `checkStatus(subscriptionNo)`，paid 后关闭+刷新（最多 5 分钟）。envVersion 按 `import.meta.env.DEV` 自动判断 trial/release。
- pending 订阅「去支付」复用 `subscriptionStore.pay(id,'wechat')`（用 `'miniappQrcode' in result` 类型守卫窄化）生成小程序码，不重复创建订阅。
- 小程序端支付页 `websopy-taro/src/passport/pay/index.tsx`：扫码 scene=subscriptionNo → detail-by-no → mp-prepay → requestPayment → mp-confirm，后端写 Redis `wxpay:paid:{no}=1`，Web 端 checkStatus 据此感知。
- 移除 dashboard 不再使用的 `siteInfo` 解构（原到期时间读 `siteInfo.expirationTime`，已改为订阅 expireTime），修复 noUnusedLocals 报错。

## 修复后端 generatePayQrcode 报错 "Field 'price_type' doesn't have a default value"

- 现象：dashboard 点「立即订阅」付费应用调 `generatePayQrcode` 时，后端 insert app_subscription 报 `price_type` 无默认值。
- 根因：后端 `AppSubscriptionController.generatePayQrcode`（websopy-java）创建订阅时漏了 `setPriceType()`，而 DB `price_type` 为 NOT NULL 无默认值。对比 `subscribe` 方法有 `setPriceType`。
- 参考 `websopy-pc/app/pages/console/pay/[subscriptionNo].vue`：它用 `subscribe` 创建订阅 + `pay(id,'wechat')` 生成二维码（两步），避开了 `generatePayQrcode`，所以没遇到此 bug。
- 修复（后端 `AppSubscriptionController.java` generatePayQrcode 方法）：补全 `setPriceType(product.getPriceType())` + `setOriginalPrice`/`setPayStatus(0)`/`setTenantId`，对齐 subscribe。**前端无需改动**，重启后端即可。
- 注意：`subscribe` 价格计算用 `price/100`（当分转元），`generatePayQrcode` 直接用 `price`（当元），两者不一致；schema 标注 price 为「元」，故 `generatePayQrcode` 价格逻辑更合理，保留不动。

## 修复价格多了100倍（product.price 实际单位是分）

- 用户反馈：`generatePayQrcode` 算出的金额多了100倍。确认 `product.price` 实际存的是**分**（非 schema 标注的元），故 `subscribe` 的 `/100` 是对的，`generatePayQrcode` 直接用 price 是错的。
- 后端 `AppSubscriptionController.generatePayQrcode` 价格计算改为 `price/100` 转元（对齐 subscribe），年付按10个月（*10，对齐 subscribe 年付优惠），季付*3，月付*1。
- 前端 `dashboard/index.vue` 参考价同步修正：`monthPrice = price/100`，`yearPrice = monthPrice*10`（原为 price 直接 + *12）。
- 结论：product.price 实际单位是**分**，所有价格展示/计算都需 /100 转元。
