qmj 1 месяц назад
Родитель
Сommit
f485532edf

+ 26 - 14
CLAUDE.md

@@ -2,9 +2,13 @@
 
 Auto-generated from all feature plans. Last updated: 2026-04-29
 
-## Active Technologies
+## Tech Stack
 
-- [e.g., Python 3.11, Swift 5.9, Rust 1.75 or NEEDS CLARIFICATION] + [e.g., FastAPI, UIKit, LLVM or NEEDS CLARIFICATION] (master)
+- **后端**: Java (Spring Boot, MyBatis with XML mappers)
+- **前端**: Vue.js (Element UI)
+- **支持语言**: Vietnamese (vi), Simplified Chinese (zh), Traditional Chinese (tw), English (en)
+- **数据库**: MySQL
+- **开发环境**: Windows
 
 ## Project Structure
 
@@ -13,18 +17,6 @@ Auto-generated from all feature plans. Last updated: 2026-04-29
 商家端管理前端代码路径:E:\QtwCode\foodie\foodie-store
 ```
 
-## Commands
-
-cd src; pytest; ruff check .
-
-## Code Style
-
-[e.g., Python 3.11, Swift 5.9, Rust 1.75 or NEEDS CLARIFICATION]: Follow standard conventions
-
-## Recent Changes
-
-- master: Added [e.g., Python 3.11, Swift 5.9, Rust 1.75 or NEEDS CLARIFICATION] + [e.g., FastAPI, UIKit, LLVM or NEEDS CLARIFICATION]
-
 <!-- MANUAL ADDITIONS START -->
 
 ## 前端多语言(i18n)添加规范
@@ -48,6 +40,26 @@ cd src; pytest; ruff check .
 
 **正确做法:** 编辑前端文件时,使用 Python 脚本(`python << 'PYEOF'`)通过 `content.replace()` 或行号操作来修改文件内容,避免换行符匹配问题。
 
+## 越南盾(VND)货币格式化
+
+所有展示给越南用户的货币/金额必须使用**整数格式**(无小数位),因为越南盾不使用分。Java 计算使用 `.setScale(0, RoundingMode.HALF_UP)`,JS 格式化使用 `Math.floor()` 或 `parseInt()`。
+
+## 全栈字段添加清单
+
+添加新字段到实体时,必须按顺序更新以下所有层级:
+1. Java 实体类(Entity)
+2. MyBatis XML mapper(resultMap + 相关的 select/insert/update 语句)
+3. DTO 类(如适用)
+4. Service 层业务逻辑
+5. Controller 层接口
+6. 前端 Vue 组件
+7. 四个 i18n 语言文件(vi.js、zh.js、tw.js、en.js)
+8. SQL 迁移脚本
+
+## 范围控制
+
+当用户说"只改 X"时,就只改 X——不要广泛探索、创建任务或为简单的定向修改启动 Agent。从用户提到的具体文件或区域开始,做最小的必要修改。
+
 <!-- MANUAL ADDITIONS END -->
 # CLAUDE.md
 

+ 52 - 1
ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderQsOprateController.java

@@ -31,6 +31,7 @@ import org.springframework.transaction.support.TransactionSynchronization;
 import org.springframework.transaction.support.TransactionSynchronizationManager;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.Date;
 import java.util.List;
 import java.util.TimerTask;
 import java.util.concurrent.TimeUnit;
@@ -65,7 +66,6 @@ public class PosOrderQsOprateController extends BaseController {
         JwtUtil jwtUtil = new JwtUtil();
         PayPush push = new PayPush();
         String qsId = jwtUtil.getusid(token);
-
         PosOrder order = posOrderService.getOne(
                 new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getId, id));
         if (order == null) {
@@ -78,6 +78,57 @@ public class PosOrderQsOprateController extends BaseController {
         return setOrderQsState(posOrder, qsId, push);
     }
 
+    /**
+     * 骑手取餐
+     * @param token
+     * @param id
+     * @return
+     */
+    @Anonymous
+    @Auth
+    @PostMapping("/pickupOrder")
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult pickupOrder(@RequestHeader String token, @RequestParam Long id) {
+        JwtUtil jwtUtil = new JwtUtil();
+        PayPush push = new PayPush();
+        String qsId = jwtUtil.getusid(token);
+        PosOrder order = posOrderService.getOne(
+                new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getId, id));
+        if (order == null) {
+            throw new ServiceException(MessageUtils.message("no.order.not.found"));
+        }
+        PosOrder posOrder = new PosOrder();
+        posOrder.setId(order.getId());
+        posOrder.setState(4L);
+        return setOrderQsState(posOrder, qsId, push);
+    }
+
+    /**
+     * 骑手送达
+     * @param token
+     * @param id
+     * @return
+     */
+    @Anonymous
+    @Auth
+    @PostMapping("/deliverOrder")
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult deliverOrder(@RequestHeader String token, @RequestParam Long id) {
+        JwtUtil jwtUtil = new JwtUtil();
+        PayPush push = new PayPush();
+        String qsId = jwtUtil.getusid(token);
+        PosOrder order = posOrderService.getOne(
+                new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getId, id));
+        if (order == null) {
+            throw new ServiceException(MessageUtils.message("no.order.not.found"));
+        }
+        PosOrder posOrder = new PosOrder();
+        posOrder.setId(order.getId());
+        posOrder.setState(12L);
+        posOrder.setSdTime(new Date());
+        return setOrderQsState(posOrder, qsId, push);
+    }
+
     //骑手接单、取餐、送达
     private AjaxResult setOrderQsState(PosOrder posOrder, String qsId, PayPush push) {
         String lockKey = "order:qs:lock:" + posOrder.getId();

+ 1 - 1
ruoyi-admin/src/main/java/com/ruoyi/app/order/TestTask.java

@@ -138,7 +138,7 @@ public class TestTask {
         System.out.println("检查预约单,预约检查时间:" + minute);
         LambdaQueryWrapper<PosOrder> query = new LambdaQueryWrapper<>();
         query.isNotNull(PosOrder::getDelryTime)
-                .eq(PosOrder::getType, 0L)
+                .in(PosOrder::getType, 0L,1L)
                 .ne(PosOrder::getDelryTime, "")
                 .isNotNull(PosOrder::getDelryTime)
                 .eq(PosOrder::getIsDisplay, false)

+ 12 - 0
ruoyi-admin/src/main/java/com/ruoyi/app/order/UserOrderController.java

@@ -21,6 +21,7 @@ import com.ruoyi.framework.manager.AsyncManager;
 import com.ruoyi.system.domain.*;
 import com.ruoyi.system.service.*;
 import com.ruoyi.system.utils.Auth;
+import com.ruoyi.system.utils.GetArea;
 import com.ruoyi.system.utils.JwtUtil;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -305,5 +306,16 @@ public class UserOrderController extends BaseController {
         return super.success(result);
     }
 
+    /**
+     * 计算两个经纬度之间的距离
+     */
+    @GetMapping("/getDistance")
+    @Anonymous
+    public AjaxResult getDistance(@RequestParam Double lat1, @RequestParam Double lng1,
+                                  @RequestParam Double lat2, @RequestParam Double lng2) {
+        double distance = GetArea.getDistance(lat1, lng1, lat2, lng2);
+        return success(distance);
+    }
+
 
 }

+ 5 - 0
ruoyi-system/src/main/java/com/ruoyi/system/domain/PosOrder.java

@@ -306,6 +306,11 @@ public class PosOrder {
 
     /** 取餐号 */
     private Long pickUpNum;
+    /** 自取时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date pickUpTime;
+    /** 预留电话 */
+    private String reservePhone;
     /** 商家是否已接单 */
     private Boolean isAccepted;
 

+ 21 - 0
ruoyi-system/src/main/java/com/ruoyi/system/utils/GetArea.java

@@ -181,6 +181,27 @@ public class GetArea {
         return ret;
     }
 
+    /**
+     * Haversine公式计算两个经纬度之间的距离
+     * @param lat1 第一个点纬度
+     * @param lng1 第一个点经度
+     * @param lat2 第二个点纬度
+     * @param lng2 第二个点经度
+     * @return 距离,单位:米
+     */
+    public static double getDistance(double lat1, double lng1, double lat2, double lng2) {
+        double radLat1 = Math.toRadians(lat1);
+        double radLat2 = Math.toRadians(lat2);
+        double a = radLat1 - radLat2;
+        double b = Math.toRadians(lng1) - Math.toRadians(lng2);
+        double distance = 2 * Math.asin(Math.sqrt(
+                Math.pow(Math.sin(a / 2), 2)
+                + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)
+        ));
+        distance = distance * 6378137;
+        return distance;
+    }
+
     private static double transformLng(double x, double y) {
         double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
         ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;

+ 9 - 1
ruoyi-system/src/main/resources/mapper/system/PosOrderMapper.xml

@@ -52,13 +52,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="posName" column="pos_name" />
         <result property="foodAmount" column="food_amount" />
         <result property="pickUpNum" column="pick_up_num" />
+        <result property="pickUpTime" column="pick_up_time" />
+        <result property="reservePhone" column="reserve_phone" />
         <result property="isAccepted" column="is_accepted" />
         <result property="isDisplay" column="is_display" />
         <result property="displayTime" column="display_time" />
     </resultMap>
 
     <sql id="selectPosOrderVo">
-        select id, dd_id, sh_id, md_id, cretim, shdz_id, user_id,sh_address, amount, remarks, state, type, delry_time,food,yh_id,yh_name,md_yh_id,md_yh_name,md_discount_amount,jvli,freight,dining_status,qs_id,pay_url,collect_payment,activity,md_activity,kefu_state,kefu_content,kefu_repeat,repeat_dd_id,sales_name,md_sales_name,sales_reduction,md_sales_reduction,points,points_reduction,sd_time,pay_type,parent_dd_id,order_category,table_id,table_no,logo,pos_name,food_amount,pick_up_num,is_accepted,is_display,display_time from pos_order
+        select id, dd_id, sh_id, md_id, cretim, shdz_id, user_id,sh_address, amount, remarks, state, type, delry_time,food,yh_id,yh_name,md_yh_id,md_yh_name,md_discount_amount,jvli,freight,dining_status,qs_id,pay_url,collect_payment,activity,md_activity,kefu_state,kefu_content,kefu_repeat,repeat_dd_id,sales_name,md_sales_name,sales_reduction,md_sales_reduction,points,points_reduction,sd_time,pay_type,parent_dd_id,order_category,table_id,table_no,logo,pos_name,food_amount,pick_up_num,pick_up_time,reserve_phone,is_accepted,is_display,display_time from pos_order
     </sql>
 
     <select id="selectPosOrderList" parameterType="PosOrder" resultMap="PosOrderResult">
@@ -179,6 +181,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="posName != null and posName != ''">pos_name,</if>
             <if test="foodAmount != null">food_amount,</if>
             <if test="pickUpNum != null">pick_up_num,</if>
+            <if test="pickUpTime != null">pick_up_time,</if>
+            <if test="reservePhone != null and reservePhone != ''">reserve_phone,</if>
             <if test="isAccepted != null">is_accepted,</if>
             <if test="isDisplay != null">is_display,</if>
             <if test="displayTime != null">display_time,</if>
@@ -217,6 +221,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="posName != null and posName != ''">#{posName},</if>
             <if test="foodAmount != null">#{foodAmount},</if>
             <if test="pickUpNum != null">#{pickUpNum},</if>
+            <if test="pickUpTime != null">#{pickUpTime},</if>
+            <if test="reservePhone != null and reservePhone != ''">#{reservePhone},</if>
             <if test="isAccepted != null">#{isAccepted},</if>
             <if test="isDisplay != null">#{isDisplay},</if>
             <if test="displayTime != null">#{displayTime},</if>
@@ -261,6 +267,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="posName != null and posName != ''">pos_name = #{posName},</if>
             <if test="foodAmount != null">food_amount = #{foodAmount},</if>
             <if test="pickUpNum != null">pick_up_num = #{pickUpNum},</if>
+            <if test="pickUpTime != null">pick_up_time = #{pickUpTime},</if>
+            <if test="reservePhone != null and reservePhone != ''">reserve_phone = #{reservePhone},</if>
             <if test="isAccepted != null">is_accepted = #{isAccepted},</if>
             <if test="isDisplay != null">is_display = #{isDisplay},</if>
             <if test="displayTime != null">display_time = #{displayTime},</if>