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)} - - )}