fix(shop): 修正订阅流程及产品价格单位处理
- 后端 generatePayQrcode 价格计算改为 price/100 转元,年付按 10 个月计价 - 前端 dashboard 订阅价格同步调整,保持与后端一致的单位换算 - 解决 generatePayQrcode price_type 参数无生效导致的报错问题 - confirmSubscribe 改用 subscribe + pay 两步流程,规避后端未重启的问题 - 移除 confirmSubscribe 中的 isFreeProduct 分支,改用订阅状态判断 - 订阅信息加载策略调整,固定使用 productId=65 查询产品详情 - 保证前端代码通过 vue-tsc 校验,未引入新 TS 错误
This commit is contained in:
@@ -85,3 +85,24 @@
|
|||||||
- 后端 `AppSubscriptionController.generatePayQrcode` 价格计算改为 `price/100` 转元(对齐 subscribe),年付按10个月(*10,对齐 subscribe 年付优惠),季付*3,月付*1。
|
- 后端 `AppSubscriptionController.generatePayQrcode` 价格计算改为 `price/100` 转元(对齐 subscribe),年付按10个月(*10,对齐 subscribe 年付优惠),季付*3,月付*1。
|
||||||
- 前端 `dashboard/index.vue` 参考价同步修正:`monthPrice = price/100`,`yearPrice = monthPrice*10`(原为 price 直接 + *12)。
|
- 前端 `dashboard/index.vue` 参考价同步修正:`monthPrice = price/100`,`yearPrice = monthPrice*10`(原为 price 直接 + *12)。
|
||||||
- 结论:product.price 实际单位是**分**,所有价格展示/计算都需 /100 转元。
|
- 结论:product.price 实际单位是**分**,所有价格展示/计算都需 /100 转元。
|
||||||
|
|
||||||
|
## 改用 subscribe+pay 避开 generatePayQrcode 的 price_type 报错
|
||||||
|
|
||||||
|
- 现象:用户反馈 `generatePayQrcode` 仍报 `price_type` 无默认值(报错 SQL 字段集是修复前的,说明后端未重启/未重编译,`setPriceType` 修复未生效)。
|
||||||
|
- 关键认知:`generatePayQrcode` 后端**不接收 priceType 参数**(从 `product.getPriceType()` 取),所以前端传 priceType 给它也没用,无法绕过。
|
||||||
|
- 修复(前端方案,不依赖后端重启):dashboard `confirmSubscribe` 改用 `subscribe` + `pay` 两步(参考 websopy-pc 的 `pay/[subscriptionNo].vue` 模式):
|
||||||
|
- `subscribe` 创建订阅(后端有 `setPriceType`,不报错;价格 `/100` 正确)→ 免费 `status=active` 直接成功
|
||||||
|
- 付费 `status=pending` → `pay(subscriptionId,'wechat')` 生成小程序码 → Modal 展示 + 轮询 `checkStatus`
|
||||||
|
- 移除 `confirmSubscribe` 里的 `isFreeProduct` 分支(改用 `subResult.status` 判断);`isFreeProduct` 仍用于订阅 Modal 的免费提示。
|
||||||
|
- vue-tsc 验证 dashboard 零 error TS(总错误 1778 不变)。
|
||||||
|
- 后端 `generatePayQrcode` 的 `setPriceType` 修复仍保留(重启后端后该接口也能用),但前端已不依赖它。
|
||||||
|
|
||||||
|
## 订阅 productId 改为固定 65(小程序商城)
|
||||||
|
|
||||||
|
- 需求:dashboard 立即订阅请求的 productId 从动态(按 `tenantId` 查 `app_product`)改为写死 `65`。
|
||||||
|
- 改动 `src/views/shop/dashboard/index.vue`:
|
||||||
|
- imports:`pageProducts` → `getProductDetail`。
|
||||||
|
- `loadSubscriptionInfo`:移除 `userStore.info.tenantId` 判断和 `pageProducts({tenantId,current:1,size:1})` 调用,改为 `getProductDetail(65)` 查固定产品详情;定义 `FIXED_PRODUCT_ID = 65` 常量,订阅列表过滤和 `currentProduct.productId` 统一使用该常量。
|
||||||
|
- `confirmSubscribe` 无需改动(用 `currentProduct.productId`,已自动是 65)。
|
||||||
|
- `getProductDetail(65)` 返回的 product 含 name/priceType/price,前端参考价 `monthPrice = price/100`、`yearPrice = monthPrice*10` 仍适用。
|
||||||
|
- vue-tsc 验证 dashboard 零 error TS(总错误 1778 不变)。
|
||||||
|
|||||||
@@ -348,7 +348,7 @@ import { getShopSettingCategoryValues } from '@/api/shop/shopSetting';
|
|||||||
import { getCompressedImageUrl } from '@/utils/image';
|
import { getCompressedImageUrl } from '@/utils/image';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { removeSiteInfoCache } from '@/api/cms/cmsWebsite';
|
import { removeSiteInfoCache } from '@/api/cms/cmsWebsite';
|
||||||
import { pageProducts } from '@/api/app/appProduct';
|
import { getProductDetail } from '@/api/app/appProduct';
|
||||||
import type { AppProduct } from '@/api/app/appProduct/model';
|
import type { AppProduct } from '@/api/app/appProduct/model';
|
||||||
import type { AppSubscription } from '@/api/app/appSubscription/model';
|
import type { AppSubscription } from '@/api/app/appSubscription/model';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
@@ -430,22 +430,14 @@ const formatDateTime = (dt?: string) => {
|
|||||||
|
|
||||||
// 加载当前应用的订阅信息
|
// 加载当前应用的订阅信息
|
||||||
const loadSubscriptionInfo = async () => {
|
const loadSubscriptionInfo = async () => {
|
||||||
const tenantId = userStore.info?.tenantId;
|
// 固定订阅产品:productId=65(小程序商城)
|
||||||
if (!tenantId) {
|
const FIXED_PRODUCT_ID = 65;
|
||||||
console.warn('无法获取租户ID,跳过订阅信息加载');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
subscriptionLoading.value = true;
|
subscriptionLoading.value = true;
|
||||||
try {
|
try {
|
||||||
// 1. 按租户ID查询应用产品(取第一条)
|
// 1. 按固定 productId 查询产品详情
|
||||||
const productRes = await pageProducts({
|
const product = await getProductDetail(FIXED_PRODUCT_ID);
|
||||||
tenantId,
|
|
||||||
current: 1,
|
|
||||||
size: 1
|
|
||||||
});
|
|
||||||
const product = productRes.list?.[0];
|
|
||||||
if (!product || !product.productId) {
|
if (!product || !product.productId) {
|
||||||
console.warn('当前租户未找到应用产品');
|
console.warn(`未找到产品 ${FIXED_PRODUCT_ID}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentProduct.value = product;
|
currentProduct.value = product;
|
||||||
@@ -456,7 +448,7 @@ const loadSubscriptionInfo = async () => {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
const subs = (subRes.list || []).filter(
|
const subs = (subRes.list || []).filter(
|
||||||
(s) => s.productId === product.productId
|
(s) => s.productId === FIXED_PRODUCT_ID
|
||||||
);
|
);
|
||||||
// 优先取 active 中 expireTime 最新;否则取 pending 最新
|
// 优先取 active 中 expireTime 最新;否则取 pending 最新
|
||||||
const active = subs
|
const active = subs
|
||||||
|
|||||||
Reference in New Issue
Block a user