From 54404aa48fb538bc9de42862ef7c25a7ac9f7c85 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com>
Date: Sun, 12 Apr 2026 21:57:50 +0800
Subject: [PATCH] =?UTF-8?q?feat(order):=20=E8=BF=81=E7=A7=BB=E5=92=8C?=
=?UTF-8?q?=E5=AE=8C=E5=96=84=E9=85=8D=E9=80=81=E6=96=B9=E5=BC=8F=E5=8A=9F?=
=?UTF-8?q?=E8=83=BD=EF=BC=8C=E6=94=AF=E6=8C=81=E5=85=A8=E9=93=BE=E8=B7=AF?=
=?UTF-8?q?=E5=85=A5=E5=BA=93=E4=B8=8E=E5=B1=95=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 迁移配送方式选择功能从 orderConfirm 页至 user/ticket/use 页面
- orderConfirm 页面移除配送方式相关状态、UI与校验,取消配送费计算
- user/ticket/use 页面新增配送方式UI组件,支持配送费计算、楼层选择弹窗和提交校验
- 新增录入deliveryMethod、deliveryFloor、deliveryFee字段至订单模型与后端数据库
- 骑手端订单列表新增配送方式、楼层、配送费的详细展示
- 更新环境配置接口地址到正式API,修正测试及开发环境
- 用户页底部组件UI优化,新增版权icon并重构结构样式
- 使用配送方式字段校验下单逻辑,支持编辑模式配送信息回显与费用显示
- 移除orderConfirm中配送方式相关样式和组件,实现代码回滚清理
---
.workbuddy/expert-history.json | 4 +-
.workbuddy/memory/2026-04-10.md | 17 ++
.workbuddy/memory/2026-04-12.md | 25 +++
config/env.js | 12 +-
src/api/glt/gltTicketOrder/model/index.ts | 6 +
src/pages/user/components/UserFooter.tsx | 20 ++-
src/rider/orders/index.tsx | 30 ++++
src/shop/orderConfirm/index.scss | 182 --------------------
src/shop/orderConfirm/index.tsx | 185 +-------------------
src/user/ticket/use.scss | 173 +++++++++++++++++++
src/user/ticket/use.tsx | 200 +++++++++++++++++++++-
11 files changed, 467 insertions(+), 387 deletions(-)
create mode 100644 .workbuddy/memory/2026-04-12.md
diff --git a/.workbuddy/expert-history.json b/.workbuddy/expert-history.json
index 59a066f..815131d 100644
--- a/.workbuddy/expert-history.json
+++ b/.workbuddy/expert-history.json
@@ -63,10 +63,10 @@
"profession": "高级开发工程师",
"avatarUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/avatars/02-Engineering/SeniorDeveloper/SeniorDeveloper.png",
"promptUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/experts/02-Engineering/SeniorDeveloper/SeniorDeveloper_zh.md",
- "usedAt": 1775756293122,
+ "usedAt": 1775972794982,
"industryId": "all"
}
]
},
- "lastUpdated": 1775757430292
+ "lastUpdated": 1775999935033
}
\ No newline at end of file
diff --git a/.workbuddy/memory/2026-04-10.md b/.workbuddy/memory/2026-04-10.md
index de05a05..b10f47d 100644
--- a/.workbuddy/memory/2026-04-10.md
+++ b/.workbuddy/memory/2026-04-10.md
@@ -69,6 +69,23 @@
- 订单创建接口接收并存储这两个字段
- 骑手端/后台展示配送方式和楼层信息
+## 配送方式功能迁移:orderConfirm → user/ticket/use
+
+### 原因
+配送方式选择功能从购买下单页(orderConfirm)迁移到水票核销/立即送水页面(user/ticket/use)。
+
+### 修改的文件
+1. `src/shop/orderConfirm/index.tsx` - 回滚:移除配送方式状态变量、UI、校验、楼层选择弹窗、配送费计算
+2. `src/shop/orderConfirm/index.scss` - 回滚:移除配送方式/楼层选择相关样式
+3. `src/api/glt/gltTicketOrder/model/index.ts` - GltTicketOrder 新增 deliveryMethod、deliveryFloor、deliveryFee 字段
+4. `src/user/ticket/use.tsx` - 新增:配送方式选择UI、配送费计算、楼层选择弹窗、提交校验、编辑模式回显
+5. `src/user/ticket/use.scss` - 新增:配送方式/楼层选择样式
+
+### 关键差异
+- orderConfirm 页面是付费购买,配送费加到实付金额中
+- use 页面是水票核销(不付费),配送费以"到付"形式展示在底部栏
+- use 页面同时支持新建和编辑模式,编辑时回显配送信息
+
## 微信订阅消息配置(补充)
### 需要做的配置
diff --git a/.workbuddy/memory/2026-04-12.md b/.workbuddy/memory/2026-04-12.md
new file mode 100644
index 0000000..05ccf8e
--- /dev/null
+++ b/.workbuddy/memory/2026-04-12.md
@@ -0,0 +1,25 @@
+# 2026-04-12 工作日志
+
+## 配送方式功能完善:全链路入库+展示
+
+### 问题
+配送方式(deliveryMethod)、楼层(deliveryFloor)、配送费(deliveryFee)在小程序端用户下单页面已可选择并提交,但后端数据库表没有对应字段,数据实际没有保存。骑手端和后台管理端也没有展示这些信息。
+
+### 修改的文件
+
+#### 后端(/Users/gxwebsoft/JAVA/java-10584)
+1. `src/main/java/com/gxwebsoft/glt/entity/GltTicketOrder.java` - 新增 deliveryMethod(String)、deliveryFloor(Integer)、deliveryFee(BigDecimal) 三个数据库字段
+2. `sql/glt_ticket_order_delivery_fields.sql` - 新增 ALTER TABLE SQL,给 glt_ticket_order 表添加三个字段
+
+#### 小程序端(/Users/gxwebsoft/VUE/template-10584)
+3. `src/rider/orders/index.tsx` - 骑手送水订单页面:新增配送方式中文映射函数,订单卡片中展示配送方式、楼层、配送费
+
+#### 后台管理端(/Users/gxwebsoft/VUE/mp-10584)
+4. `src/api/glt/gltTicketOrder/model/index.ts` - GltTicketOrder 接口新增 deliveryMethod、deliveryFloor、deliveryFee 字段
+5. `src/views/glt/gltTicketOrder/index.vue` - 列表页"配送信息"列中展示配送方式、楼层、配送费
+6. `src/views/glt/gltTicketOrder/components/gltTicketOrderEdit.vue` - 编辑弹窗中新增配送方式只读展示
+
+### 部署注意事项
+- **必须先执行 SQL**:`java-10584/sql/glt_ticket_order_delivery_fields.sql`
+- MyBatis-Plus 使用驼峰自动映射,`delivery_method` → `deliveryMethod`,无需修改 Mapper XML
+- 后端 save/updateById 自动包含新字段,无需修改 Controller/Service
diff --git a/config/env.js b/config/env.js
index 70a95c7..2010f0f 100644
--- a/config/env.js
+++ b/config/env.js
@@ -8,22 +8,22 @@ const CURRENT_ENV = 'production'
export const ENV_CONFIG = {
// 开发环境
development: {
- API_BASE_URL: 'https://glt-dev-api.websoft.top/api',
- SERVER_API_URL: 'https://glt-dev-server.websoft.top/api',
+ API_BASE_URL: 'https://glt-api.websoft.top/api',
+ SERVER_API_URL: 'https://glt-server.websoft.top/api',
APP_NAME: '开发环境',
DEBUG: 'true',
},
// 测试环境
test: {
- API_BASE_URL: 'https://glt-dev-api.websoft.top/api',
- SERVER_API_URL: 'https://glt-dev-server.websoft.top/api',
+ API_BASE_URL: 'https://glt-api.websoft.top/api',
+ SERVER_API_URL: 'https://glt-server.websoft.top/api',
APP_NAME: '测试环境',
DEBUG: 'true',
},
// 生产环境
production: {
- API_BASE_URL: 'https://glt-dev-api.websoft.top/api',
- SERVER_API_URL: 'https://glt-dev-server.websoft.top/api',
+ API_BASE_URL: 'https://glt-api.websoft.top/api',
+ SERVER_API_URL: 'https://glt-server.websoft.top/api',
APP_NAME: '桂乐淘',
DEBUG: 'false',
},
diff --git a/src/api/glt/gltTicketOrder/model/index.ts b/src/api/glt/gltTicketOrder/model/index.ts
index 6e4b75a..e474dfa 100644
--- a/src/api/glt/gltTicketOrder/model/index.ts
+++ b/src/api/glt/gltTicketOrder/model/index.ts
@@ -76,6 +76,12 @@ export interface GltTicketOrder {
createTime?: string;
// 修改时间
updateTime?: string;
+ // 配送方式:elevator(电梯) / stairs(步梯) / groundFloor(一楼商铺/其他)
+ deliveryMethod?: string;
+ // 楼层(步梯+送上楼时有值,从2开始)
+ deliveryFloor?: number;
+ // 配送费(步梯+送上楼时计算:数量 × (楼层-1))
+ deliveryFee?: number;
}
/**
diff --git a/src/pages/user/components/UserFooter.tsx b/src/pages/user/components/UserFooter.tsx
index ddeef68..f3d7735 100644
--- a/src/pages/user/components/UserFooter.tsx
+++ b/src/pages/user/components/UserFooter.tsx
@@ -1,9 +1,10 @@
import {loginBySms} from "@/api/passport/login";
import {useState} from "react";
import Taro from '@tarojs/taro'
+import {View,Text} from '@tarojs/components'
import {Popup} from '@nutui/nutui-react-taro'
import {UserParam} from "@/api/system/user/model";
-import {Button} from '@nutui/nutui-react-taro'
+import {Button, Image} from '@nutui/nutui-react-taro'
import {Form, Input} from '@nutui/nutui-react-taro'
import {Copyright} from "@/config/app";
const UserFooter = () => {
@@ -46,11 +47,14 @@ const UserFooter = () => {
return (
<>
-
- {/*
当前版本:{Version}
*/}
- {/*
Copyright © { new Date().getFullYear() } {Copyright}
*/}
-
{Copyright}
-
+
+ {/*当前版本:{Version}*/}
+ {/*Copyright © { new Date().getFullYear() } {Copyright}*/}
+
+
+ {Copyright}
+
+
{
labelPosition="left"
onFinish={(values) => submitByPhone(values)}
footer={
- {
-
+
}
>
{
+ if (method === 'elevator') return '电梯'
+ if (method === 'stairs') return '步梯'
+ if (method === 'groundFloor') return '一楼商铺/其他'
+ return ''
+ }
+
const getOrderStatusColor = (order: GltTicketOrder) => {
const text = getOrderStatusText(order)
if (text === '已完成') return 'text-green-600'
@@ -383,6 +391,10 @@ export default function RiderOrders() {
const pickupName = o.warehouseName || o.storeName
const pickupAddr = o.warehouseAddress || o.storeAddress
+ // 配送方式信息
+ const deliveryMethodText = getDeliveryMethodText(o.deliveryMethod)
+ const hasDeliveryInfo = !!deliveryMethodText
+
return (
@@ -418,6 +430,24 @@ export default function RiderOrders() {
¥{o.price || '-'}
+ {hasDeliveryInfo && (
+
+ 配送方式:
+
+ {deliveryMethodText}
+
+ {o.deliveryMethod === 'stairs' && o.deliveryFloor && o.deliveryFloor > 1 && (
+ ({o.deliveryFloor}楼)
+ )}
+ {o.deliveryMethod === 'stairs' && !o.deliveryFloor && (
+ (不送上楼)
+ )}
+ {!!o.deliveryFee && o.deliveryFee > 0 && (
+ 配送费 ¥{o.deliveryFee}
+ )}
+
+ )}
+
配送时间:
{o.sendTime ? dayjs(o.sendTime).format('YYYY-MM-DD HH:mm') : '-'}
diff --git a/src/shop/orderConfirm/index.scss b/src/shop/orderConfirm/index.scss
index b68ee51..d8515ac 100644
--- a/src/shop/orderConfirm/index.scss
+++ b/src/shop/orderConfirm/index.scss
@@ -40,188 +40,6 @@
}
}
-// 配送方式选择
-.delivery-method-group {
- .delivery-method-section {
- display: flex;
- flex-direction: column;
- gap: 16px;
- }
-
- .delivery-method-label {
- display: flex;
- align-items: center;
- }
-
- .delivery-method-options {
- display: flex;
- gap: 12px;
- }
-
- .delivery-method-item {
- flex: 1;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- gap: 6px;
- padding: 16px 8px;
- border-radius: 12px;
- border: 2px solid #f0f0f0;
- background: #fafafa;
- transition: all 0.2s ease;
-
- &.active {
- border-color: #07c160;
- background: rgba(7, 193, 96, 0.05);
- }
-
- &:active {
- transform: scale(0.97);
- }
- }
-
- .delivery-method-icon {
- font-size: 24px;
- }
-
- .delivery-method-text {
- font-size: 13px;
- color: #333;
- font-weight: 500;
- }
-
- .delivery-method-item.active .delivery-method-text {
- color: #07c160;
- }
-}
-
-// 是否送上楼
-.carry-upstairs-section {
- display: flex;
- flex-direction: column;
- padding: 12px 0 0;
- border-top: 1px dashed #eee;
- margin-top: 4px;
-}
-
-.carry-upstairs-options {
- display: flex;
- gap: 12px;
-}
-
-.carry-upstairs-item {
- flex: 1;
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 12px;
- border-radius: 10px;
- border: 2px solid #f0f0f0;
- background: #fafafa;
- font-size: 18px;
- color: #666;
- transition: all 0.2s ease;
-
- &.active {
- border-color: #07c160;
- background: rgba(7, 193, 96, 0.05);
- color: #07c160;
- font-weight: 500;
- }
-
- &:active {
- transform: scale(0.97);
- }
-}
-
-// 楼层选择
-.floor-select-section {
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 12px 0 0;
- border-top: 1px dashed #eee;
- margin-top: 4px;
-}
-
-.floor-select-btn {
- display: flex;
- align-items: center;
- gap: 4px;
- padding: 8px 14px;
- border-radius: 8px;
- background: #f5f5f5;
- font-size: 18px;
- transition: background 0.2s;
-
- &:active {
- background: #e8e8e8;
- }
-}
-
-.floor-fee-tip {
- margin-left: auto;
-}
-
-// 楼层选择弹窗
-.floor-picker-popup {
- height: 100%;
- display: flex;
- flex-direction: column;
-
- &__header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 16px;
- border-bottom: 1px solid #f0f0f0;
- }
-
- &__content {
- flex: 1;
- overflow-y: auto;
- padding: 16px;
- }
-
- &__footer {
- padding: 12px 16px;
- border-top: 1px solid #f0f0f0;
- text-align: center;
- background: #fafafa;
- }
-}
-
-.floor-grid {
- display: grid;
- grid-template-columns: repeat(5, 1fr);
- gap: 12px;
-}
-
-.floor-grid-item {
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 14px 0;
- border-radius: 10px;
- border: 2px solid #f0f0f0;
- background: #fff;
- font-size: 14px;
- color: #333;
- transition: all 0.2s ease;
-
- &.active {
- border-color: #07c160;
- background: rgba(7, 193, 96, 0.08);
- color: #07c160;
- font-weight: 600;
- }
-
- &:active {
- transform: scale(0.95);
- background: #f5f5f5;
- }
-}
.address-bottom-line{
width: 100%;
border-radius: 12rpx 12rpx 0 0;
diff --git a/src/shop/orderConfirm/index.tsx b/src/shop/orderConfirm/index.tsx
index cc87a16..58790d2 100644
--- a/src/shop/orderConfirm/index.tsx
+++ b/src/shop/orderConfirm/index.tsx
@@ -81,15 +81,6 @@ const OrderConfirm = () => {
const [storeLoading, setStoreLoading] = useState(false)
const [selectedStore, setSelectedStore] = useState(getSelectedStoreFromStorage())
- // 配送方式:elevator(电梯) / stairs(步梯) / groundFloor(一楼商铺/其他)
- const [deliveryMethod, setDeliveryMethod] = useState('')
- // 步梯是否需要送上楼(null=未选择)
- const [needCarryUpstairs, setNeedCarryUpstairs] = useState(null)
- // 楼层(从2开始,需要送上楼时选择)
- const [deliveryFloor, setDeliveryFloor] = useState(2)
- // 楼层选择弹窗
- const [floorPickerVisible, setFloorPickerVisible] = useState(false)
-
const router = Taro.getCurrentInstance().router;
const params = router?.params || ({} as Record)
const goodsIdParam = params?.goodsId
@@ -222,20 +213,11 @@ const OrderConfirm = () => {
return calculateCouponDiscount(selectedCoupon, total)
}
- // 计算配送费:每桶每层1元,第1层不收费
- const getDeliveryFee = () => {
- // 仅步梯 + 需要送上楼 时才有配送费
- if (deliveryMethod !== 'stairs' || !needCarryUpstairs) return 0
- if (deliveryFloor <= 1) return 0
- return quantity * (deliveryFloor - 1)
- }
-
// 计算实付金额
const getFinalPrice = () => {
const total = getGoodsTotal()
const discount = getCouponDiscount()
- const deliveryFee = getDeliveryFee()
- return Math.max(0, total - discount + deliveryFee)
+ return Math.max(0, total - discount)
}
@@ -499,24 +481,6 @@ const OrderConfirm = () => {
return;
}
- // 配送方式校验(仅送货上门模式需要选择)
- if (goods.deliveryMode !== 1 && !deliveryMethod) {
- Taro.showToast({
- title: '请选择配送方式',
- icon: 'error'
- })
- return;
- }
-
- // 步梯场景:必须选择是否送上楼
- if (deliveryMethod === 'stairs' && needCarryUpstairs === null) {
- Taro.showToast({
- title: '请选择是否需要送上楼',
- icon: 'error'
- })
- return;
- }
-
if (!payment) {
Taro.showToast({
title: '请选择支付方式',
@@ -591,9 +555,7 @@ const OrderConfirm = () => {
buyerRemarks: orderRemark,
couponId: parseInt(String(bestCoupon.id), 10),
skuId: resolvedSkuId,
- specInfo: orderDataParam?.specInfo,
- deliveryMethod: deliveryMethod || undefined,
- deliveryFloor: needCarryUpstairs ? deliveryFloor : undefined
+ specInfo: orderDataParam?.specInfo
}
);
@@ -646,9 +608,7 @@ const OrderConfirm = () => {
// 🔧 确保 couponId 是正确的数字类型,且不传递 undefined
couponId: selectedCoupon ? parseInt(String(selectedCoupon.id), 10) : undefined,
skuId: resolvedSkuId,
- specInfo: orderDataParam?.specInfo,
- deliveryMethod: deliveryMethod || undefined,
- deliveryFloor: needCarryUpstairs ? deliveryFloor : undefined
+ specInfo: orderDataParam?.specInfo
}
);
@@ -1000,88 +960,6 @@ const OrderConfirm = () => {
{/* />*/}
{/**/}
- {/* 配送方式选择(仅送货上门模式显示) */}
- {goods.deliveryMode !== 1 && (
-
- |
-
-
- 配送方式
- *
-
-
- {[
- { key: 'elevator', label: '电梯', icon: '🏛️' },
- { key: 'stairs', label: '步梯', icon: '🚶' },
- { key: 'groundFloor', label: '一楼商铺/其他', icon: '🏪' },
- ].map(item => (
- {
- setDeliveryMethod(item.key)
- // 切换配送方式时重置送上楼选项
- setNeedCarryUpstairs(null)
- setDeliveryFloor(2)
- }}
- >
- {item.icon}
- {item.label}
-
- ))}
-
-
- {/* 步梯:是否需要送上楼 */}
- {deliveryMethod === 'stairs' && (
-
- 是否需要送上楼?
-
- setNeedCarryUpstairs(true)}
- >
- 需要送上楼
-
- {
- setNeedCarryUpstairs(false)
- setDeliveryFloor(2)
- }}
- >
- 不需要
-
-
-
- )}
-
- {/* 步梯+送上楼:选择楼层 */}
- {deliveryMethod === 'stairs' && needCarryUpstairs === true && (
-
- 送至楼层
- setFloorPickerVisible(true)}
- >
- 1 ? 'text-gray-900' : 'text-gray-400'}>
- {deliveryFloor > 1 ? `${deliveryFloor}楼` : '请选择楼层'}
-
-
-
- {deliveryFloor > 1 && (
-
-
- 配送费:{quantity}桶 × {deliveryFloor - 1}层 = ¥{getDeliveryFee().toFixed(2)}
-
-
- )}
-
- )}
-
- |
-
- )}
-
@@ -1180,14 +1058,7 @@ const OrderConfirm = () => {
)}
onClick={() => setCouponVisible(true)}
/>
- |
- ¥{getDeliveryFee().toFixed(2)}
- {deliveryMethod === 'stairs' && needCarryUpstairs && deliveryFloor > 1 && (
- ({quantity}桶×{deliveryFloor - 1}层)
- )}
- |
- }/>
+
|
已优惠
@@ -1361,49 +1232,6 @@ const OrderConfirm = () => {
| | |
|
- {/* 楼层选择弹窗 */}
- setFloorPickerVisible(false)}
- style={{height: '40vh'}}
- >
-
-
- 选择楼层
- setFloorPickerVisible(false)}
- >
- 关闭
-
-
-
-
- {Array.from({length: 32}, (_, i) => i + 2).map(f => (
- {
- setDeliveryFloor(f)
- setFloorPickerVisible(false)
- }}
- >
- {f}楼
-
- ))}
-
-
- {deliveryFloor > 1 && (
-
-
- 配送费:{quantity}桶 × {deliveryFloor - 1}层 = ¥{(quantity * (deliveryFloor - 1)).toFixed(2)}
-
-
- )}
-
-
-
@@ -1418,11 +1246,6 @@ const OrderConfirm = () => {
已优惠 ¥{getCouponDiscount().toFixed(2)}
)}
- {getDeliveryFee() > 0 && (
-
- 含配送费 ¥{getDeliveryFee().toFixed(2)}
-
- )}