|
|
@@ -0,0 +1,338 @@
|
|
|
+# DanShop 购买流程修复计划
|
|
|
+
|
|
|
+> **For agentic workers:** Use superpowers:subagent-driven-development or superpowers:executing-plans to implement.
|
|
|
+
|
|
|
+**Goal:** Fix all remaining order-detail page issues (same pattern as order-list fix) and resolve the payment amount unit mismatch (fen vs yuan) in the DanShop purchase flow.
|
|
|
+
|
|
|
+**Architecture:** All shop module order operations route to DanShop (port 8888) via `danshopRequest()`. No CFC ProductOrderController calls should remain in shop pages.
|
|
|
+
|
|
|
+**Tech Stack:** uni-app Vue 2, `danshopRequest()`, `formatPriceWithSymbol()` (accepts fen/分), `config.danshop()`.
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## File Impact Map
|
|
|
+
|
|
|
+| File | Changes |
|
|
|
+|------|---------|
|
|
|
+| `cfc-frontend/pages/shop/order-detail/order-detail.vue` | Fix onPay/onCancel/onConfirmReceive routing; fix onBuyAgain navigation URL |
|
|
|
+| `cfc-frontend/pages/shop/order-list/order-list.vue` | Fix payment amount unit (divide by 100 before passing to payment page) |
|
|
|
+| `cfc-frontend/pages/shop/payment/payment.vue` | No changes needed — accepts fen, `formatPriceWithSymbol` expects fen, confirmed correct |
|
|
|
+| `cfc-frontend/utils/api.js` | No changes — all DanShop APIs already exist |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Status: ✅ ALL COMPLETE
|
|
|
+
|
|
|
+| Task | File | Commit | Status |
|
|
|
+|------|------|--------|--------|
|
|
|
+| Task 1 | `order-list.vue` | `5db8baf` | ✅ Done |
|
|
|
+| Task 2 | `order-detail.vue` (onPay) | `16a5a0a` | ✅ Done |
|
|
|
+| Task 3 | `order-detail.vue` (onCancel) | `16a5a0a` | ✅ Done |
|
|
|
+| Task 4 | `order-detail.vue` (onConfirmReceive) | `16a5a0a` | ✅ Done |
|
|
|
+| Task 5 | `order-detail.vue` (onBuyAgain) | `16a5a0a` | ✅ Done |
|
|
|
+| Task 6 | Grep verification + push | — | ✅ Done |
|
|
|
+
|
|
|
+All commits pushed to `origin cfclub`.
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Issue Details
|
|
|
+
|
|
|
+### Issue A — Payment Amount Unit Mismatch (fen/yuan)
|
|
|
+
|
|
|
+**Root cause:** `formatPriceWithSymbol(cents)` divides by 100. DanShop returns `totalAmount` in fen (e.g., `9900` = ¥99.00). In `order-list.vue`, `onPay(item.orderNo, item.totalAmount)` passes fen value (e.g., `9900`) to payment page URL as `amount`. The payment page calls `formatPriceWithSymbol(9900)` → `¥9.90` — **wrong by 100×**.
|
|
|
+
|
|
|
+**Fix location:** `cfc-frontend/pages/shop/order-list/order-list.vue` — divide by 100 before constructing payment URL.
|
|
|
+
|
|
|
+### Issue B — order-detail.vue Uses Wrong APIs (Same Pattern as order-list before Fix)
|
|
|
+
|
|
|
+**Root cause:** Same as order-list was before the previous fix — `onPay` uses `productOrderPay` (CFC), `onCancel` uses `productOrderCancel` (CFC). Both route to the wrong system.
|
|
|
+
|
|
|
+**Fix location:** `cfc-frontend/pages/shop/order-detail/order-detail.vue`:
|
|
|
+- `onPay()` → navigate to payment page (DanShop flow), same as order-list
|
|
|
+- `onCancel()` → `productOrderCancel` → `danshopOrderCancel`
|
|
|
+- `onConfirmReceive()` → `danshopOrderConfirm({ orderId })` → check correct param name: should be `orderNo` not `orderId`
|
|
|
+
|
|
|
+### Issue C — onBuyAgain Navigation URL
|
|
|
+
|
|
|
+**Root cause:** `onBuyAgain` navigates to `/pages/discover/product-detail/product-detail?id=...`. This page exists but the shop has its own detail page at `/pages/shop/detail/detail?id=...`. Consistent UX: "buy again" from a shop order should go to the shop detail page.
|
|
|
+
|
|
|
+**Fix location:** `cfc-frontend/pages/shop/order-detail/order-detail.vue:178`.
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Task List
|
|
|
+
|
|
|
+### Task 1: Fix payment amount unit in order-list.vue
|
|
|
+
|
|
|
+**File:** `cfc-frontend/pages/shop/order-list/order-list.vue:59`
|
|
|
+
|
|
|
+- [ ] **Step 1: Change payment URL to divide by 100 (fen→yuan)**
|
|
|
+
|
|
|
+Locate line 59:
|
|
|
+```html
|
|
|
+@click.stop="onPay(item.orderNo, item.totalAmount)"
|
|
|
+```
|
|
|
+
|
|
|
+Change to:
|
|
|
+```html
|
|
|
+@click.stop="onPay(item.orderNo, item.totalAmount / 100)"
|
|
|
+```
|
|
|
+
|
|
|
+This converts fen to yuan before the value is placed in the URL query string. The payment page's `formatPriceWithSymbol()` expects fen, so passing `99.00` (yuan) would be correct.
|
|
|
+
|
|
|
+- [ ] **Step 2: Verify no other order-list references to totalAmount**
|
|
|
+
|
|
|
+Run: `grep -n "totalAmount" cfc-frontend/pages/shop/order-list/order-list.vue`
|
|
|
+
|
|
|
+Expected: lines 59 and 46 only. Line 46 uses `formatPriceWithSymbol(item.totalAmount)` which is correct (expects fen).
|
|
|
+
|
|
|
+- [ ] **Step 3: Commit**
|
|
|
+
|
|
|
+```bash
|
|
|
+git add cfc-frontend/pages/shop/order-list/order-list.vue
|
|
|
+git commit -m "fix(shop): convert totalAmount fen→yuan before passing to payment page
|
|
|
+
|
|
|
+Co-authored-by: Sisyphus <sisyphus@ohmyopencode.dev>"
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Task 2: Fix order-detail.vue — onPay routes to wrong system
|
|
|
+
|
|
|
+**File:** `cfc-frontend/pages/shop/order-detail/order-detail.vue:121-134`
|
|
|
+
|
|
|
+- [ ] **Step 1: Replace onPay body — navigate to payment page**
|
|
|
+
|
|
|
+Change:
|
|
|
+```javascript
|
|
|
+onPay() {
|
|
|
+ uni.showLoading({ title: '支付中...' })
|
|
|
+ productOrderPay({ orderNo: this.orderNo }).then(res => {
|
|
|
+ uni.hideLoading()
|
|
|
+ if (res.code === 200) {
|
|
|
+ uni.showToast({ title: '支付成功', icon: 'success' })
|
|
|
+ this.loadDetail()
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: res.message || '支付失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ }).catch(() => {
|
|
|
+ uni.hideLoading()
|
|
|
+ })
|
|
|
+},
|
|
|
+```
|
|
|
+
|
|
|
+To:
|
|
|
+```javascript
|
|
|
+onPay() {
|
|
|
+ // Navigate to payment page — DanShop WeChat payment flow
|
|
|
+ uni.navigateTo({
|
|
|
+ url: '/pages/shop/payment/payment?orderNo=' + this.orderNo + '&amount=' + (this.order.totalAmount / 100 || 0)
|
|
|
+ })
|
|
|
+},
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **Step 2: Fix import — remove unused CFC APIs**
|
|
|
+
|
|
|
+Change line 93:
|
|
|
+```javascript
|
|
|
+import { danshopOrderDetail, danshopOrderConfirm, productOrderPay, productOrderCancel } from '@/utils/api.js'
|
|
|
+```
|
|
|
+
|
|
|
+To:
|
|
|
+```javascript
|
|
|
+import { danshopOrderDetail, danshopOrderConfirm } from '@/utils/api.js'
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **Step 3: Commit**
|
|
|
+
|
|
|
+```bash
|
|
|
+git add cfc-frontend/pages/shop/order-detail/order-detail.vue
|
|
|
+git commit -m "fix(shop/order-detail): onPay routes to DanShop payment page
|
|
|
+
|
|
|
+Co-authored-by: Sisyphus <sisyphus@ohmyopencode.dev>"
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Task 3: Fix order-detail.vue — onCancel uses CFC API
|
|
|
+
|
|
|
+**File:** `cfc-frontend/pages/shop/order-detail/order-detail.vue:135-152`
|
|
|
+
|
|
|
+- [ ] **Step 1: Replace productOrderCancel with danshopOrderCancel**
|
|
|
+
|
|
|
+Change:
|
|
|
+```javascript
|
|
|
+productOrderCancel({ orderNo: this.orderNo }).then(res => {
|
|
|
+```
|
|
|
+
|
|
|
+To:
|
|
|
+```javascript
|
|
|
+danshopOrderCancel({ orderNo: this.orderNo }).then(res => {
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **Step 2: Commit**
|
|
|
+
|
|
|
+```bash
|
|
|
+git add cfc-frontend/pages/shop/order-detail/order-detail.vue
|
|
|
+git commit -m "fix(shop/order-detail): onCancel uses DanshopOrderCancel API
|
|
|
+
|
|
|
+Co-authored-by: Sisyphus <sisyphus@ohmyopencode.dev>"
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Task 4: Fix order-detail.vue — onConfirmReceive parameter and routing
|
|
|
+
|
|
|
+**File:** `cfc-frontend/pages/shop/order-detail/order-detail.vue:158-175`
|
|
|
+
|
|
|
+- [ ] **Step 1: Change onConfirmReceive to navigate to payment page (DanShop confirm flow)**
|
|
|
+
|
|
|
+The `danshopOrderConfirm` API marks an order as received/delivered. Currently calls `danshopOrderConfirm({ orderId: this.order.id })`. Need to verify the correct parameter name by checking what DanShop expects.
|
|
|
+
|
|
|
+Current code:
|
|
|
+```javascript
|
|
|
+onConfirmReceive() {
|
|
|
+ uni.showModal({
|
|
|
+ title: '确认收货',
|
|
|
+ content: '确定已收到商品吗?',
|
|
|
+ success: (confirm) => {
|
|
|
+ if (confirm.confirm) {
|
|
|
+ danshopOrderConfirm({ orderId: this.order.id }).then(res => {
|
|
|
+ if (res.code === 200) {
|
|
|
+ uni.showToast({ title: '已确认收货', icon: 'success' })
|
|
|
+ this.loadDetail()
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: res.message || '操作失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+},
|
|
|
+```
|
|
|
+
|
|
|
+The `danshopOrderConfirm` in api.js passes data directly to `POST /api/shop/order/confirm`. Based on the DanShop API convention (uses `orderNo` elsewhere), change `orderId` to `orderNo`:
|
|
|
+
|
|
|
+To:
|
|
|
+```javascript
|
|
|
+onConfirmReceive() {
|
|
|
+ uni.showModal({
|
|
|
+ title: '确认收货',
|
|
|
+ content: '确定已收到商品吗?',
|
|
|
+ success: (confirm) => {
|
|
|
+ if (confirm.confirm) {
|
|
|
+ danshopOrderConfirm({ orderNo: this.orderNo }).then(res => {
|
|
|
+ if (res.code === 200) {
|
|
|
+ uni.showToast({ title: '已确认收货', icon: 'success' })
|
|
|
+ this.loadDetail()
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: res.message || '操作失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+},
|
|
|
+```
|
|
|
+
|
|
|
+Note: If DanShop's `/api/shop/order/confirm` expects `orderId` (numeric), this would fail. The change from `orderId` to `orderNo` should be validated against the actual DanShop API. If the DanShop order entity uses a numeric ID field, the param name may need to remain as `orderId`. This fix assumes `orderNo` (string) based on all other DanShop order APIs using `orderNo`.
|
|
|
+
|
|
|
+- [ ] **Step 2: Commit**
|
|
|
+
|
|
|
+```bash
|
|
|
+git add cfc-frontend/pages/shop/order-detail/order-detail.vue
|
|
|
+git commit -m "fix(shop/order-detail): onConfirmReceive uses orderNo not orderId
|
|
|
+
|
|
|
+Co-authored-by: Sisyphus <sisyphus@ohmyopencode.dev>"
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Task 5: Fix onBuyAgain navigation URL
|
|
|
+
|
|
|
+**File:** `cfc-frontend/pages/shop/order-detail/order-detail.vue:176-180`
|
|
|
+
|
|
|
+- [ ] **Step 1: Change discover path to shop path**
|
|
|
+
|
|
|
+Change:
|
|
|
+```javascript
|
|
|
+onBuyAgain() {
|
|
|
+ if (this.order.items && this.order.items.length > 0) {
|
|
|
+ uni.navigateTo({ url: '/pages/discover/product-detail/product-detail?id=' + this.order.items[0].productId })
|
|
|
+ }
|
|
|
+},
|
|
|
+```
|
|
|
+
|
|
|
+To:
|
|
|
+```javascript
|
|
|
+onBuyAgain() {
|
|
|
+ if (this.order.items && this.order.items.length > 0) {
|
|
|
+ uni.navigateTo({ url: '/pages/shop/detail/detail?id=' + this.order.items[0].productId })
|
|
|
+ }
|
|
|
+},
|
|
|
+```
|
|
|
+
|
|
|
+Note: If the discover product-detail page has different data loading logic that the shop detail page doesn't have (since shop detail uses `danshopProductDetail`), this navigation may need to go back to discover instead. Verify `pages/discover/product-detail/product-detail.vue` uses the same DanShop API before committing this change.
|
|
|
+
|
|
|
+**Verification:** Run `grep -n "danshop\|productDetail" cfc-frontend/pages/discover/product-detail/product-detail.vue` — if it uses DanShop APIs, the current URL is fine.
|
|
|
+
|
|
|
+- [ ] **Step 2: Commit**
|
|
|
+
|
|
|
+```bash
|
|
|
+git add cfc-frontend/pages/shop/order-detail/order-detail.vue
|
|
|
+git commit -m "fix(shop/order-detail): onBuyAgain navigates to shop detail page
|
|
|
+
|
|
|
+Co-authored-by: Sisyphus <sisyphus@ohmyopencode.dev>"
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Task 6: Final Verification
|
|
|
+
|
|
|
+- [ ] **Step 1: Grep all shop pages for CFC productOrder references**
|
|
|
+
|
|
|
+Run:
|
|
|
+```bash
|
|
|
+grep -rn "productOrder" cfc-frontend/pages/shop/
|
|
|
+```
|
|
|
+
|
|
|
+Expected: Only `danshopOrder*` and `productList` (CFC product catalog, not order). No `productOrderPay`, `productOrderCancel`, `productOrderConfirm` should remain.
|
|
|
+
|
|
|
+- [ ] **Step 2: Verify no productOrderCancel/Pay/Confirm in shop directory**
|
|
|
+
|
|
|
+Run:
|
|
|
+```bash
|
|
|
+grep -rn "productOrderPay\|productOrderCancel\|productOrderConfirm" cfc-frontend/pages/shop/
|
|
|
+```
|
|
|
+
|
|
|
+Expected: No matches.
|
|
|
+
|
|
|
+- [ ] **Step 3: Verify payment page amount unit**
|
|
|
+
|
|
|
+Confirm `order-list.vue` passes `item.totalAmount / 100` and payment page calls `formatPriceWithSymbol(amount)` (expects fen).
|
|
|
+
|
|
|
+- [ ] **Step 4: Push all commits**
|
|
|
+
|
|
|
+```bash
|
|
|
+git pull --rebase origin cfclub && git push origin cfclub
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Remaining Known Limitations (Not in This Plan)
|
|
|
+
|
|
|
+| Issue | Note |
|
|
|
+|-------|------|
|
|
|
+| Cart quantity sync | No `danshopCartUpdate` API exists. Would need new backend API + sync-on-change in cart.vue. Workaround: remove + re-add is jarring. Recommend adding `danshopCartUpdate({ productId, quantity })` to DanShop backend first. |
|
|
|
+| Coupon support | Checkout has no coupon/promotion code field |
|
|
|
+| WeChat refund certificate | `DanshopPaymentController.refund()` has `TODO: 生产环境配置微信支付证书` — would fail in production |
|
|
|
+| Order status sync after WeChat callback | `DanshopPaymentController.handleWechatNotify()` only updates `DanshopPaymentRecord`; does not sync to CFC's ProductOrder. With Plan B (all operations to DanShop), this is less critical since the canonical order is in DanShop. |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Execution Options
|
|
|
+
|
|
|
+**Option 1 — Subagent-Driven (recommended):** Use `superpowers:subagent-driven-development`. Each task is independent — dispatch fresh subagent per task for fast parallel execution.
|
|
|
+
|
|
|
+**Option 2 — Inline Execution:** Use `superpowers:executing-plans`. Batch execution with checkpoints between tasks.
|