Pārlūkot izejas kodu

Merge remote-tracking branch 'origin/dev' into dev

jinshihui 1 dienu atpakaļ
vecāks
revīzija
13d4eb1e1e
46 mainītis faili ar 2092 papildinājumiem un 621 dzēšanām
  1. 521 462
      nightFragrance-admin/src/main/java/com/ylx/web/controller/massage/MaTechnicianController.java
  2. 1 8
      nightFragrance-admin/src/main/java/com/ylx/web/controller/massage/TCommentUserController.java
  3. 2 1
      nightFragrance-massage/src/main/java/com/ylx/fareSetting/controller/MaProjectFareSettingController.java
  4. 51 20
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/CityOperationApplication.java
  5. 7 2
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/CommentUserAudit.java
  6. 18 5
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/MaProject.java
  7. 1 1
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/dto/MaProjectSaveDto.java
  8. 7 2
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/dto/MaProjectUpdateDto.java
  9. 21 0
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/dto/RefuseOrderReqDTO.java
  10. 31 6
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/vo/MaTechnicianAppAddVo.java
  11. 26 0
      nightFragrance-massage/src/main/java/com/ylx/massage/enums/OrderTipEnum.java
  12. 1 2
      nightFragrance-massage/src/main/java/com/ylx/massage/mapper/TCommentUserMapper.java
  13. 23 1
      nightFragrance-massage/src/main/java/com/ylx/massage/service/IMaTechnicianService.java
  14. 8 2
      nightFragrance-massage/src/main/java/com/ylx/massage/service/TCommentUserService.java
  15. 3 3
      nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/MaProjectServiceImpl.java
  16. 133 35
      nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/MaTechnicianServiceImpl.java
  17. 1 1
      nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/TCommentUserAuditServiceImpl.java
  18. 110 1
      nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/TCommentUserServiceImpl.java
  19. 39 0
      nightFragrance-massage/src/main/java/com/ylx/order/controller/OrderCommentController.java
  20. 32 0
      nightFragrance-massage/src/main/java/com/ylx/order/controller/RefundController.java
  21. 21 7
      nightFragrance-massage/src/main/java/com/ylx/order/controller/RegulationController.java
  22. 41 0
      nightFragrance-massage/src/main/java/com/ylx/order/domain/TCommentPicture.java
  23. 35 21
      nightFragrance-massage/src/main/java/com/ylx/order/domain/TCommentUser.java
  24. 0 3
      nightFragrance-massage/src/main/java/com/ylx/order/domain/TOrder.java
  25. 0 28
      nightFragrance-massage/src/main/java/com/ylx/order/domain/dto/AutoFlowConfigDTO.java
  26. 86 0
      nightFragrance-massage/src/main/java/com/ylx/order/domain/dto/OrderCommentDTO.java
  27. 2 3
      nightFragrance-massage/src/main/java/com/ylx/order/domain/dto/OrderSubmitDTO.java
  28. 123 0
      nightFragrance-massage/src/main/java/com/ylx/order/domain/dto/RegulationConfigDTO.java
  29. 10 1
      nightFragrance-massage/src/main/java/com/ylx/order/domain/vo/OrderDetailVO.java
  30. 29 0
      nightFragrance-massage/src/main/java/com/ylx/order/domain/vo/RegulationConfigVO.java
  31. 51 0
      nightFragrance-massage/src/main/java/com/ylx/order/enums/AuditStatusEnum.java
  32. 27 0
      nightFragrance-massage/src/main/java/com/ylx/order/enums/RefundStageTypeEnum.java
  33. 18 0
      nightFragrance-massage/src/main/java/com/ylx/order/mapper/TCommentPictureMapper.java
  34. 4 0
      nightFragrance-massage/src/main/java/com/ylx/order/service/AutoFlowConfigService.java
  35. 1 0
      nightFragrance-massage/src/main/java/com/ylx/order/service/RefundRuleDetailService.java
  36. 6 0
      nightFragrance-massage/src/main/java/com/ylx/order/service/RefundRuleMasterService.java
  37. 14 0
      nightFragrance-massage/src/main/java/com/ylx/order/service/RegulationService.java
  38. 30 0
      nightFragrance-massage/src/main/java/com/ylx/order/service/TCommentPictureService.java
  39. 47 0
      nightFragrance-massage/src/main/java/com/ylx/order/service/impl/AutoFlowConfigServiceImpl.java
  40. 23 0
      nightFragrance-massage/src/main/java/com/ylx/order/service/impl/RefundRuleDetailServiceImpl.java
  41. 337 0
      nightFragrance-massage/src/main/java/com/ylx/order/service/impl/RefundRuleMasterServiceImpl.java
  42. 71 0
      nightFragrance-massage/src/main/java/com/ylx/order/service/impl/RegulationServiceImpl.java
  43. 59 0
      nightFragrance-massage/src/main/java/com/ylx/order/service/impl/TCommentPictureServiceImpl.java
  44. 3 1
      nightFragrance-massage/src/main/java/com/ylx/order/service/impl/TOrderServiceImpl.java
  45. 5 5
      nightFragrance-massage/src/main/resources/mapper/massage/TCommentUserMapper.xml
  46. 13 0
      nightFragrance-massage/src/main/resources/mapper/order/TCommentPictureMapper.xml

+ 521 - 462
nightFragrance-admin/src/main/java/com/ylx/web/controller/massage/MaTechnicianController.java

@@ -18,6 +18,7 @@ import com.ylx.common.core.controller.BaseController;
 import com.ylx.common.core.domain.AjaxResult;
 import com.ylx.common.core.domain.R;
 import com.ylx.common.core.domain.model.LoginUser;
+import com.ylx.common.core.domain.model.WxLoginUser;
 import com.ylx.common.core.domain.model.aliyun.SMSVerificationCode;
 import com.ylx.common.core.domain.model.aliyun.SendSmsComponents;
 import com.ylx.common.core.domain.model.aliyun.SendSmsEnum;
@@ -31,6 +32,7 @@ import com.ylx.common.utils.StringUtils;
 import com.ylx.common.utils.poi.ExcelUtil;
 import com.ylx.framework.manager.AsyncManager;
 import com.ylx.framework.manager.factory.AsyncFactory;
+import com.ylx.framework.web.service.WxTokenService;
 import com.ylx.massage.domain.MaProject;
 import com.ylx.massage.domain.MaTechnician;
 import com.ylx.massage.domain.dto.*;
@@ -43,6 +45,8 @@ import com.ylx.servicecategory.service.ServiceCategoryService;
 import com.ylx.system.service.ISysConfigService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -68,6 +72,8 @@ import java.util.Random;
 import java.util.concurrent.TimeUnit;
 import java.util.regex.Pattern;
 
+import static jdk.nashorn.internal.runtime.regexp.joni.Config.log;
+
 /**
  * 技师Controller
  *
@@ -75,6 +81,7 @@ import java.util.regex.Pattern;
  * @date 2024-03-22
  */
 @Api("技师管理")
+@Slf4j
 @RestController
 @RequestMapping("/technician/technician")
 public class MaTechnicianController extends BaseController {
@@ -94,6 +101,8 @@ public class MaTechnicianController extends BaseController {
     private ISysConfigService configService;
     @Autowired
     private RedisCache redisCache;
+    @Autowired
+    private WxTokenService wxTokenService;
 
 
     public static final String PHONE_THREEUSERPARTCLIENT_CODE_KEY = "sys:clientLogin:phone:";
@@ -131,9 +140,9 @@ public class MaTechnicianController extends BaseController {
     @ApiOperation(value = "商户登录", notes = "商户登录")
     @PostMapping(value = "/clientLogin")
     @Transactional
-    public Result<JSONObject> login(@RequestBody ThirdPartyLoginsVo thirdPartyLoginsVo) throws Exception {
+    public Result<WxLoginUser> login(@RequestBody ThirdPartyLoginsVo thirdPartyLoginsVo) throws Exception {
         // 获取登录用户信息
-        Result<JSONObject> result = new Result<>();
+        Result<WxLoginUser> result = new Result<>();
 
         // 校验手机号是否为空
         if (StringUtils.isEmpty(thirdPartyLoginsVo.getPhone())) {
@@ -164,271 +173,320 @@ public class MaTechnicianController extends BaseController {
             // 初始化加密工具
             BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
             // 验证:比对是否匹配
-            boolean isOk = encoder.matches(thirdPartyLoginsVo.getPassWord(),maTechnician.getTePassword());
-                if (!isOk) {
-                    return Result.error("密码错误");
-                }
-
-
+            boolean isOk = encoder.matches(thirdPartyLoginsVo.getPassWord(), maTechnician.getTePassword());
+            if (!isOk) {
+                return Result.error("密码错误");
             }
 
-            // 登录成功删除验证码
-            redisTemplate.delete(PHONE_THREEUSERPARTCLIENT_CODE_KEY + thirdPartyLoginsVo.getPhone());
-            result.success("登录成功");
-            return result;
-        }
 
-        /**
-         * 商户忘记密码接口
-         */
-        @PostMapping("/resetPassword")
-        public Result<?> resetPassword (@RequestBody ThirdPartyLoginsVo thirdPartyLoginsVo){
-            // 核心正则表达式:
-            // ^ 表示开头,$ 表示结尾
-            // [a-zA-Z0-9] 表示只能是字母或数字
-            // {8,20} 表示长度必须在8到20之间
-            String regex = "^[a-zA-Z0-9]{8,20}$";
-            boolean isMatch = Pattern.matches(regex, thirdPartyLoginsVo.getPassWord().trim());
-            if (!isMatch) {
-                // 根据需求返回指定的异常提示
-                return Result.error("请输入8-20位数字/字母组合");
-            }
-            // 短信验证
-            String msg = redisTemplate.opsForValue().get(PHONE_THREEUSERPARTCLIENT_CODE_KEY + thirdPartyLoginsVo.getPhone());
-            if (StringUtils.isEmpty(msg)) {
-                return Result.error("验证码已失效");
-            }
-            if (msg != null && msg.startsWith("\"") && msg.endsWith("\"")) {
-                msg = msg.substring(1, msg.length() - 1);
-            }
-            if (!thirdPartyLoginsVo.getPhoneMsg().equals(msg)) {
-                return Result.error("短信验证码不正确");
-            }
-            // 重置密码逻辑
-            LambdaUpdateWrapper<MaTechnician> updateWrapper = new LambdaUpdateWrapper<>();
-            updateWrapper.eq(MaTechnician::getTePhone, thirdPartyLoginsVo.getPhone());
-            updateWrapper.set(MaTechnician::getTePassword, thirdPartyLoginsVo.getPassWord());
-            maTechnicianService.update(updateWrapper);
-            redisTemplate.delete(PHONE_THREEUSERPARTCLIENT_CODE_KEY + thirdPartyLoginsVo.getPhone());
-            return Result.ok("重置密码成功");
         }
-
-        /**
-         * 校验图形验证码接口
-         */
-        @PostMapping("/getValidateCaptcha")
-        public Result<?> getValidateCaptcha (@RequestBody ValidateCaptchaDto req){
-            validateCaptcha(req.getPhone(), req.getCode(), req.getUuid());
-            return Result.ok("校验成功");
+        WxLoginUser wxUser = new WxLoginUser();
+        BeanUtils.copyProperties(maTechnician, wxUser);
+        // 生成并返回令牌
+        String token = wxTokenService.createToken(wxUser);
+        log.info("token的值:{}", token);
+        if (token == null || token.isEmpty()) {
+            return Result.error("生成令牌失败");
         }
-        /**
-         * 商户入驻申请接口
-         */
-        @PostMapping("/apply")
-        public Result<?> apply (@RequestBody MaTechnicianAppAddVo req){
-            // 1. 基础参数校验
-            if (StringUtils.isAnyBlank(req.getTeName(), req.getTePhone(), req.getTeAddress(), req.getAvatar())) {
-                return Result.error("必填项不能为空");
-            }
-            //校验性别不能为空
-            if (Objects.isNull(req.getTeSex())) {
-                return Result.error("性别不能为空");
-            }
-            // 短信验证
-            String msg = redisTemplate.opsForValue().get(PHONE_THREEUSERPARTCLIENT_CODE_KEY + req.getTePhone());
-            if (StringUtils.isEmpty(msg)) {
-                return Result.error("验证码已失效");
-            }
-            if (msg != null && msg.startsWith("\"") && msg.endsWith("\"")) {
-                msg = msg.substring(1, msg.length() - 1);
-            }
-            if (!req.getPhoneMsg().equals(msg)) {
-                return Result.error("短信验证码不正确");
-            }
-            if (StringUtils.isNotEmpty(req.getPhoneImgMsg())) {
-                validateCaptcha(req.getTeName(), req.getPhoneImgMsg(), req.getUuid());
-            }
-            // 2. 调用业务层处理入驻申请
-            maTechnicianService.apply(req);
-            return Result.ok("提交成功,进入审核流程");
+        //给我把token的值保存到redis中
+        redisTemplate.opsForValue().set(wxUser.getCOpenid(), token, 180, TimeUnit.MINUTES);
+        wxUser.setToken(token);
+        // 返回用户信息
+        // 记录登录信息
+        AsyncManager.me().execute(AsyncFactory.recordLogininfor(wxUser.getCOpenid(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
+        result.setResult(wxUser);
+        // 登录成功删除验证码
+        redisTemplate.delete(PHONE_THREEUSERPARTCLIENT_CODE_KEY + thirdPartyLoginsVo.getPhone());
+
+        result.success("登录成功");
+        return result;
+    }
+
+    /**
+     * 商户忘记密码接口
+     */
+    @PostMapping("/resetPassword")
+    public Result<?> resetPassword(@RequestBody ThirdPartyLoginsVo thirdPartyLoginsVo) {
+        // 核心正则表达式:
+        // ^ 表示开头,$ 表示结尾
+        // [a-zA-Z0-9] 表示只能是字母或数字
+        // {8,20} 表示长度必须在8到20之间
+        String regex = "^[a-zA-Z0-9]{8,20}$";
+        boolean isMatch = Pattern.matches(regex, thirdPartyLoginsVo.getPassWord().trim());
+        if (!isMatch) {
+            // 根据需求返回指定的异常提示
+            return Result.error("请输入8-20位数字/字母组合");
+        }
+        // 短信验证
+        String msg = redisTemplate.opsForValue().get(PHONE_THREEUSERPARTCLIENT_CODE_KEY + thirdPartyLoginsVo.getPhone());
+        if (StringUtils.isEmpty(msg)) {
+            return Result.error("验证码已失效");
+        }
+        if (msg != null && msg.startsWith("\"") && msg.endsWith("\"")) {
+            msg = msg.substring(1, msg.length() - 1);
+        }
+        if (!thirdPartyLoginsVo.getPhoneMsg().equals(msg)) {
+            return Result.error("短信验证码不正确");
+        }
+        // 重置密码逻辑
+        LambdaUpdateWrapper<MaTechnician> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.eq(MaTechnician::getTePhone, thirdPartyLoginsVo.getPhone());
+        updateWrapper.set(MaTechnician::getTePassword, thirdPartyLoginsVo.getPassWord());
+        maTechnicianService.update(updateWrapper);
+        redisTemplate.delete(PHONE_THREEUSERPARTCLIENT_CODE_KEY + thirdPartyLoginsVo.getPhone());
+        return Result.ok("重置密码成功");
+    }
+
+    /**
+     * 校验图形验证码接口
+     */
+    @PostMapping("/getValidateCaptcha")
+    public Result<?> getValidateCaptcha(@RequestBody ValidateCaptchaDto req) {
+        validateCaptcha(req.getPhone(), req.getCode(), req.getUuid());
+        return Result.ok("校验成功");
+    }
+
+    /**
+     * 商户入驻申请接口
+     */
+    @PostMapping("/apply")
+    public Result<?> apply(@RequestBody MaTechnicianAppAddVo req) {
+        // 1. 基础参数校验
+        if (StringUtils.isAnyBlank(req.getTeName(), req.getTePhone(),  req.getAvatar())) {
+            return Result.error("必填项不能为空");
         }
-        /**
-         * 校验验证码
-         *
-         * @param username 用户名
-         * @param code     验证码
-         * @param uuid     唯一标识
-         * @return 结果
-         */
-        public void validateCaptcha (String username, String code, String uuid){
-            boolean captchaEnabled = configService.selectCaptchaEnabled();
-            if (captchaEnabled) {
-                String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
-                String captcha = redisCache.getCacheObject(verifyKey);
-                redisCache.deleteObject(verifyKey);
-                if (captcha == null) {
-                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
-                    throw new CaptchaExpireException();
-                }
-                if (!code.equalsIgnoreCase(captcha)) {
-                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
-                    throw new CaptchaException();
-                }
-            }
+        //校验性别不能为空
+        if (Objects.isNull(req.getTeSex())) {
+            return Result.error("性别不能为空");
         }
-
-        /**
-         * 申请技师文件
-         * @param req
-         */
-        @PostMapping("/applyFile")
-        public Result applyFile (@RequestBody MerchantApplyFileRequestDto req) {
-            maTechnicianService.applyFile(req);
-            return Result.ok("上传成功");
+        // 短信验证
+        String msg = redisTemplate.opsForValue().get(PHONE_THREEUSERPARTCLIENT_CODE_KEY + req.getTePhone());
+        if (StringUtils.isEmpty(msg)) {
+            return Result.error("验证码已失效");
         }
-        /**
-         * 获取待接单列表:前端传技师实时经纬度筛选订单
-         */
-        @GetMapping("/wait/list")
-        public Result<List<WaitOrderDTO>> getWaitOrder (WaitOrderQueryDTO query){
-            List<WaitOrderDTO> list = maTechnicianService.listWaitOrder(query);
-            return Result.ok(list);
+        if (msg != null && msg.startsWith("\"") && msg.endsWith("\"")) {
+            msg = msg.substring(1, msg.length() - 1);
         }
-
-        /**
-         * 技师状态切换
-         *
-         * @param
-         */
-        @GetMapping("/switchToOffline")
-        public Result switchToOffline (@RequestParam Long userId, @RequestParam Boolean forceConfirm){
-            return maTechnicianService.switchToOffline(userId, forceConfirm);
+        if (!req.getPhoneMsg().equals(msg)) {
+            return Result.error("短信验证码不正确");
         }
-        /**
-         * 查询商户信息接口
-         */
-        @GetMapping("/getTechnician")
-        public Result<?> getTechnician (@RequestParam String openid){
-            LambdaQueryWrapper<MaTechnician> queryWrapper = new LambdaQueryWrapper<>();
-            queryWrapper.eq(MaTechnician::getCOpenid, openid);
-            MaTechnician maTechnician = maTechnicianService.getBaseMapper().selectOne(queryWrapper);
-            return Result.ok(maTechnician);
+        if (StringUtils.isNotEmpty(req.getPhoneImgMsg())) {
+            validateCaptcha(req.getTeName(), req.getPhoneImgMsg(), req.getUuid());
         }
+        // 2. 调用业务层处理入驻申请
+        maTechnicianService.apply(req);
+        return Result.ok("提交成功,进入审核流程");
+    }
 
-        /**
-         * 修改和上传商户信息接口
-         */
-        @PostMapping("/updateTechnician")
-        public Result<?> updateTechnician (@RequestBody MaTechnicianAppAddVo req){
-            if (req.getAuditStatus() == 0 || req.getAuditStatus() == 3) {
-                //修改基本信息
-                updateMaTechnician(req);
+    /**
+     * 校验验证码
+     *
+     * @param username 用户名
+     * @param code     验证码
+     * @param uuid     唯一标识
+     * @return 结果
+     */
+    public void validateCaptcha(String username, String code, String uuid) {
+        boolean captchaEnabled = configService.selectCaptchaEnabled();
+        if (captchaEnabled) {
+            String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
+            String captcha = redisCache.getCacheObject(verifyKey);
+            redisCache.deleteObject(verifyKey);
+            if (captcha == null) {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
+                throw new CaptchaExpireException();
+            }
+            if (!code.equalsIgnoreCase(captcha)) {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
+                throw new CaptchaException();
             }
-            return Result.ok("修改成功");
         }
+    }
 
+    /**
+     * 申请技师文件
+     *
+     * @param req
+     */
+    @PostMapping("/applyFile")
+    public Result applyFile(@RequestBody MerchantApplyFileRequestDto req) {
+        maTechnicianService.applyFile(req);
+        return Result.ok("上传成功");
+    }
 
-        private void updateMaTechnician (MaTechnicianAppAddVo req){
-            LambdaUpdateWrapper<MaTechnician> updateWrapper = new LambdaUpdateWrapper<>();
-            updateWrapper.eq(MaTechnician::getId, req.getId());
-            updateWrapper.set(MaTechnician::getTePhone, req.getTePhone());
-            updateWrapper.set(MaTechnician::getTeName, req.getTeName());
-            updateWrapper.set(MaTechnician::getOpenService, req.getServiceTag());
-            updateWrapper.set(MaTechnician::getTeAddress, req.getTeAddress());
-            updateWrapper.set(MaTechnician::getTeAge, req.getTeAge());
-            updateWrapper.set(MaTechnician::getAvatar, req.getAvatar());
-            updateWrapper.set(MaTechnician::getTeBrief, req.getTeBrief());
-            maTechnicianService.update(updateWrapper);
-        }
+    /**
+     * 获取待接单列表:前端传技师实时经纬度筛选订单
+     */
+    @PostMapping("/wait/list")
+    public Result<List<WaitOrderDTO>> getWaitOrder(@RequestBody WaitOrderQueryDTO query) {
+        List<WaitOrderDTO> list = maTechnicianService.listWaitOrder(query);
+        return Result.ok(list);
+    }
 
-        /**
-         * 查询技师列表
-         */
-        @PreAuthorize("@ss.hasPermi('technician:technician:list')")
-        @GetMapping("/list")
-        public TableDataInfo list (MaTechnician maTechnician){
-            startPage();
-            List<MaTechnician> list = maTechnicianService.selectMaTechnicianList(maTechnician);
-            return getDataTable(list);
-        }
+    /**
+     * 滑动接单逻辑不变,
+     * 仅列表查询逻辑修正
+     */
+    @PostMapping("/accept")
+    public Result<String> acceptOrder(@RequestBody AcceptOrderReqDTO req) {
+        String tip = maTechnicianService.acceptOrder(req);
+        return Result.ok(tip);
+    }
 
-        /**
-         * 导出技师列表
-         */
-        @PreAuthorize("@ss.hasPermi('technician:technician:export')")
-        @Log(title = "技师", businessType = BusinessType.EXPORT)
-        @PostMapping("/export")
-        public void export (HttpServletResponse response, MaTechnician maTechnician){
-            List<MaTechnician> list = maTechnicianService.selectMaTechnicianList(maTechnician);
-            ExcelUtil<MaTechnician> util = new ExcelUtil<MaTechnician>(MaTechnician.class);
-            util.exportExcel(response, list, "技师数据");
-        }
+    /**
+     * 技师接单确认逻辑不变,
+     * 仅列表查询逻辑修正
+     */
+    @GetMapping("/rest/confirm")
+    public Result<String> confirmRestAccept(@RequestParam Long techId, @RequestParam Long orderId) {
+        String tip = maTechnicianService.confirmRestAccept(techId, orderId);
+        return Result.ok(tip);
+    }
 
-        /**
-         * 获取技师详细信息
-         */
-        @PreAuthorize("@ss.hasPermi('technician:technician:query')")
-        @GetMapping(value = "/{id}")
-        public AjaxResult getInfo (@PathVariable("id") Long id){
-            return success(maTechnicianService.selectMaTechnicianById(id));
-        }
+    /**
+     * 技师拒绝接单逻辑不变,
+     * 仅列表查询逻辑修正
+     */
+    @PostMapping("/refuse")
+    public Result<Void> refuseOrder(@RequestBody RefuseOrderReqDTO req) {
+        maTechnicianService.refuseOrder(req);
+        return Result.ok("拒绝成功");
+    }
+
+    /**
+     * 技师状态切换
+     *
+     * @param
+     */
+    @GetMapping("/switchToOffline")
+    public Result switchToOffline(@RequestParam Long userId, @RequestParam Boolean forceConfirm) {
+        return maTechnicianService.switchToOffline(userId, forceConfirm);
+    }
 
-        /**
-         * 新增技师
-         */
-        @ApiOperation("技师入驻")
-        @PreAuthorize("@ss.hasPermi('technician:technician:add')")
-        @Log(title = "技师", businessType = BusinessType.INSERT)
-        @PostMapping
-        public AjaxResult add (@RequestBody MaTechnicianAppAddVo maTechnicianAppAddVo){
-            return toAjax(maTechnicianService.insertMaTechnician(maTechnicianAppAddVo));
+    /**
+     * 查询商户信息接口
+     */
+    @GetMapping("/getTechnician")
+    public Result<?> getTechnician(@RequestParam String openid) {
+        LambdaQueryWrapper<MaTechnician> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(MaTechnician::getCOpenid, openid);
+        MaTechnician maTechnician = maTechnicianService.getBaseMapper().selectOne(queryWrapper);
+        return Result.ok(maTechnician);
+    }
+
+    /**
+     * 修改和上传商户信息接口
+     */
+    @PostMapping("/updateTechnician")
+    public Result<?> updateTechnician(@RequestBody MaTechnicianAppAddVo req) {
+        if (req.getAuditStatus() == 0 || req.getAuditStatus() == 3) {
+            //修改基本信息
+            updateMaTechnician(req);
         }
+        return Result.ok("修改成功");
+    }
 
-        /**
-         * 后台新增商户
-         *
-         * @param dto 商户新增DTO
-         * @return AjaxResult 结果
-         */
-        @ApiOperation("后台新增商户")
-        @PreAuthorize("@ss.hasPermi('technician:technician:add')")
-        @Log(title = "商户", businessType = BusinessType.INSERT)
-        @PostMapping("/merchant")
-        public AjaxResult addMerchant (@RequestBody MaTechnicianMerchantAddDTO dto){
-            try {
-                LoginUser loginUser = getLoginUser();
-                return toAjax(maTechnicianService.insertMerchant(dto, loginUser));
-            } catch (Exception e) {
-                e.printStackTrace();
-                throw new RuntimeException(e);
-            }
+
+    private void updateMaTechnician(MaTechnicianAppAddVo req) {
+        LambdaUpdateWrapper<MaTechnician> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.eq(MaTechnician::getId, req.getId());
+        updateWrapper.set(MaTechnician::getTePhone, req.getTePhone());
+        updateWrapper.set(MaTechnician::getTeName, req.getTeName());
+        updateWrapper.set(MaTechnician::getOpenService, req.getServiceTag());
+        updateWrapper.set(MaTechnician::getTeAge, req.getTeAge());
+        updateWrapper.set(MaTechnician::getAvatar, req.getAvatar());
+        updateWrapper.set(MaTechnician::getTeBrief, req.getTeBrief());
+        maTechnicianService.update(updateWrapper);
+    }
+
+    /**
+     * 查询技师列表
+     */
+    @PreAuthorize("@ss.hasPermi('technician:technician:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(MaTechnician maTechnician) {
+        startPage();
+        List<MaTechnician> list = maTechnicianService.selectMaTechnicianList(maTechnician);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出技师列表
+     */
+    @PreAuthorize("@ss.hasPermi('technician:technician:export')")
+    @Log(title = "技师", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, MaTechnician maTechnician) {
+        List<MaTechnician> list = maTechnicianService.selectMaTechnicianList(maTechnician);
+        ExcelUtil<MaTechnician> util = new ExcelUtil<MaTechnician>(MaTechnician.class);
+        util.exportExcel(response, list, "技师数据");
+    }
+
+    /**
+     * 获取技师详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('technician:technician:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id) {
+        return success(maTechnicianService.selectMaTechnicianById(id));
+    }
+
+    /**
+     * 新增技师
+     */
+    @ApiOperation("技师入驻")
+    @PreAuthorize("@ss.hasPermi('technician:technician:add')")
+    @Log(title = "技师", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody MaTechnicianAppAddVo maTechnicianAppAddVo) {
+        return toAjax(maTechnicianService.insertMaTechnician(maTechnicianAppAddVo));
+    }
+
+    /**
+     * 后台新增商户
+     *
+     * @param dto 商户新增DTO
+     * @return AjaxResult 结果
+     */
+    @ApiOperation("后台新增商户")
+    @PreAuthorize("@ss.hasPermi('technician:technician:add')")
+    @Log(title = "商户", businessType = BusinessType.INSERT)
+    @PostMapping("/merchant")
+    public AjaxResult addMerchant(@RequestBody MaTechnicianMerchantAddDTO dto) {
+        try {
+            LoginUser loginUser = getLoginUser();
+            return toAjax(maTechnicianService.insertMerchant(dto, loginUser));
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
         }
+    }
 
-        /**
-         * 后台编辑商户
-         *
-         * @param id  商户ID
-         * @param dto 商户编辑DTO
-         * @return AjaxResult 结果
-         */
-        @ApiOperation("后台编辑商户")
-        @PreAuthorize("@ss.hasPermi('technician:technician:edit')")
-        @Log(title = "商户", businessType = BusinessType.UPDATE)
-        @PutMapping("/merchant/{id}")
-        public AjaxResult editMerchant (@PathVariable("id") Integer id, @RequestBody MaTechnicianMerchantAddDTO dto){
-            try {
-                LoginUser loginUser = getLoginUser();
-                return toAjax(maTechnicianService.updateMerchant(id, dto, loginUser));
-            } catch (Exception e) {
-                e.printStackTrace();
-                throw new RuntimeException(e);
-            }
+    /**
+     * 后台编辑商户
+     *
+     * @param id  商户ID
+     * @param dto 商户编辑DTO
+     * @return AjaxResult 结果
+     */
+    @ApiOperation("后台编辑商户")
+    @PreAuthorize("@ss.hasPermi('technician:technician:edit')")
+    @Log(title = "商户", businessType = BusinessType.UPDATE)
+    @PutMapping("/merchant/{id}")
+    public AjaxResult editMerchant(@PathVariable("id") Integer id, @RequestBody MaTechnicianMerchantAddDTO dto) {
+        try {
+            LoginUser loginUser = getLoginUser();
+            return toAjax(maTechnicianService.updateMerchant(id, dto, loginUser));
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
         }
+    }
 
     /**
      * 后台上传商户合同文件
      *
-     * @param id   商户ID
+     * @param id  商户ID
      * @param map 合同文件
      * @return R 上传结果
      */
@@ -436,7 +494,7 @@ public class MaTechnicianController extends BaseController {
     @PreAuthorize("@ss.hasPermi('technician:technician:edit')")
     @Log(title = "商户合同", businessType = BusinessType.UPDATE)
     @PostMapping("/merchant/{id}/contract")
-    public R uploadMerchantContract(@PathVariable("id") Integer id, @RequestBody Map<String,Object> map) {
+    public R uploadMerchantContract(@PathVariable("id") Integer id, @RequestBody Map<String, Object> map) {
         try {
             LoginUser loginUser = getLoginUser();
             return R.ok(maTechnicianService.uploadMerchantContract(id, map, loginUser));
@@ -446,259 +504,260 @@ public class MaTechnicianController extends BaseController {
         }
     }
 
-        /**
-         * 查询商户入驻审核列表
-         *
-         * @param page 分页参数
-         * @param dto  查询条件
-         * @return Page 商户入驻审核分页列表
-         */
-        @ApiOperation("后台查询商户入驻审核列表")
-        @PreAuthorize("@ss.hasPermi('technician:technician:list')")
-        @GetMapping("/merchant/audit/list")
-        public R<Page<MaTechnicianAuditListVO>> merchantAuditList
-        (Page < MaTechnicianAuditListVO > page, MaTechnicianAuditQueryDTO dto){
-            try {
-                return R.ok(maTechnicianService.selectMerchantAuditList(page, dto));
-            } catch (Exception e) {
-                e.printStackTrace();
-                throw new RuntimeException(e);
-            }
+    /**
+     * 查询商户入驻审核列表
+     *
+     * @param page 分页参数
+     * @param dto  查询条件
+     * @return Page 商户入驻审核分页列表
+     */
+    @ApiOperation("后台查询商户入驻审核列表")
+    @PreAuthorize("@ss.hasPermi('technician:technician:list')")
+    @GetMapping("/merchant/audit/list")
+    public R<Page<MaTechnicianAuditListVO>> merchantAuditList
+    (Page<MaTechnicianAuditListVO> page, MaTechnicianAuditQueryDTO dto) {
+        try {
+            return R.ok(maTechnicianService.selectMerchantAuditList(page, dto));
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
         }
+    }
 
-        /**
-         * 商户入驻审核
-         *
-         * @param id  商户ID
-         * @param dto 审核提交参数
-         * @return AjaxResult 结果
-         */
-        @ApiOperation("商户入驻审核")
-        @PreAuthorize("@ss.hasPermi('technician:technician:edit')")
-        @Log(title = "商户入驻审核", businessType = BusinessType.UPDATE)
-        @PutMapping("/merchant/audit/{id}/submit")
-        public AjaxResult submitMerchantAudit (@PathVariable("id") Integer id, @RequestBody MaTechnicianAuditSubmitDTO
-        dto){
-            try {
-                LoginUser loginUser = getLoginUser();
-                return toAjax(maTechnicianService.submitMerchantAudit(id, dto, loginUser));
-            } catch (Exception e) {
-                e.printStackTrace();
-                throw new RuntimeException(e);
-            }
+    /**
+     * 商户入驻审核
+     *
+     * @param id  商户ID
+     * @param dto 审核提交参数
+     * @return AjaxResult 结果
+     */
+    @ApiOperation("商户入驻审核")
+    @PreAuthorize("@ss.hasPermi('technician:technician:edit')")
+    @Log(title = "商户入驻审核", businessType = BusinessType.UPDATE)
+    @PutMapping("/merchant/audit/{id}/submit")
+    public AjaxResult submitMerchantAudit(@PathVariable("id") Integer id, @RequestBody MaTechnicianAuditSubmitDTO
+                                                                                  dto) {
+        try {
+            LoginUser loginUser = getLoginUser();
+            return toAjax(maTechnicianService.submitMerchantAudit(id, dto, loginUser));
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
         }
+    }
 
-        /**
-         * 待审核页面审核通过商户
-         *
-         * @param id  商户ID
-         * @param dto 待审核通过参数
-         * @return AjaxResult 结果
-         */
-        @ApiOperation("待审核页面审核通过商户")
-        @PreAuthorize("@ss.hasPermi('technician:technician:edit')")
-        @Log(title = "商户待审核通过", businessType = BusinessType.UPDATE)
-        @PutMapping("/merchant/audit/{id}/approve")
-        public AjaxResult approvePendingMerchantAudit (@PathVariable("id") Integer id,
-                                                                                           @RequestBody MaTechnicianPendingAuditSubmitDTO
-        dto){
-            try {
-                LoginUser loginUser = getLoginUser();
-                return toAjax(maTechnicianService.approvePendingMerchantAudit(id, dto, loginUser));
-            } catch (Exception e) {
-                e.printStackTrace();
-                throw new RuntimeException(e);
-            }
+    /**
+     * 待审核页面审核通过商户
+     *
+     * @param id  商户ID
+     * @param dto 待审核通过参数
+     * @return AjaxResult 结果
+     */
+    @ApiOperation("待审核页面审核通过商户")
+    @PreAuthorize("@ss.hasPermi('technician:technician:edit')")
+    @Log(title = "商户待审核通过", businessType = BusinessType.UPDATE)
+    @PutMapping("/merchant/audit/{id}/approve")
+    public AjaxResult approvePendingMerchantAudit(@PathVariable("id") Integer id,
+                                                  @RequestBody MaTechnicianPendingAuditSubmitDTO
+                                                          dto) {
+        try {
+            LoginUser loginUser = getLoginUser();
+            return toAjax(maTechnicianService.approvePendingMerchantAudit(id, dto, loginUser));
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
         }
+    }
 
-        /**
-         * 查询商户列表
-         *
-         * @param page 分页参数
-         * @param dto  商户查询DTO
-         * @return Page 商户分页列表
-         */
-        @ApiOperation("后台查询商户列表")
-        @PreAuthorize("@ss.hasPermi('technician:technician:list')")
-        @GetMapping("/merchant/list")
-        public R<Page<MaTechnicianMerchantListVO>> merchantList
-        (Page < MaTechnicianMerchantListVO > page, MaTechnicianMerchantQueryDTO dto){
-            try {
-                return R.ok(maTechnicianService.selectMerchantList(page, dto));
-            } catch (Exception e) {
-                e.printStackTrace();
-                throw new RuntimeException(e);
-            }
+    /**
+     * 查询商户列表
+     *
+     * @param page 分页参数
+     * @param dto  商户查询DTO
+     * @return Page 商户分页列表
+     */
+    @ApiOperation("后台查询商户列表")
+    @PreAuthorize("@ss.hasPermi('technician:technician:list')")
+    @GetMapping("/merchant/list")
+    public R<Page<MaTechnicianMerchantListVO>> merchantList
+    (Page<MaTechnicianMerchantListVO> page, MaTechnicianMerchantQueryDTO dto) {
+        try {
+            return R.ok(maTechnicianService.selectMerchantList(page, dto));
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
         }
+    }
 
-        /**
-         * 查询商户详情
-         *
-         * @param id 商户ID
-         * @return R<MaTechnicianMerchantDetailVO> 商户详情
-         */
-        @ApiOperation("后台查询商户详情")
-        @PreAuthorize("@ss.hasPermi('technician:technician:query')")
-        @GetMapping("/merchant/detail/{id}")
-        public R<MaTechnicianMerchantDetailVO> merchantDetail (@PathVariable("id") Long id){
-            try {
-                return R.ok(maTechnicianService.selectMerchantDetail(id));
-            } catch (Exception e) {
-                e.printStackTrace();
-                throw new RuntimeException(e);
-            }
+    /**
+     * 查询商户详情
+     *
+     * @param id 商户ID
+     * @return R<MaTechnicianMerchantDetailVO> 商户详情
+     */
+    @ApiOperation("后台查询商户详情")
+    @PreAuthorize("@ss.hasPermi('technician:technician:query')")
+    @GetMapping("/merchant/detail/{id}")
+    public R<MaTechnicianMerchantDetailVO> merchantDetail(@PathVariable("id") Long id) {
+        try {
+            return R.ok(maTechnicianService.selectMerchantDetail(id));
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
         }
+    }
 
-        /**
-         * 查看商户证照
-         *
-         * @param id 商户ID
-         * @return R<MaTechnicianCertificateVO> 商户证照
-         */
-        @ApiOperation("后台查看商户证照")
-        @PreAuthorize("@ss.hasPermi('technician:technician:query')")
-        @GetMapping("/merchant/{id}/certificate")
-        public R<MaTechnicianCertificateVO> merchantCertificate (@PathVariable("id") Integer id){
-            try {
-                return R.ok(maTechnicianService.selectMerchantCertificate(id));
-            } catch (Exception e) {
-                e.printStackTrace();
-                throw new RuntimeException(e);
-            }
+    /**
+     * 查看商户证照
+     *
+     * @param id 商户ID
+     * @return R<MaTechnicianCertificateVO> 商户证照
+     */
+    @ApiOperation("后台查看商户证照")
+    @PreAuthorize("@ss.hasPermi('technician:technician:query')")
+    @GetMapping("/merchant/{id}/certificate")
+    public R<MaTechnicianCertificateVO> merchantCertificate(@PathVariable("id") Integer id) {
+        try {
+            return R.ok(maTechnicianService.selectMerchantCertificate(id));
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
         }
+    }
 
-        /**
-         * 修改技师
-         */
-        @PreAuthorize("@ss.hasPermi('technician:technician:edit')")
-        @Log(title = "技师", businessType = BusinessType.UPDATE)
-        @PutMapping
-        public AjaxResult edit (@RequestBody MaTechnicianAppAddVo maTechnicianAppAddVo){
-            return toAjax(maTechnicianService.updateMaTechnician(maTechnicianAppAddVo));
-        }
+    /**
+     * 修改技师
+     */
+    @PreAuthorize("@ss.hasPermi('technician:technician:edit')")
+    @Log(title = "技师", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody MaTechnicianAppAddVo maTechnicianAppAddVo) {
+        return toAjax(maTechnicianService.updateMaTechnician(maTechnicianAppAddVo));
+    }
 
-        /**
-         * 删除技师
-         */
-        @PreAuthorize("@ss.hasPermi('technician:technician:remove')")
-        @Log(title = "技师", businessType = BusinessType.DELETE)
-        @DeleteMapping("/{ids}")
-        public AjaxResult remove (@PathVariable Long[]ids){
-            return toAjax(maTechnicianService.deleteMaTechnicianByIds(ids));
-        }
+    /**
+     * 删除技师
+     */
+    @PreAuthorize("@ss.hasPermi('technician:technician:remove')")
+    @Log(title = "技师", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(maTechnicianService.deleteMaTechnicianByIds(ids));
+    }
 
-        /**
-         * 1. 获取服务类目列表 (对应图1、图3)
-         */
-        @GetMapping("/getServiceCategoryList")
-        public AjaxResult getServiceCategoryList () {
-            List<ServiceCategory> list = serviceCategoryService.listH5ServiceCategory();
-            return AjaxResult.success(list);
-        }
+    /**
+     * 1. 获取服务类目列表 (对应图1、图3)
+     */
+    @GetMapping("/getServiceCategoryList")
+    public AjaxResult getServiceCategoryList() {
+        List<ServiceCategory> list = serviceCategoryService.listH5ServiceCategory();
+        return AjaxResult.success(list);
+    }
 
-        /**
-         * 1. 获取技能列表 (对应图1、图3)
-         * 支持 Tab 切换:all(全部), active(已开通), applying(申请中), rejected(驳回)
-         */
-        @PostMapping("/getSkillList")
-        public TableDataInfo getSkillList (@RequestBody MaProjectGetVo req){
-            startPage();
-            List<MaProject> list = maTechnicianService.selectMaTechnicianListBy(req.getUserId(), req.getAuditStatus());
-            if (ObjectUtils.isEmpty(list)) {
-                List<Project> projectslist = maTechnicianService.selectTechnicianListBy(req.getTypeId());
-                return getDataTable(projectslist);
-            } else {
-                return getDataTable(list);
-            }
+    /**
+     * 1. 获取技能列表 (对应图1、图3)
+     * 支持 Tab 切换:all(全部), active(已开通), applying(申请中), rejected(驳回)
+     */
+    @PostMapping("/getSkillList")
+    public TableDataInfo getSkillList(@RequestBody MaProjectGetVo req) {
+        startPage();
+        List<MaProject> list = maTechnicianService.selectMaTechnicianListBy(req.getUserId(), req.getAuditStatus());
+        if (ObjectUtils.isEmpty(list)) {
+            List<Project> projectslist = maTechnicianService.selectTechnicianListBy(req.getTypeId());
+            return getDataTable(projectslist);
+        } else {
+            return getDataTable(list);
         }
+    }
 
-        /**
-         * 查询未开通的服务项目列表
-         *
-         * @param req
-         * @return
-         */
-        @PostMapping("/getNotApplyList")
-        public Result<?> getNotApplyList (@RequestBody MaProjectGetVo req){
+    /**
+     * 查询未开通的服务项目列表
+     *
+     * @param req
+     * @return
+     */
+    @PostMapping("/getNotApplyList")
+    public Result<?> getNotApplyList(@RequestBody MaProjectGetVo req) {
 
-            return Result.ok(maTechnicianService.getNotApplyList(req.getUserId(), req.getTypeId()));
+        return Result.ok(maTechnicianService.getNotApplyList(req.getUserId(), req.getTypeId()));
 
-        }
+    }
 
-        /**
-         * 申请开通新服务
-         */
-        @PostMapping("/applyForService")
-        public AjaxResult applyForService (@RequestBody MaProjectSaveDto dto){
+    /**
+     * 申请开通新服务
+     */
+    @PostMapping("/applyForService")
+    public AjaxResult applyForService(@RequestBody MaProjectSaveDto dto) {
+
+        return toAjax(maTechnicianService.applyForService(dto));
+    }
 
-            return toAjax(maTechnicianService.applyForService(dto));
+    /**
+     * 重新申请开通新服务
+     *
+     * @param req
+     * @return
+     */
+    @PostMapping("/updateApply")
+    public Result<?> updateApply(@RequestBody MaProjectUpdateDto req) {
+        if (StringUtils.isNotEmpty(req.getProjectId()) && StringUtils.isNotEmpty(req.getApplyReason())) {
+            LambdaUpdateWrapper<MaProject> updateWrapper = new LambdaUpdateWrapper<>();
+            updateWrapper.eq(MaProject::getId, req.getProjectId());
+            updateWrapper.set(MaProject::getApplyReason, req.getApplyReason());
+            updateWrapper.set(MaProject::getAuditStatus, 0);
+            maProjectService.update(updateWrapper);
         }
+        return Result.ok("重新申请成功,提交到审核阶段");
 
-        /**
-         * 重新申请开通新服务
-         *
-         * @param req
-         * @return
-         */
-        @PostMapping("/updateApply")
-        public Result<?> updateApply (@RequestBody MaProjectUpdateDto req){
-            if (StringUtils.isNotEmpty(req.getProjectId()) && StringUtils.isNotEmpty(req.getApplyReason())) {
+    }
+
+    /**
+     * 申请下架,删除服务项目,编辑售价价格
+     *
+     * @param req
+     * @return
+     */
+    @PostMapping("/updateMaProject")
+    public Result<?> updateMaProject(@RequestBody MaProjectUpdateDto req) {
+        String message = "";
+        if (StringUtils.isNotEmpty(req.getProjectId())) {
+            if (req.getIsDelete()) {
+                LambdaUpdateWrapper<MaProject> updateWrapper = new LambdaUpdateWrapper<>();
+                updateWrapper.eq(MaProject::getProjectId, req.getProjectId());
+                updateWrapper.set(MaProject::getIsDelete, 1);
+                maProjectService.update(updateWrapper);
+                message = "删除成功";
+            }
+            if (req.getIsPass()) {
                 LambdaUpdateWrapper<MaProject> updateWrapper = new LambdaUpdateWrapper<>();
                 updateWrapper.eq(MaProject::getId, req.getProjectId());
-                updateWrapper.set(MaProject::getApplyReason, req.getApplyReason());
-                updateWrapper.set(MaProject::getAuditStatus, 0);
+                updateWrapper.set(MaProject::getProjectIsEnable, 1);
                 maProjectService.update(updateWrapper);
+                message = "申请下架成功";
             }
-            return Result.ok("重新申请成功,提交到审核阶段");
+            if (req.getProjectCurrentPrice() != null) {
 
-        }
+                LambdaUpdateWrapper<MaProject> updateWrapper = new LambdaUpdateWrapper<>();
+                updateWrapper.eq(MaProject::getId, req.getProjectId());
+                updateWrapper.set(MaProject::getProjectCurrentPrice, req.getProjectCurrentPrice());
+                maProjectService.update(updateWrapper);
+                message = "修改价格完成";
 
-        /**
-         * 申请下架,删除服务项目,编辑售价价格
-         *
-         * @param req
-         * @return
-         */
-        @PostMapping("/updateMaProject")
-        public Result<?> updateMaProject (@RequestBody MaProjectUpdateDto req){
-            String message = "";
-            if (StringUtils.isNotEmpty(req.getProjectId())) {
-                if (req.getIsDelete()) {
-                    LambdaUpdateWrapper<MaProject> updateWrapper = new LambdaUpdateWrapper<>();
-                    updateWrapper.eq(MaProject::getId, req.getProjectId());
-                    updateWrapper.set(MaProject::getIsDelete, 1);
-                    maProjectService.update(updateWrapper);
-                    message = "删除成功";
-                }
-                if (req.getIsPass()) {
-                    LambdaUpdateWrapper<MaProject> updateWrapper = new LambdaUpdateWrapper<>();
-                    updateWrapper.eq(MaProject::getId, req.getProjectId());
-                    updateWrapper.set(MaProject::getProjectIsEnable, 1);
-                    maProjectService.update(updateWrapper);
-                    message = "申请下架成功";
-                }
-                if (req.getProjectCurrentPrice() != null) {
-
-                    LambdaUpdateWrapper<MaProject> updateWrapper = new LambdaUpdateWrapper<>();
-                    updateWrapper.eq(MaProject::getId, req.getProjectId());
-                    updateWrapper.set(MaProject::getProjectCurrentPrice, req.getProjectCurrentPrice());
-                    maProjectService.update(updateWrapper);
-                    message = "修改价格完成";
-
-                }
             }
-            return Result.ok(message);
-        }
-        /**
-         * 商户入住信息
-         *
-         * @param userId
-         * @return
-         */
-
-        @GetMapping("/getTechnicianList")
-        public Result<?> getTechnicianList (@RequestParam(value = "userId") Long userId){
-            return Result.ok(maTechnicianService.getTechnicianList(userId));
         }
+        return Result.ok(message);
+    }
 
+    /**
+     * 商户入住信息
+     *
+     * @param userId
+     * @return
+     */
+
+    @GetMapping("/getTechnicianList")
+    public Result<?> getTechnicianList(@RequestParam(value = "userId") Long userId) {
+        return Result.ok(maTechnicianService.getTechnicianList(userId));
     }
+
+}

+ 1 - 8
nightFragrance-admin/src/main/java/com/ylx/web/controller/massage/TCommentUserController.java

@@ -1,26 +1,19 @@
 package com.ylx.web.controller.massage;
 
 import com.alibaba.fastjson.JSON;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import com.ylx.common.core.controller.BaseController;
 import com.ylx.common.core.domain.R;
 import com.ylx.common.core.domain.model.WxLoginUser;
 import com.ylx.common.utils.SecurityUtils;
-import com.ylx.massage.domain.TComment;
-import com.ylx.massage.domain.TCommentUser;
 import com.ylx.massage.service.TCommentUserAuditService;
 import com.ylx.massage.service.TCommentUserService;
+import com.ylx.order.domain.TCommentUser;
 import com.ylx.system.domain.vo.ReviewUserCommentsDto;
 import com.ylx.system.domain.vo.BatchAuditCommentsDto;
 import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
 import io.swagger.annotations.ApiOperation;
-import org.apache.commons.lang3.StringUtils;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;

+ 2 - 1
nightFragrance-massage/src/main/java/com/ylx/fareSetting/controller/MaProjectFareSettingController.java

@@ -7,6 +7,7 @@ import com.ylx.fareSetting.service.IMaProjectFareSettingService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -24,7 +25,7 @@ public class MaProjectFareSettingController {
     @Resource
     private IMaProjectFareSettingService maProjectFareSettingService;
 
-
+    @PreAuthorize("@customerAuth.isCustomer()")
     @PostMapping("/calculate")
     @ApiOperation("下单前计算打车费")
     public R<FareCalculateResultVO> calculate(@Validated @RequestBody FareCalculateDTO dto) {

+ 51 - 20
nightFragrance-massage/src/main/java/com/ylx/massage/domain/CityOperationApplication.java

@@ -6,6 +6,7 @@ import java.util.Date;
 import com.baomidou.mybatisplus.annotation.*;
 import com.baomidou.mybatisplus.extension.activerecord.Model;
 import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.models.auth.In;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
@@ -21,36 +22,67 @@ import java.io.Serializable;
 @Data
 @EqualsAndHashCode(callSuper = false)
 @Accessors(chain = true)
-@TableName(value = "city_operation_application",autoResultMap = true)
-public class CityOperationApplication  implements Serializable {
-//主键ID
-@TableId(value = "id", type = IdType.AUTO)
+@TableName(value = "city_operation_application", autoResultMap = true)
+public class CityOperationApplication implements Serializable {
+    //主键ID
+    @TableId(value = "id", type = IdType.AUTO)
     private Long id;
-//城市编码 (例如: 110000)
-@TableField("city_code")
+    /**
+     * 省级行政区编码 (如: 110000)
+     */
+    @TableField("province_code")
+    private String provinceCode;
+
+    /**
+     * 省级行政区名称 (如: 北京市)
+     */
+    @TableField("province_name")
+    private String provinceName;
+
+    /**
+     * 地级市编码 (如: 110100)
+     */
+    @TableField("city_code")
     private String cityCode;
-//城市名称 (冗余字段,方便查询,例如: 北京市)
-@TableField("city_name")
+
+    /**
+     * 地级市名称 (如: 北京市)
+     */
+    @TableField("city_name")
     private String cityName;
-//运营中心ID
-@TableField("operation_center_id")
-    private Long operationCenterId;
-//运营中心名称
-@TableField("operation_center_name")
+
+    /**
+     * 区/县编码 (如: 110101)
+     */
+    @TableField("district_code")
+    private String districtCode;
+
+    /**
+     * 区/县名称 (如: 东城区)
+     */
+    @TableField("district_name")
+    private String districtName;
+
+    //运营中心ID
+    @TableField("operation_center_id")
+    private Integer operationCenterId;
+    //运营中心名称
+    @TableField("operation_center_name")
     private String operationCenterName;
-//实际审批通过时间
-@TableField("actual_approval_time")
+    //实际审批通过时间
+    @TableField("actual_approval_time")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
     private Date actualApprovalTime;
-//申请原因 (限制500字以内)
+    //申请原因 (限制500字以内)
     @TableField("apply_reason")
     private String applyReason;
 
-//状态 (0:待审核, 1:已通过, 2:已驳回)
+    //状态 (0:待审核, 1:已通过, 2:已驳回)
     @TableField("status")
     private Integer status;
-//商户ID
+    //商户ID
     @TableField("merchant_id")
-    private String merchantId;
+    private Integer merchantId;
     /**
      * 创建时间
      */
@@ -83,6 +115,5 @@ public class CityOperationApplication  implements Serializable {
     private Integer isDelete;
 
 
-
 }
 

+ 7 - 2
nightFragrance-massage/src/main/java/com/ylx/massage/domain/CommentUserAudit.java

@@ -32,9 +32,9 @@ public class CommentUserAudit implements Serializable {
     private String commentId;
 
     /**
-     * 订单
+     * 订单id
      */
-    private String orderNo;
+    private String orderId;
 
     /**
      * 评论内容
@@ -81,4 +81,9 @@ public class CommentUserAudit implements Serializable {
      */
     @TableLogic
     private Integer isDelete;
+
+    /**
+     * 是否上架:1=上架,0=下架
+     */
+    private Integer isPublished;
 }

+ 18 - 5
nightFragrance-massage/src/main/java/com/ylx/massage/domain/MaProject.java

@@ -2,6 +2,8 @@ package com.ylx.massage.domain;
 
 import java.math.BigDecimal;
 
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import com.ylx.common.annotation.Excel;
@@ -17,7 +19,8 @@ import java.util.Date;
  */
 @ApiModel(value = "MaProject", description = "服务项目")
 @Data
-public class MaProject extends BaseEntity {
+@TableName("Ma_Project")
+public class MaProject {
     private static final long serialVersionUID = 1L;
 
     /**
@@ -30,7 +33,7 @@ public class MaProject extends BaseEntity {
      */
     @Excel(name = "项目ID")
     @ApiModelProperty("项目ID")
-    private String projectId;
+    private Long projectId;
     /**
      * 项目名称
      */
@@ -132,7 +135,7 @@ public class MaProject extends BaseEntity {
      */
     @Excel(name = "商户ID")
     @ApiModelProperty("商户ID")
-    private String merchantId;
+    private Long merchantId;
     /**
      * 审核状态:0-待审核,1-审核通过,2-审核驳回
      */
@@ -144,7 +147,7 @@ public class MaProject extends BaseEntity {
      */
     @Excel(name = "创建人")
     @ApiModelProperty("创建人")
-    private Long createUser;
+    private Long createBy;
     /** 申请时间 */
     @Excel(name = "申请时间")
     @ApiModelProperty("申请时间")
@@ -154,7 +157,7 @@ public class MaProject extends BaseEntity {
      */
     @Excel(name = "修改人")
     @ApiModelProperty("修改人")
-    private Long updateUser;
+    private Long updateBy;
 
     /**
      * 是否删除(0否1是)
@@ -162,6 +165,16 @@ public class MaProject extends BaseEntity {
     @ApiModelProperty("是否删除(0否1是)")
     @Excel(name = "是否删除(0否1是)")
     private Long isDelete;
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+    /**
+     * 更新时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
 
 
 }

+ 1 - 1
nightFragrance-massage/src/main/java/com/ylx/massage/domain/dto/MaProjectSaveDto.java

@@ -10,7 +10,7 @@ public class MaProjectSaveDto {
     /**
      * 商户id
      */
-    private String userId;
+    private Long userId;
     /**
      * 商户手机号
      */

+ 7 - 2
nightFragrance-massage/src/main/java/com/ylx/massage/domain/dto/MaProjectUpdateDto.java

@@ -9,7 +9,10 @@ import java.util.List;
 
 @Data
 public class MaProjectUpdateDto {
-
+    /**
+     * 商家id
+     */
+    private Long merchantId;
     /**
      * 项目id列表
      */
@@ -26,6 +29,8 @@ public class MaProjectUpdateDto {
      * 是否删除
      */
     private Boolean isDelete;
-    /** 我的售价 */
+    /**
+     * 我的售价
+     */
     private BigDecimal projectCurrentPrice;
 }

+ 21 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/dto/RefuseOrderReqDTO.java

@@ -0,0 +1,21 @@
+package com.ylx.massage.domain.dto;
+
+import lombok.Data;
+
+@Data
+public class RefuseOrderReqDTO {
+    /**
+     * 技师ID
+     */
+    private Long techId;
+
+    /**
+     * 订单ID
+     */
+    private Long orderId;
+
+    /**
+     * 拒单原因(必填)
+     */
+    private String refuseReason;
+}

+ 31 - 6
nightFragrance-massage/src/main/java/com/ylx/massage/domain/vo/MaTechnicianAppAddVo.java

@@ -1,5 +1,6 @@
 package com.ylx.massage.domain.vo;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.ylx.common.annotation.Excel;
@@ -68,14 +69,38 @@ public class MaTechnicianAppAddVo {
     private String tePhone;
 
     /**
-     * 合作意向城市
+     * 省级行政区编码 (如: 110000)
      */
-    @Excel(name = "合作意向城市")
-    @ApiModelProperty("合作意向城市")
-    private String teAddress;
-    @ApiModelProperty("合作意向城市Code")
-    private String teAreaCode;
+    private String provinceCode;
 
+    /**
+     * 省级行政区名称 (如: 北京市)
+     */
+    private String provinceName;
+
+    /**
+     * 地级市编码 (如: 110100)
+     */
+    private String cityCode;
+
+    /**
+     * 地级市名称 (如: 北京市)
+     */
+    private String cityName;
+
+    /**
+     * 区/县编码 (如: 110101)
+     */
+    private String districtCode;
+
+    /**
+     * 区/县名称 (如: 东城区)
+     */
+    private String districtName;
+    //运营中心ID
+    private Integer operationCenterId;
+    //运营中心名称
+    private String operationCenterName;
     /**
      * 服务标签(1:按摩推拿 2:陪玩)
      */

+ 26 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/enums/OrderTipEnum.java

@@ -0,0 +1,26 @@
+package com.ylx.massage.enums;
+
+public enum OrderTipEnum {
+    // 1. 订单已被抢走 → 重复接单
+    REPEAT_ORDER("操作失败,请重试刷新当前页面"),
+
+    // 2. 时间冲突(你问的这个)
+    TIME_CONFLICT("当前订单服务开始时间与已有订单时间冲突,不支持接待"),
+
+    // 3. 技师休息中,确认接单
+    REST_CONFIRM("您当前处于休息中,接单后将切换为上线状态,是否确认接单"),
+
+    // 4. 接单成功
+    ALREADY_ACCEPT("已接单");
+
+    // 提示文案
+    private final String tip;
+
+    OrderTipEnum(String tip) {
+        this.tip = tip;
+    }
+
+    public String getTip() {
+        return tip;
+    }
+}

+ 1 - 2
nightFragrance-massage/src/main/java/com/ylx/massage/mapper/TCommentUserMapper.java

@@ -3,9 +3,8 @@ package com.ylx.massage.mapper;
 import java.util.List;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.apache.ibatis.annotations.Param;
-import com.ylx.massage.domain.TCommentUser;
+import com.ylx.order.domain.TCommentUser;
 
 /**
  * 用户评论表(TCommentUser)表数据库访问层

+ 23 - 1
nightFragrance-massage/src/main/java/com/ylx/massage/service/IMaTechnicianService.java

@@ -86,7 +86,7 @@ public interface IMaTechnicianService extends IService<MaTechnician> {
      * @param loginUser 当前登录用户
      * @return 上传结果
      */
-    Integer uploadMerchantContract(Integer id, Map<String,Object> file, LoginUser loginUser);
+    Integer uploadMerchantContract(Integer id, Map<String, Object> file, LoginUser loginUser);
 
     /**
      * 后台查询商户入驻审核列表
@@ -206,6 +206,28 @@ public interface IMaTechnicianService extends IService<MaTechnician> {
      */
     List<WaitOrderDTO> listWaitOrder(WaitOrderQueryDTO query);
 
+    /**
+     * 接单
+     *
+     * @param req
+     * @return
+     */
+    String acceptOrder(AcceptOrderReqDTO req);
+    /**
+     * 技师接单确认接单
+     *
+     * @param techId
+     * @param orderId
+     * @return
+     */
+    String confirmRestAccept(Long techId, Long orderId);
+    /**
+     * 技师拒绝接单
+     *
+     * @param req
+     * @return
+     */
+    void refuseOrder(RefuseOrderReqDTO req);
     /**
      * 技师列表
      *

+ 8 - 2
nightFragrance-massage/src/main/java/com/ylx/massage/service/TCommentUserService.java

@@ -2,8 +2,8 @@ package com.ylx.massage.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ylx.common.core.domain.model.WxLoginUser;
-import com.ylx.lottery.domain.vo.LocalActivityTableVO;
-import com.ylx.massage.domain.TCommentUser;
+import com.ylx.order.domain.TCommentUser;
+import com.ylx.order.domain.dto.OrderCommentDTO;
 
 import java.util.List;
 
@@ -32,5 +32,11 @@ public interface TCommentUserService extends IService<TCommentUser> {
      */
      List<TCommentUser> selectAll(TCommentUser tCommentUser);
 
+    /**
+     * 提交评论(入库+生成审核记录)
+     * @param dto 评论DTO
+     */
+    void submitComment(OrderCommentDTO dto);
+
 }
 

+ 3 - 3
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/MaProjectServiceImpl.java

@@ -87,13 +87,13 @@ public class MaProjectServiceImpl extends ServiceImpl<MaProjectMapper, MaProject
 
         if (maProjectVo.getId() == null) {
             // 新增
-            maProject.setCreateUser(loginUser.getUser().getUserId());
-            maProject.setUpdateUser(loginUser.getUser().getUserId());
+            maProject.setCreateBy(loginUser.getUser().getUserId());
+            maProject.setUpdateBy(loginUser.getUser().getUserId());
             maProject.setCreateTime(DateUtils.getNowDate());
             return maProjectMapper.insertMaProject(maProject);
         } else {
             // 修改
-            maProject.setUpdateUser(loginUser.getUser().getUserId());
+            maProject.setUpdateBy(loginUser.getUser().getUserId());
             return maProjectMapper.updateMaProject(maProject);
         }
 

+ 133 - 35
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/MaTechnicianServiceImpl.java

@@ -6,6 +6,7 @@ import java.time.Duration;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -26,6 +27,7 @@ import com.ylx.massage.controller.CityOperationApplicationController;
 import com.ylx.massage.domain.*;
 import com.ylx.massage.domain.dto.*;
 import com.ylx.massage.domain.vo.*;
+import com.ylx.massage.enums.OrderTipEnum;
 import com.ylx.massage.enums.ProjectCategoryEnum;
 import com.ylx.massage.enums.TechnicianStatusEnum;
 import com.ylx.massage.mapper.*;
@@ -116,7 +118,8 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
     private MerchantApplyFileMapper merchantApplyFileMapper;
     @Resource
     private TOrderMapper orderMapper;
-
+    @Resource
+    private  CityOperationApplicationMapper cityOperationApplicationMapper;
 
 
     /**
@@ -143,11 +146,24 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
         queryWrapper.eq(MaTechnician::getCOpenid, req.getCOpenid());
         MaTechnician maTechnician1 = maTechnicianMapper.selectOne(queryWrapper);
         if (maTechnician1 == null) {
-           throw new RuntimeException("商户不存在");
+            throw new RuntimeException("商户不存在");
         }
         LambdaUpdateWrapper<MaTechnician> updateWrapper = new LambdaUpdateWrapper<>();
         updateWrapper.eq(MaTechnician::getId, maTechnician1.getId());
         maTechnicianMapper.update(maTechnician, updateWrapper);
+        CityOperationApplication cityOperationApplication = new CityOperationApplication();
+        cityOperationApplication.setMerchantId(maTechnician1.getId());
+        cityOperationApplication.setOperationCenterId(req.getOperationCenterId());
+        cityOperationApplication.setProvinceCode(req.getProvinceCode());
+        cityOperationApplication.setProvinceName(req.getProvinceName());
+        cityOperationApplication.setCityCode(req.getCityCode());
+        cityOperationApplication.setCityName(req.getCityName());
+        cityOperationApplication.setDistrictCode(req.getDistrictCode());
+        cityOperationApplication.setDistrictName(req.getDistrictName());
+        cityOperationApplication.setOperationCenterName(req.getOperationCenterName());
+        cityOperationApplication.setCreateBy(maTechnician1.getId().toString());
+        cityOperationApplication.setUpdateBy(maTechnician1.getId().toString());
+        cityOperationApplicationMapper.insert(cityOperationApplication);
 
     }
 
@@ -394,13 +410,13 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
      * 后台上传商户合同文件
      *
      * @param id        商户ID
-     * @param file      合同文件
+     * @param
      * @param loginUser 当前登录用户
      * @return 上传结果
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public Integer uploadMerchantContract(Integer id, Map<String,Object> map, LoginUser loginUser) {
+    public Integer uploadMerchantContract(Integer id, Map<String, Object> map, LoginUser loginUser) {
         if (id == null) {
             throw new ServiceException("商户ID不能为空");
         }
@@ -848,11 +864,16 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
         query.eq(MaProject::getMerchantType, typeId);
         List<MaProject> maProjectList = maProjectMapper.selectList(query);
         // 获取已申请技能ID集合
-        List<String> projectIdList = maProjectList.stream().map(MaProject::getProjectId).collect(Collectors.toList());
-        LambdaQueryWrapper<Project> query1 = new LambdaQueryWrapper<>();
-        query1.eq(Project::getType, typeId);
-        query1.notIn(Project::getId, projectIdList);
-        return projectMapper.selectList(query1);
+        List<Long> projectIdList = maProjectList.stream().map(MaProject::getProjectId).collect(Collectors.toList());
+        if (projectIdList.size() == 0) {
+            LambdaQueryWrapper<Project> query1 = new LambdaQueryWrapper<>();
+            query1.eq(Project::getType, typeId);
+            return projectMapper.selectList(query1);
+        }
+        LambdaQueryWrapper<Project> query2 = new LambdaQueryWrapper<>();
+        query2.eq(Project::getType, typeId);
+        query2.notIn(Project::getId, projectIdList);
+        return projectMapper.selectList(query2);
     }
 
     /**
@@ -901,7 +922,7 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
         List<Project> projectList = projectMapper.selectList(query);
         for (Project project : projectList) {
             MaProject maProject = new MaProject();
-            maProject.setProjectId(project.getId().toString());
+            maProject.setProjectId(project.getId().longValue());
             maProject.setProjectName(project.getTitle());
             maProject.setProjectDescribe(project.getDetail());
             maProject.setProjectDuration(project.getStandardDuration());
@@ -909,10 +930,10 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
             maProject.setProjectMaxPrice(project.getPriceMax());
             maProject.setProjectLowestPrice(project.getPriceMin());
             maProject.setCreateBy(dto.getUserId());
+            maProject.setUpdateBy(dto.getUserId());
             maProject.setMerchantId(dto.getUserId());
             maProject.setApplyTime(DateUtils.getNowDate());
             maProject.setMerchantPhone(dto.getMerchantPhone());
-            maProject.setCreateTime(DateUtils.getNowDate());
             maProjectMapper.insert(maProject);
         }
     }
@@ -1210,7 +1231,7 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
         queryWrapper.eq(TOrder::getStatus, OrderStatusEnum.WAIT_JD.getCode());
         // 1.查询所有待派未接单订单(status=待接单)
         List<TOrder> allWaitOrder = orderMapper.selectList(queryWrapper);
-        if(CollectionUtils.isEmpty(allWaitOrder)){
+        if (CollectionUtils.isEmpty(allWaitOrder)) {
             return Collections.emptyList();
         }
 
@@ -1241,9 +1262,82 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
                        .sorted(Comparator.comparing(WaitOrderDTO::getDistanceMeter))
                        .collect(Collectors.toList());
     }
+
+    /**
+     * 接单
+     *
+     * @param req
+     * @return
+     */
+    @Override
+    public String acceptOrder(AcceptOrderReqDTO req) {
+        Long techId = req.getTechId();
+        Long orderId = req.getOrderId();
+        //【校验1:订单是否已被其他技师接单】
+        TOrder order = orderMapper.selectById(orderId);
+        if (OrderStatusEnum.RECEIVED_ORDER.getCode().equals(order.getStatus())) {
+            return OrderTipEnum.REPEAT_ORDER.getTip();
+        }
+        //【校验2:时间冲突校验(该技师已有已接单订单)】
+        boolean isTimeConflict = checkOrderTimeConflict(techId, order);
+        if (isTimeConflict) {
+            String tip = String.format(OrderTipEnum.TIME_CONFLICT.getTip(),
+                    order.getStartTime().format(DateTimeFormatter.ofPattern("MM月dd日HH:mm")),
+                    order.getCompletedTime().format(DateTimeFormatter.ofPattern("MM月dd日HH:mm")));
+            return tip;
+        }
+        //【校验3:技师休息状态】
+        MaTechnician tech = maTechnicianMapper.selectById(techId);
+        if (TechnicianStatusEnum.RESTING.getCode().equals(tech.getPostState())) {
+            return OrderTipEnum.REST_CONFIRM.getTip();
+        }
+        // 正常接单,绑定技师ID到订单
+        doAcceptOrder(techId, orderId);
+        return OrderTipEnum.ALREADY_ACCEPT.getTip();
+    }
+    /**
+     * 技师接单确认接单
+     *
+     * @param techId
+     * @param orderId
+     * @return
+     */
+    @Override
+    public String confirmRestAccept(Long techId, Long orderId){
+        LambdaUpdateWrapper<MaTechnician> update = new LambdaUpdateWrapper<>();
+        update.eq(MaTechnician::getId, techId);
+        update.set(MaTechnician::getPostState, TechnicianStatusEnum.ONLINE.getCode());
+        maTechnicianMapper.update(null, update);
+        doAcceptOrder(techId, orderId);
+        return OrderTipEnum.ALREADY_ACCEPT.getTip();
+    }
+    /**
+     * 技师拒绝接单
+     *
+     * @param req
+     * @return
+     */
+    @Override
+    public void refuseOrder(RefuseOrderReqDTO req){
+        LambdaUpdateWrapper<TOrder> update = new LambdaUpdateWrapper<>();
+        update.eq(TOrder::getId, req.getOrderId());
+        update.set(TOrder::getStatus, OrderStatusEnum.REFUSE.getCode());
+        update.set(TOrder::getRejectedReason, req.getRefuseReason());
+        orderMapper.update(null, update);
+        //拒单后订单重回待接单池,其他技师可刷到
+        LambdaUpdateWrapper<TOrder> update2 = new LambdaUpdateWrapper<>();
+        update2.eq(TOrder::getId, req.getOrderId());
+        update2.set(TOrder::getStatus, OrderStatusEnum.WAIT_JD.getCode());
+        update2.set(TOrder::getMerchantId, "");
+        update2.set(TOrder::getRejectedReason, "");
+        orderMapper.update(null, update2);
+    }
     // =================工具方法=================
-    /** Haversine 计算经纬度距离 返回米 */
-    private BigDecimal calcDistance(BigDecimal lat1, BigDecimal lng1, BigDecimal lat2, BigDecimal lng2){
+
+    /**
+     * Haversine 计算经纬度距离 返回米
+     */
+    private BigDecimal calcDistance(BigDecimal lat1, BigDecimal lng1, BigDecimal lat2, BigDecimal lng2) {
         // 球面距离计算公式,地球半径6371000米
         // 可使用BigDecimal三角函数或数据库函数优化
         double latRad1 = Math.toRadians(lat1.doubleValue());
@@ -1253,31 +1347,33 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
 
         double dLat = latRad2 - latRad1;
         double dLng = lngRad2 - lngRad1;
-        double a = Math.pow(Math.sin(dLat/2),2)
-                           + Math.cos(latRad1)*Math.cos(latRad2)
-                                     * Math.pow(Math.sin(dLng/2),2);
-        double dis = 2 * 6371000 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
-        return BigDecimal.valueOf(dis).setScale(2,BigDecimal.ROUND_HALF_UP);
+        double a = Math.pow(Math.sin(dLat / 2), 2)
+                           + Math.cos(latRad1) * Math.cos(latRad2)
+                                     * Math.pow(Math.sin(dLng / 2), 2);
+        double dis = 2 * 6371000 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+        return BigDecimal.valueOf(dis).setScale(2, BigDecimal.ROUND_HALF_UP);
     }
 
-    private String getShortProjectName(String name){
-        if(name != null && name.length()>10){
-            return name.substring(0,8)+"...";
+    private String getShortProjectName(String name) {
+        if (name != null && name.length() > 10) {
+            return name.substring(0, 8) + "...";
         }
         return name;
     }
 
-    private String formatDistance(BigDecimal distanceMeter){
-        BigDecimal km = distanceMeter.divide(new BigDecimal(1000),2,BigDecimal.ROUND_HALF_UP);
-        if(km.compareTo(BigDecimal.ONE)>0){
-            return km+"km";
-        }else{
-            return distanceMeter.intValue()+"m";
+    private String formatDistance(BigDecimal distanceMeter) {
+        BigDecimal km = distanceMeter.divide(new BigDecimal(1000), 2, BigDecimal.ROUND_HALF_UP);
+        if (km.compareTo(BigDecimal.ONE) > 0) {
+            return km + "km";
+        } else {
+            return distanceMeter.intValue() + "m";
         }
     }
 
-    /** 校验技师已有订单时间冲突(只查该技师已接单数据) */
-    private boolean checkOrderTimeConflict(Long techId, TOrder newOrder){
+    /**
+     * 校验技师已有订单时间冲突(只查该技师已接单数据)
+     */
+    private boolean checkOrderTimeConflict(Long techId, TOrder newOrder) {
         LambdaQueryWrapper<TOrder> query = new LambdaQueryWrapper<>();
         query.eq(TOrder::getMerchantId, techId);
         query.eq(TOrder::getStatus, OrderStatusEnum.RECEIVED_ORDER.getCode());
@@ -1286,20 +1382,22 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
         List<TOrder> acceptedOrders = orderMapper.selectList(query);
         LocalDate newOrderDate = newOrder.getStartTime().toLocalDate();
         LocalDateTime newStart = newOrder.getStartTime();
-        for(TOrder old:acceptedOrders){
-            if(!newOrderDate.isEqual(old.getCompletedTime().toLocalDate())){
+        for (TOrder old : acceptedOrders) {
+            if (!newOrderDate.isEqual(old.getCompletedTime().toLocalDate())) {
                 continue;
             }
             LocalDateTime oldEnd = old.getCompletedTime();
-            if(newStart.isBefore(oldEnd) || newStart.isEqual(oldEnd)){
+            if (newStart.isBefore(oldEnd) || newStart.isEqual(oldEnd)) {
                 return true;
             }
         }
         return false;
     }
 
-    /** 接单:给订单赋值技师ID */
-    private void doAcceptOrder(Long techId, Long orderId){
+    /**
+     * 接单:给订单赋值技师ID
+     */
+    private void doAcceptOrder(Long techId, Long orderId) {
         TOrder update = new TOrder();
         update.setId(orderId);
         update.setMerchantId(techId);

+ 1 - 1
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/TCommentUserAuditServiceImpl.java

@@ -5,10 +5,10 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ylx.common.exception.ServiceException;
 import com.ylx.common.utils.StringUtils;
 import com.ylx.massage.domain.CommentUserAudit;
-import com.ylx.massage.domain.TCommentUser;
 import com.ylx.massage.mapper.TCommentUserAuditMapper;
 import com.ylx.massage.service.TCommentUserAuditService;
 import com.ylx.massage.service.TCommentUserService;
+import com.ylx.order.domain.TCommentUser;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 

+ 110 - 1
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/TCommentUserServiceImpl.java

@@ -1,14 +1,25 @@
 package com.ylx.massage.service.impl;
 
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ylx.common.core.domain.model.WxLoginUser;
-import com.ylx.massage.domain.TCommentUser;
+import com.ylx.common.exception.ServiceException;
+import com.ylx.massage.domain.CommentUserAudit;
+import com.ylx.massage.mapper.TCommentUserAuditMapper;
+import com.ylx.order.domain.TCommentUser;
 import com.ylx.massage.mapper.TCommentUserMapper;
 import com.ylx.massage.service.TCommentUserService;
+import com.ylx.order.domain.dto.OrderCommentDTO;
+import com.ylx.order.enums.AuditStatusEnum;
+import com.ylx.order.service.TCommentPictureService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
+import javax.annotation.Resource;
 import java.util.Collections;
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -21,6 +32,14 @@ import java.util.List;
 @Service("tCommentUserService")
 public class TCommentUserServiceImpl extends ServiceImpl<TCommentUserMapper, TCommentUser> implements TCommentUserService {
 
+    @Resource
+    private TCommentUserMapper tCommentUserMapper;
+    @Resource
+    private TCommentUserAuditMapper tCommentUserAuditMapper;
+
+    @Resource
+    private TCommentPictureService tCommentPictureService;
+
     @Override
     public Boolean saveComment(TCommentUser comment, WxLoginUser wxLoginUser) {
         return null;
@@ -30,4 +49,94 @@ public class TCommentUserServiceImpl extends ServiceImpl<TCommentUserMapper, TCo
     public List<TCommentUser> selectAll(TCommentUser tCommentUser) {
         return Collections.emptyList();
     }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void submitComment(OrderCommentDTO dto) {
+        // 1. 参数校验
+        validateComment(dto);
+
+        // 1. 获取并校验当前用户
+//        WxLoginUser wxLoginUser = SecurityUtils.getWxLoginUser();
+//        if (ObjectUtil.isNull(wxLoginUser)) {
+//            throw new ServiceException("用户未登录");
+//        }
+
+        // 2. 构建评论实体 TCommentUser
+        TCommentUser comment = new TCommentUser();
+        String userId = "2052914416724815873";
+        comment.setUserId(userId);
+        comment.setOrderId(dto.getOrderId());
+        comment.setMerchantId(Math.toIntExact(dto.getMerchantId()));
+        comment.setMerchantName(dto.getMerchantName());
+        comment.setText(dto.getText());
+        comment.setExperienceComment(dto.getExperienceComment());
+        comment.setPriceComment(dto.getPriceComment());
+        comment.setAttitudeComment(dto.getAttitudeComment());
+        comment.setGroomingComment(dto.getGroomingComment());
+        comment.setCommentTime(new Date());
+        comment.setCreateTime(new Date());
+        comment.setUpdateTime(new Date());
+        comment.setIsDelete(0);
+
+        // 4. 保存评论到 t_comment_user
+        int insertResult = tCommentUserMapper.insert(comment);
+        if (insertResult <= 0) {
+            throw new RuntimeException("评论入库失败");
+        }
+
+        // 5. 构建审核记录 CommentUserAudit
+        CommentUserAudit audit = new CommentUserAudit();
+        audit.setCommentId(comment.getId());
+        audit.setOrderId(dto.getOrderId());
+        audit.setText(dto.getText());
+        audit.setAuditStatus(AuditStatusEnum.PENDING.getCode());
+        audit.setAuditReason(null);
+        audit.setAuditorId(null);
+        audit.setAuditorName(null);
+        audit.setAuditTime(null);
+        audit.setCreateTime(new Date());
+        audit.setUpdateTime(new Date());
+        audit.setIsDelete(0);
+        audit.setIsPublished(0);
+
+        int auditResult = tCommentUserAuditMapper.insert(audit);
+        if (auditResult <= 0) {
+            throw new ServiceException("评论审核记录入库失败");
+        }
+        // 5. 保存评论图片(新增)
+        List<String> pictureUrls = dto.getCommentPictures();
+        if (CollectionUtils.isNotEmpty(pictureUrls)) {
+            tCommentPictureService.batchSavePictures(comment.getId(), pictureUrls);
+        }
+        log.info("评论入库成功,评论ID:{},订单号:{},用户ID:{}", comment.getId(), dto.getOrderId(), userId);
+    }
+    /**
+     * 校验评论参数
+     */
+    private void validateComment(OrderCommentDTO dto) {
+        if (dto == null) {
+            throw new IllegalArgumentException("评论信息不能为空");
+        }
+        if (StrUtil.isBlank(dto.getOrderId())) {
+            throw new IllegalArgumentException("订单ID不能为空");
+        }
+        if (dto.getMerchantId() == null) {
+            throw new IllegalArgumentException("商户ID不能为空");
+        }
+        if (StrUtil.isBlank(dto.getText())) {
+            throw new IllegalArgumentException("评论内容不能为空");
+        }
+        // 评分校验:1-5分
+        checkScore(dto.getExperienceComment(), "体验评价");
+        checkScore(dto.getPriceComment(), "价格评价");
+        checkScore(dto.getAttitudeComment(), "态度评价");
+        checkScore(dto.getGroomingComment(), "仪表仪容评价");
+    }
+
+    private void checkScore(Integer score, String fieldName) {
+        if (score == null || score < 1 || score > 5) {
+            throw new IllegalArgumentException(fieldName + "必须在1~5分之间");
+        }
+    }
 }

+ 39 - 0
nightFragrance-massage/src/main/java/com/ylx/order/controller/OrderCommentController.java

@@ -0,0 +1,39 @@
+package com.ylx.order.controller;
+
+import com.ylx.common.core.domain.R;
+import com.ylx.massage.service.TCommentUserService;
+import com.ylx.order.domain.dto.OrderCommentDTO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 类描述:订单评论控制器
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/9 15:59
+ */
+
+@Api(tags = "订单评论")
+@RestController
+@RequestMapping("/order/comment")
+@RequiredArgsConstructor
+public class OrderCommentController {
+
+    private final TCommentUserService tCommentUserService;
+
+    @ApiOperation("提交评论(用户评论技师)")
+    @PostMapping("/submit")
+    public R<?> submitComment(@Validated  @RequestBody OrderCommentDTO dto) {
+        tCommentUserService.submitComment(dto);
+        return R.ok("评价完成");
+    }
+
+
+}

+ 32 - 0
nightFragrance-massage/src/main/java/com/ylx/order/controller/RefundController.java

@@ -0,0 +1,32 @@
+package com.ylx.order.controller;
+
+import com.ylx.common.core.domain.R;
+import com.ylx.order.domain.vo.RegulationConfigVO;
+import com.ylx.order.service.RegulationService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@RestController
+@RequestMapping("/order/refund")
+@Api(tags = {"订单退款模块"})
+@Slf4j
+public class RefundController {
+
+    @Resource
+    private RegulationService regulationService;
+
+    @ApiOperation("根据商户履约状态获取退款描述")
+    @GetMapping("/desc/list")
+    public R<List<RegulationConfigVO>> getDescList(Integer execStatus) {
+        List<RegulationConfigVO> list = this.regulationService.getDescListByExecStatus(execStatus);
+        return R.ok(list);
+    }
+
+}

+ 21 - 7
nightFragrance-massage/src/main/java/com/ylx/order/controller/RegulationController.java

@@ -1,11 +1,13 @@
 package com.ylx.order.controller;
 
-import com.ylx.order.service.AutoFlowConfigService;
-import com.ylx.order.service.RefundRuleMasterService;
+import com.ylx.common.core.domain.R;
+import com.ylx.order.domain.dto.RegulationConfigDTO;
+import com.ylx.order.service.RegulationService;
 import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 
@@ -16,8 +18,20 @@ import javax.annotation.Resource;
 public class RegulationController {
 
     @Resource
-    private AutoFlowConfigService autoFlowConfigService;
-    @Resource
-    private RefundRuleMasterService refundRuleMasterService;
+    private RegulationService regulationService;
+
+    @ApiOperation("保存订单流转与退款规则配置")
+    @PostMapping("/save")
+    public R<?> saveConfig(@RequestBody @Validated RegulationConfigDTO dto) {
+        this.regulationService.saveFullConfig(dto);
+        return R.ok();
+    }
+
+    @ApiOperation("获取当前配置(用于回显)")
+    @GetMapping("/get")
+    public R<RegulationConfigDTO> getConfig() {
+        RegulationConfigDTO config = this.regulationService.getFullConfig();
+        return R.ok(config);
+    }
 
 }

+ 41 - 0
nightFragrance-massage/src/main/java/com/ylx/order/domain/TCommentPicture.java

@@ -0,0 +1,41 @@
+package com.ylx.order.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.ylx.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 类描述:评论图片关联表
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/9 16:42
+ */
+@Data
+@ApiModel("评论图片关联表")
+@TableName("t_comment_picture")
+public class TCommentPicture extends BaseEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("主键ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty("评论ID(关联 t_comment_user.id)")
+    private String commentId;
+
+    @ApiModelProperty("图片URL")
+    private String pictureUrl;
+
+    @ApiModelProperty("排序顺序(从小到大显示)")
+    private Integer sortOrder;
+
+
+}

+ 35 - 21
nightFragrance-massage/src/main/java/com/ylx/massage/domain/TCommentUser.java → nightFragrance-massage/src/main/java/com/ylx/order/domain/TCommentUser.java

@@ -1,4 +1,4 @@
-package com.ylx.massage.domain;
+package com.ylx.order.domain;
 
 
 
@@ -41,23 +41,15 @@ public class TCommentUser extends Model<TCommentUser> {
     private String id;
 
     /**
-     * 用户OpenID
+     * 用户id
      * 微信用户的唯一标识,用于关联评论发布者
      */
-    @ApiModelProperty("用户openid")
-    private String openId;
-
-    /**
-     * 订单号
-     * 关联的订单编号,用于关联具体的服务订单
-     */
-    @ApiModelProperty("订单号")
-    private String orderNo;
+    @ApiModelProperty("用户id")
+    private String userId;
 
     /**
      * 订单id
      */
-    @TableField(exist = false)
     @ApiModelProperty("订单id")
     private String orderId;
 
@@ -76,20 +68,25 @@ public class TCommentUser extends Model<TCommentUser> {
     private Integer sensitiveWord;
 
     /**
-     * 技师ID
+     * 商户id
      * 被评论技师的唯一标识
      */
-    @ApiModelProperty("技师id")
-    private String jsId;
+    @ApiModelProperty("商户id")
+    private Integer merchantId;
 
     /**
      * 技师姓名
      * 冗余字段,存储被评论技师的姓名,便于查询展示
      */
     @ApiModelProperty("技师姓名")
-    private String name;
-
+    private String merchantName;
 
+    /**
+     * 头像地址
+     */
+    @TableField("user_icon")
+    @ApiModelProperty("头像地址")
+    private String userIcon;
     /**
      * 评论时间
      * 用户发布评论的时间戳
@@ -128,12 +125,29 @@ public class TCommentUser extends Model<TCommentUser> {
     @ApiModelProperty("昵称")
     private String nickName;
 
-     /**
-     * 分数
+    /**
+     *  体验评价等级1-5
+     */
+    @ApiModelProperty("体验评价等级1-5")
+    private Integer experienceComment;
+
+    /**
+     *  价格评价等级1-5
+     */
+    @ApiModelProperty("价格评价等级1-5")
+    private Integer priceComment;
+
+    /**
+     *  态度评价等级1-5
      */
-    @ApiModelProperty("分数")
-    private Integer star;
+    @ApiModelProperty("态度评价等级1-5")
+    private Integer attitudeComment;
 
+    /**
+     *  仪表仪容等级1-5
+     */
+    @ApiModelProperty("仪表仪容等级1-5")
+    private Integer groomingComment;
     /**
      * 审核状态:0待审核 1通过 2拒绝
      */

+ 0 - 3
nightFragrance-massage/src/main/java/com/ylx/order/domain/TOrder.java

@@ -85,9 +85,6 @@ public class TOrder extends BaseEntity {
     @ApiModelProperty("联系人电话号码")
     private String contactPhoneNumber;
 
-    @ApiModelProperty("联系人微信号(可选)")
-    private String contactWechatId;
-
     @ApiModelProperty("详细服务地址")
     private String contactAddressInfo;
 

+ 0 - 28
nightFragrance-massage/src/main/java/com/ylx/order/domain/dto/AutoFlowConfigDTO.java

@@ -1,28 +0,0 @@
-package com.ylx.order.domain.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-
-@Data
-@ApiModel("客户端提交订单DTO")
-public class AutoFlowConfigDTO implements Serializable {
-    private static final long serialVersionUID = 134359989887419040L;
-
-
-    @ApiModelProperty("主键ID")
-    private Long id;
-
-    @ApiModelProperty("是否开启自动流转: 0=关闭, 1=开启")
-    private Integer isEnabled;
-
-    @ApiModelProperty("超时阈值(小时)")
-    private BigDecimal timeoutHours;
-
-    @ApiModelProperty("系统处理动作: 0=自动退款")
-    private Integer defaultAction;
-
-}

+ 86 - 0
nightFragrance-massage/src/main/java/com/ylx/order/domain/dto/OrderCommentDTO.java

@@ -0,0 +1,86 @@
+package com.ylx.order.domain.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.List;
+
+/**
+ * 类描述:订单评论DTO
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/9 15:27
+ */
+@Data
+public class OrderCommentDTO {
+
+    /**
+     * 订单id
+     */
+    @NotBlank(message = "订单id不能为空")
+    @ApiModelProperty("订单id")
+    private String orderId;
+
+    /**
+     * 商户id
+     * 被评论技师的唯一标识
+     */
+    @NotNull(message = "商户id不能为空")
+    @ApiModelProperty("商户id")
+    private Long merchantId;
+
+    /**
+     * 商户姓名
+     * 冗余字段,存储被评论技师的姓名,便于查询展示
+     */
+    @NotBlank(message = "商户姓名不能为空")
+    @ApiModelProperty("商户姓名")
+    private String merchantName;
+    /**
+     *  体验评价等级1-5
+     */
+    @NotNull(message = "体验评价等级不能为空")
+    @ApiModelProperty("体验评价等级1-5")
+    private Integer experienceComment;
+
+    /**
+     *  价格评价等级1-5
+     */
+    @NotNull(message = "价格评价等级不能为空")
+    @ApiModelProperty("价格评价等级1-5")
+    private Integer priceComment;
+
+    /**
+     *  态度评价等级1-5
+     */
+    @NotNull(message = "态度评价等级不能为空")
+    @ApiModelProperty("态度评价等级1-5")
+    private Integer attitudeComment;
+
+    /**
+     *  仪表仪容等级1-5
+     */
+    @NotNull(message = "仪表仪容等级不能为空")
+    @ApiModelProperty("仪表仪容等级1-5")
+    private Integer groomingComment;
+
+    /**
+     * 评论内容
+     * 用户对本次服务评价的文本内容
+     */
+    @NotBlank(message = "评论内容不能为空")
+    @ApiModelProperty("评论内容")
+    private String text;
+
+    /**
+     * 评论图片列表(多张)
+     * 最多支持9张图片,URL格式为完整http路径
+     */
+    @Size(max = 6, message = "最多上传6张图片")
+    @ApiModelProperty("评论图片列表")
+    private List<String> commentPictures;
+}

+ 2 - 3
nightFragrance-massage/src/main/java/com/ylx/order/domain/dto/OrderSubmitDTO.java

@@ -1,12 +1,10 @@
 package com.ylx.order.domain.dto;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
-import javax.validation.constraints.DecimalMax;
-import javax.validation.constraints.DecimalMin;
-import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotNull;
 import java.io.Serializable;
 import java.math.BigDecimal;
@@ -27,6 +25,7 @@ public class OrderSubmitDTO implements Serializable {
 
     @NotNull(message = "预约开始时间不能为空")
     @ApiModelProperty("预约开始时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private LocalDateTime appointmentStartTime;
 
     @NotNull(message = "联系人地址ID不能为空")

+ 123 - 0
nightFragrance-massage/src/main/java/com/ylx/order/domain/dto/RegulationConfigDTO.java

@@ -0,0 +1,123 @@
+package com.ylx.order.domain.dto;
+
+import lombok.Data;
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 订单流转与退款规则配置 DTO
+ * 用于接收前端“保存”操作提交的完整配置信息
+ */
+@Data
+public class RegulationConfigDTO {
+
+    // ==================== 1. 订单自动流转配置 ====================
+
+    /**
+     * 是否开启自动流转: true-开启, false-关闭
+     * 对应 DB: auto_flow_config.is_enabled
+     */
+    @NotNull(message = "自动流转开关不能为空")
+    private Boolean autoFlowEnabled;
+
+    /**
+     * 自动流转超时阈值(小时)
+     * 对应 DB: auto_flow_config.timeout_hours
+     * UI: "用户下单超 [ ] 小时"
+     */
+    @NotNull(message = "自动流转时间不能为空")
+    private BigDecimal timeoutHours;
+
+    /**
+     * 系统自动处理动作
+     * 对应 DB: auto_flow_config.default_action
+     * 0=自动退款 (目前UI只展示了这一个选项,预留扩展)
+     */
+    private Integer defaultAction;
+
+
+    // ==================== 2. 退款规则配置 ====================
+    // UI 上将退款规则分为了三个主要板块,我们将其封装为内部类列表
+
+    @NotNull(message = "未出发阶段策略不能为空")
+    private Integer preDepartureStrategy; // 0 or 1
+
+    /**
+     * 阶段一:商户未出发前 (Stage Type 0)
+     * UI 特征:支持多行配置(起始小时 至 结束小时,退款%)
+     */
+    @Valid
+    private List<TimeRangeRuleItem> preDepartureRules;
+
+    /**
+     * 阶段二:商户已出发/途中 (Stage Type 1)
+     * UI 特征:通常是一个固定比例,或者简单的列表
+     */
+    @Valid
+    private List<SimplePercentRuleItem> onWayRules;
+
+    /**
+     * 阶段三:服务进行中 (Stage Type 2)
+     * UI 特征:通常是一个固定比例
+     */
+    @Valid
+    private List<SimplePercentRuleItem> inServiceRules;
+
+
+    // ==================== 内部辅助类 ====================
+
+    /**
+     * 时间段规则项 (用于“商户未出发前”)
+     * 对应 DB: refund_rule_detail (stage_type=0)
+     */
+    @Data
+    public static class TimeRangeRuleItem {
+        /**
+         * 距离服务开始时间的起始小时数 (如 24.0)
+         * 对应 DB: time_start_hours
+         */
+        @NotNull(message = "起始小时不能为空")
+        private BigDecimal timeStartHours;
+
+        /**
+         * 距离服务开始时间的结束小时数 (如 8.0)
+         * 对应 DB: time_end_hours
+         */
+        @NotNull(message = "结束小时不能为空")
+        private BigDecimal timeEndHours;
+
+        /**
+         * 退款百分比 (如 80.00 代表 80%)
+         * 对应 DB: refund_percent
+         */
+        @NotNull(message = "退款比例不能为空")
+        private BigDecimal refundPercent;
+
+        /**
+         * 排序权重
+         */
+        private Integer sortOrder;
+    }
+
+    /**
+     * 简单比例规则项 (用于“商户已出发”和“服务中”)
+     * 对应 DB: refund_rule_detail (stage_type=1 or 2)
+     * 注意:这两个阶段通常不涉及复杂的时间窗口,或者时间窗口是隐含的
+     */
+    @Data
+    public static class SimplePercentRuleItem {
+        /**
+         * 退款类型: 0=全额, 1=部分
+         */
+        private Integer refundType;
+
+        /**
+         * 退款百分比
+         */
+        @NotNull(message = "退款比例不能为空")
+        private BigDecimal refundPercent;
+
+    }
+}

+ 10 - 1
nightFragrance-massage/src/main/java/com/ylx/order/domain/vo/OrderDetailVO.java

@@ -59,7 +59,13 @@ public class OrderDetailVO {
      */
     @ApiModelProperty("项目名称")
     private String projectName;
-
+    @ApiModelProperty("商户id")
+    private Long merchantId;
+    /**
+     * 商家名字
+     */
+    @ApiModelProperty("商家名字")
+    private String merchantName;
     /**
      * 项目时长
      */
@@ -116,6 +122,9 @@ public class OrderDetailVO {
     @ApiModelProperty("订单号")
     private String orderNo;
 
+    @ApiModelProperty("订单id")
+    private String orderId;
+
     @ApiModelProperty("下单时间")
     private String createTime;
 

+ 29 - 0
nightFragrance-massage/src/main/java/com/ylx/order/domain/vo/RegulationConfigVO.java

@@ -0,0 +1,29 @@
+package com.ylx.order.domain.vo;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.ylx.giftCard.domain.GiftCard;
+import com.ylx.order.domain.RefundRuleDetail;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+@ApiModel("订单退款规则配置VO")
+@Data
+public class RegulationConfigVO {
+
+    /**
+     * 退款规则描述
+     */
+    private String refundDesc;
+
+    /**
+     * 前端展示排序
+     */
+    private Integer sortOrder;
+
+
+    public RegulationConfigVO(RefundRuleDetail entity) {
+        this.refundDesc = entity.getRefundDesc();
+        this.sortOrder = entity.getSortOrder();
+    }
+
+}

+ 51 - 0
nightFragrance-massage/src/main/java/com/ylx/order/enums/AuditStatusEnum.java

@@ -0,0 +1,51 @@
+package com.ylx.order.enums;
+
+public enum AuditStatusEnum {
+    /**
+     * 待审核
+     */
+    PENDING(0, "待审核"),
+
+    /**
+     * 通过
+     */
+    APPROVED(1, "通过"),
+
+    /**
+     * 拒绝
+     */
+    REJECTED(2, "拒绝");
+
+    private final Integer code;
+    private final String desc;
+
+    AuditStatusEnum(Integer code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    /**
+     * 根据code获取枚举
+     * @param code 状态码
+     * @return 枚举对象,找不到返回null
+     */
+    public static AuditStatusEnum fromCode(Integer code) {
+        if (code == null) {
+            return null;
+        }
+        for (AuditStatusEnum status : values()) {
+            if (status.code.equals(code)) {
+                return status;
+            }
+        }
+        return null;
+    }
+}

+ 27 - 0
nightFragrance-massage/src/main/java/com/ylx/order/enums/RefundStageTypeEnum.java

@@ -0,0 +1,27 @@
+package com.ylx.order.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum RefundStageTypeEnum {
+
+    PRE_DEPARTURE(0, "商户未出发前"),
+    ON_THE_WAY(1, "商户已出发"),
+    IN_SERVICE(2, "服务中订单");
+
+    private final Integer code;
+    private final String info;
+
+    RefundStageTypeEnum(Integer code, String info) {
+        this.code = code;
+        this.info = info;
+    }
+
+    public static RefundStageTypeEnum getByCode(Integer code) {
+        for (RefundStageTypeEnum e : values()) {
+            if (e.getCode().equals(code)) return e;
+        }
+        return null;
+    }
+
+}

+ 18 - 0
nightFragrance-massage/src/main/java/com/ylx/order/mapper/TCommentPictureMapper.java

@@ -0,0 +1,18 @@
+package com.ylx.order.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ylx.order.domain.TCommentPicture;
+import org.apache.ibatis.annotations.Mapper;
+
+
+/**
+ * 类描述:
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/9 16:49
+ */
+@Mapper
+public interface TCommentPictureMapper extends BaseMapper<TCommentPicture> {
+}

+ 4 - 0
nightFragrance-massage/src/main/java/com/ylx/order/service/AutoFlowConfigService.java

@@ -2,6 +2,10 @@ package com.ylx.order.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ylx.order.domain.AutoFlowConfig;
+import com.ylx.order.domain.dto.RegulationConfigDTO;
 
 public interface AutoFlowConfigService extends IService<AutoFlowConfig> {
+    void handleAutoFlowConfig(RegulationConfigDTO dto);
+
+    void loadAutoFlowConfig(RegulationConfigDTO dto);
 }

+ 1 - 0
nightFragrance-massage/src/main/java/com/ylx/order/service/RefundRuleDetailService.java

@@ -4,4 +4,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.ylx.order.domain.RefundRuleDetail;
 
 public interface RefundRuleDetailService extends IService<RefundRuleDetail> {
+    void clearDetailsByStage(Integer stageType, String operator);
 }

+ 6 - 0
nightFragrance-massage/src/main/java/com/ylx/order/service/RefundRuleMasterService.java

@@ -2,6 +2,12 @@ package com.ylx.order.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ylx.order.domain.RefundRuleMaster;
+import com.ylx.order.domain.dto.RegulationConfigDTO;
 
 public interface RefundRuleMasterService extends IService<RefundRuleMaster> {
+
+    void handleRefundRules(RegulationConfigDTO dto);
+
+    void loadRefundRules(RegulationConfigDTO dto);
+
 }

+ 14 - 0
nightFragrance-massage/src/main/java/com/ylx/order/service/RegulationService.java

@@ -0,0 +1,14 @@
+package com.ylx.order.service;
+
+import com.ylx.order.domain.dto.RegulationConfigDTO;
+import com.ylx.order.domain.vo.RegulationConfigVO;
+
+import java.util.List;
+
+public interface RegulationService {
+    void saveFullConfig(RegulationConfigDTO dto);
+
+    RegulationConfigDTO getFullConfig();
+
+    List<RegulationConfigVO> getDescListByExecStatus(Integer execStatus);
+}

+ 30 - 0
nightFragrance-massage/src/main/java/com/ylx/order/service/TCommentPictureService.java

@@ -0,0 +1,30 @@
+package com.ylx.order.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ylx.order.domain.TCommentPicture;
+
+import java.util.List;
+
+/**
+ * 类描述:
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/9 16:51
+ */
+public interface TCommentPictureService extends IService<TCommentPicture> {
+
+    /**
+     * 批量保存评论图片
+     * @param commentId 评论ID
+     * @param pictureUrls 图片URL列表
+     */
+    void batchSavePictures(String commentId, List<String> pictureUrls);
+
+    /**
+     * 根据评论ID查询图片列表(已按排序顺序)
+     * @param commentId 评论ID
+     * @return 图片列表
+     */
+    List<TCommentPicture> getByCommentId(String commentId);
+}

+ 47 - 0
nightFragrance-massage/src/main/java/com/ylx/order/service/impl/AutoFlowConfigServiceImpl.java

@@ -1,13 +1,60 @@
 package com.ylx.order.service.impl;
 
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ylx.order.domain.AutoFlowConfig;
+import com.ylx.order.domain.dto.RegulationConfigDTO;
 import com.ylx.order.mapper.AutoFlowConfigMapper;
 import com.ylx.order.service.AutoFlowConfigService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 @Slf4j
 @Service
 public class AutoFlowConfigServiceImpl extends ServiceImpl<AutoFlowConfigMapper, AutoFlowConfig> implements AutoFlowConfigService {
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void handleAutoFlowConfig(RegulationConfigDTO dto) {
+
+        // 查询是否存在记录
+        LambdaQueryWrapper<AutoFlowConfig> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(AutoFlowConfig::getIsDelete, 0);
+        AutoFlowConfig config = this.baseMapper.selectOne(wrapper);
+
+        if (ObjectUtil.isNull(config)) {
+            config = new AutoFlowConfig();
+            config.setIsEnabled(dto.getAutoFlowEnabled() ? 1 : 0);
+            config.setTimeoutHours(dto.getTimeoutHours());
+            config.setDefaultAction(ObjectUtil.isNotNull(dto.getDefaultAction()) ? dto.getDefaultAction() : 0);
+            this.baseMapper.insert(config);
+        } else {
+            config.setIsEnabled(dto.getAutoFlowEnabled() ? 1 : 0);
+            config.setTimeoutHours(dto.getTimeoutHours());
+            if (ObjectUtil.isNotNull(dto.getDefaultAction())) {
+                config.setDefaultAction(dto.getDefaultAction());
+            }
+            this.baseMapper.updateById(config);
+        }
+
+    }
+
+    @Override
+    public void loadAutoFlowConfig(RegulationConfigDTO dto) {
+        LambdaQueryWrapper<AutoFlowConfig> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(AutoFlowConfig::getIsDelete, 0);
+        AutoFlowConfig config = this.baseMapper.selectOne(wrapper);
+
+        if (ObjectUtil.isNull(config)) {
+            dto.setAutoFlowEnabled(false);
+            dto.setDefaultAction(0);
+            return;
+        }
+
+        dto.setAutoFlowEnabled(ObjectUtil.equals(1, config.getIsEnabled()));
+        dto.setTimeoutHours(config.getTimeoutHours());
+        dto.setDefaultAction(ObjectUtil.isNotNull(config.getDefaultAction()) ? config.getDefaultAction() : 0);
+    }
 }

+ 23 - 0
nightFragrance-massage/src/main/java/com/ylx/order/service/impl/RefundRuleDetailServiceImpl.java

@@ -1,14 +1,37 @@
 package com.ylx.order.service.impl;
 
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ylx.common.utils.DateUtils;
 import com.ylx.order.domain.RefundRuleDetail;
 import com.ylx.order.mapper.RefundRuleDetailMapper;
 import com.ylx.order.service.RefundRuleDetailService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 @Slf4j
 @Service
 public class RefundRuleDetailServiceImpl extends ServiceImpl<RefundRuleDetailMapper, RefundRuleDetail> implements RefundRuleDetailService {
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void clearDetailsByStage(Integer stageType, String operator) {
+        if (ObjectUtil.isNull(stageType)) {
+            throw new IllegalArgumentException("阶段类型不能为空");
+        }
+        // 构建更新条件:只修改 is_delete 和 update_by/update_time
+        LambdaUpdateWrapper<RefundRuleDetail> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.eq(RefundRuleDetail::getStageType, stageType)
+                .eq(RefundRuleDetail::getIsDelete, 0) // 确保只处理未删除的数据
+                .set(RefundRuleDetail::getIsDelete, 1) // 逻辑删除标记
+                .set(RefundRuleDetail::getUpdateBy, operator)
+                .set(RefundRuleDetail::getUpdateTime, DateUtils.getNowDate());
+
+        int count = this.baseMapper.update(null, updateWrapper);
+        log.info("逻辑删除阶段 [{}] 的退款规则明细,影响行数: {}", stageType, count);
+
+    }
 }

+ 337 - 0
nightFragrance-massage/src/main/java/com/ylx/order/service/impl/RefundRuleMasterServiceImpl.java

@@ -1,13 +1,350 @@
 package com.ylx.order.service.impl;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ylx.common.exception.ServiceException;
+import com.ylx.common.utils.DateUtils;
+import com.ylx.common.utils.SecurityUtils;
+import com.ylx.order.domain.RefundRuleDetail;
 import com.ylx.order.domain.RefundRuleMaster;
+import com.ylx.order.domain.dto.RegulationConfigDTO;
+import com.ylx.order.enums.RefundStageTypeEnum;
 import com.ylx.order.mapper.RefundRuleMasterMapper;
+import com.ylx.order.service.RefundRuleDetailService;
 import com.ylx.order.service.RefundRuleMasterService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
 
 @Slf4j
 @Service
 public class RefundRuleMasterServiceImpl extends ServiceImpl<RefundRuleMasterMapper, RefundRuleMaster> implements RefundRuleMasterService {
+
+    @Resource
+    private RefundRuleDetailService refundRuleDetailService;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void handleRefundRules(RegulationConfigDTO dto) {
+
+        String operator = SecurityUtils.getUsername();
+        // 第一步:处理 MASTER 表
+        Long preDepartureMasterId = createOrUpdateMaster(RefundStageTypeEnum.PRE_DEPARTURE.getCode(), operator);
+        Long onWayMasterId = createOrUpdateMaster(RefundStageTypeEnum.ON_THE_WAY.getCode(), operator);
+        Long inServiceMasterId = createOrUpdateMaster(RefundStageTypeEnum.IN_SERVICE.getCode(), operator);
+
+        // 第二步:清理旧的 DETAIL 数据
+        clearDetailsByStage(RefundStageTypeEnum.PRE_DEPARTURE.getCode(), operator);
+        clearDetailsByStage(RefundStageTypeEnum.ON_THE_WAY.getCode(), operator);
+        clearDetailsByStage(RefundStageTypeEnum.IN_SERVICE.getCode(), operator);
+
+        // 第三步:组装并插入新的 DETAIL 数据
+        List<RefundRuleDetail> allDetails = new ArrayList<>();
+
+        // 1. 处理【商户未出发前】逻辑 (最复杂的部分)
+        handlePreDepartureDetails(preDepartureMasterId, dto.getPreDepartureStrategy(), dto.getPreDepartureRules(), allDetails, operator);
+
+        // 2. 处理【商户已出发】逻辑
+        handleSimpleStageDetails(onWayMasterId, dto.getOnWayRules(), RefundStageTypeEnum.ON_THE_WAY.getCode(), allDetails, operator);
+
+        // 3. 处理【服务进行中】逻辑
+        handleSimpleStageDetails(inServiceMasterId, dto.getInServiceRules(), RefundStageTypeEnum.IN_SERVICE.getCode(), allDetails, operator);
+
+        // 批量插入明细
+        if (!allDetails.isEmpty()) {
+            this.refundRuleDetailService.saveBatch(allDetails);
+            log.info("成功保存退款规则明细,共 {} 条", allDetails.size());
+        }
+    }
+
+    @Override
+    public void loadRefundRules(RegulationConfigDTO dto) {
+        loadPreDepartureRules(dto);
+        dto.setOnWayRules(loadSimpleStageRules(RefundStageTypeEnum.ON_THE_WAY.getCode()));
+        dto.setInServiceRules(loadSimpleStageRules(RefundStageTypeEnum.IN_SERVICE.getCode()));
+    }
+
+    private void loadPreDepartureRules(RegulationConfigDTO dto) {
+        List<RefundRuleDetail> details = listDetailsByStage(RefundStageTypeEnum.PRE_DEPARTURE.getCode());
+
+        if (CollUtil.isEmpty(details)) {
+            dto.setPreDepartureStrategy(0);
+            dto.setPreDepartureRules(Collections.emptyList());
+            return;
+        }
+
+        RefundRuleDetail first = CollUtil.getFirst(details);
+        if (details.size() == 1 && ObjectUtil.equals(0, first.getRefundType())) {
+            dto.setPreDepartureStrategy(0);
+            dto.setPreDepartureRules(Collections.emptyList());
+            return;
+        }
+
+        dto.setPreDepartureStrategy(1);
+        dto.setPreDepartureRules(details.stream().map(this::toTimeRangeRuleItem).collect(Collectors.toList()));
+    }
+
+    private List<RegulationConfigDTO.SimplePercentRuleItem> loadSimpleStageRules(Integer stageType) {
+        List<RefundRuleDetail> details = listDetailsByStage(stageType);
+        if (CollUtil.isEmpty(details)) {
+            return Collections.emptyList();
+        }
+
+        List<RegulationConfigDTO.SimplePercentRuleItem> rules = new ArrayList<>(1);
+        rules.add(toSimplePercentRuleItem(CollUtil.getFirst(details)));
+        return rules;
+    }
+
+    private List<RefundRuleDetail> listDetailsByStage(Integer stageType) {
+        LambdaQueryWrapper<RefundRuleDetail> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(RefundRuleDetail::getStageType, stageType)
+                .eq(RefundRuleDetail::getIsDelete, 0)
+                .orderByAsc(RefundRuleDetail::getSortOrder)
+                .orderByAsc(RefundRuleDetail::getId);
+        return this.refundRuleDetailService.list(wrapper);
+    }
+
+    private RegulationConfigDTO.TimeRangeRuleItem toTimeRangeRuleItem(RefundRuleDetail detail) {
+        RegulationConfigDTO.TimeRangeRuleItem item = new RegulationConfigDTO.TimeRangeRuleItem();
+        item.setTimeStartHours(detail.getTimeStartHours());
+        item.setTimeEndHours(detail.getTimeEndHours());
+        item.setRefundPercent(detail.getRefundPercent());
+        item.setSortOrder(detail.getSortOrder());
+        return item;
+    }
+
+    private RegulationConfigDTO.SimplePercentRuleItem toSimplePercentRuleItem(RefundRuleDetail detail) {
+        RegulationConfigDTO.SimplePercentRuleItem item = new RegulationConfigDTO.SimplePercentRuleItem();
+        item.setRefundType(detail.getRefundType());
+        item.setRefundPercent(detail.getRefundPercent());
+        return item;
+    }
+
+    /**
+     * 创建或更新主表记录
+     * 逻辑:查找是否存在该 stage_type 的记录,存在则更新时间,不存在则新增
+     */
+    private Long createOrUpdateMaster(Integer stageType, String operator) {
+
+        // 查询是否存在
+        LambdaQueryWrapper<RefundRuleMaster> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(RefundRuleMaster::getStageType, stageType).eq(RefundRuleMaster::getIsDelete, 0);
+        RefundRuleMaster existing = this.baseMapper.selectOne(wrapper);
+
+        if (ObjectUtil.isNotNull(existing)) {
+            existing.setUpdateTime(DateUtils.getNowDate());
+            existing.setUpdateBy(operator);
+            this.baseMapper.updateById(existing);
+            return existing.getId();
+        } else {
+            // 新增
+            RefundRuleMaster master = new RefundRuleMaster();
+            master.setStageType(stageType);
+            master.setCreateBy(operator);
+            master.setCreateTime(DateUtils.getNowDate());
+            master.setIsDelete(0);
+            this.baseMapper.insert(master);
+            return master.getId();
+        }
+    }
+
+    /**
+     * 处理“未出发前”的特殊逻辑
+     *
+     * @param masterId 主表ID
+     * @param strategy 策略: 0=全额, 1=部分
+     * @param rules    前端传来的时间段列表
+     * @param operator
+     */
+    private void handlePreDepartureDetails(Long masterId, Integer strategy, List<RegulationConfigDTO.TimeRangeRuleItem> rules, List<RefundRuleDetail> targetList, String operator) {
+        if (strategy == 0) {
+            // === 情况 A:全额退款 ===
+            RefundRuleDetail detail = new RefundRuleDetail();
+            detail.setMasterId(masterId);
+            detail.setStageType(RefundStageTypeEnum.PRE_DEPARTURE.getCode());
+            detail.setRefundType(0); // 全额
+            detail.setRefundPercent(BigDecimal.valueOf(100));
+            detail.setSortOrder(1);
+            detail.setRefundDesc("出发前全额退款");
+            detail.setCreateBy(operator);
+            detail.setCreateTime(DateUtils.getNowDate());
+            targetList.add(detail);
+
+        } else if (strategy == 1) {
+            // === 情况 B:部分退款(分时段) ===
+            if (ObjectUtil.isEmpty(rules)) {
+                throw new ServiceException("选择部分退款时,必须配置时间段规则!");
+            }
+
+            rules.sort(Comparator.comparing(RegulationConfigDTO.TimeRangeRuleItem::getTimeStartHours));
+
+            for (RegulationConfigDTO.TimeRangeRuleItem rule : rules) {
+                RefundRuleDetail detail = new RefundRuleDetail();
+                detail.setMasterId(masterId);
+                detail.setStageType(RefundStageTypeEnum.PRE_DEPARTURE.getCode());
+
+                // 时间窗口
+                detail.setTimeStartHours(rule.getTimeStartHours());
+                detail.setTimeEndHours(rule.getTimeEndHours());
+
+                // 退款比例
+                detail.setRefundType(1); // 部分
+                detail.setRefundPercent(rule.getRefundPercent());
+                detail.setSortOrder(rule.getSortOrder());
+
+                // 生成描述 (可选)
+                String desc = generatePreDepartureDesc(rule);
+                detail.setRefundDesc(desc);
+
+                detail.setCreateBy(operator);
+                detail.setCreateTime(DateUtils.getNowDate());
+                targetList.add(detail);
+            }
+        }
+    }
+
+    /**
+     * 处理简单阶段(已出发、进行中)
+     * 逻辑:无论全额还是部分,都只有一条记录
+     */
+    private void handleSimpleStageDetails(Long masterId, List<RegulationConfigDTO.SimplePercentRuleItem> list, Integer refundStageTypeCode, List<RefundRuleDetail> targetList, String operator) {
+
+        // 1. 通过枚举获取阶段描述,用于日志输出
+        RefundStageTypeEnum stageEnum = RefundStageTypeEnum.getByCode(refundStageTypeCode);
+        if (ObjectUtil.isNull(stageEnum)) {
+            throw new ServiceException("refundStageTypeCode参数有误,查不到对应的类型");
+        }
+        String stageDesc = stageEnum.getInfo();
+
+        // 2. 打印日志,清晰明了
+        log.info("开始处理【{}】阶段的退款规则配置...", stageDesc);
+
+        if (CollUtil.isEmpty(list)) {
+            throw new ServiceException("【" + stageDesc + "】的比例规则项不能为空");
+        }
+
+        RegulationConfigDTO.SimplePercentRuleItem ruleItem = CollUtil.getFirst(list);
+
+        RefundRuleDetail detail = new RefundRuleDetail();
+        detail.setMasterId(masterId);
+        detail.setStageType(refundStageTypeCode);
+
+        detail.setRefundType(ruleItem.getRefundType());
+        detail.setRefundPercent(ruleItem.getRefundPercent());
+        detail.setSortOrder(1);
+
+        detail.setCreateBy(operator);
+        detail.setCreateTime(DateUtils.getNowDate());
+
+        Integer type = ruleItem.getRefundType();
+        BigDecimal percent = ruleItem.getRefundPercent();
+
+        String desc;
+        if (type != null && type == 0) {
+            desc = stageDesc + "全额退款";
+        } else {
+            desc = String.format(stageDesc + ",不再支持全额退款,只退实付金额的%s%%", percent);
+        }
+        detail.setRefundDesc(desc);
+
+        targetList.add(detail);
+
+        // 3. 处理完成日志
+        log.debug("【{}】阶段规则构建完成: Type={}, Percent={}",
+                stageDesc, ruleItem.getRefundType(), ruleItem.getRefundPercent());
+    }
+
+    private void clearDetailsByStage(Integer stageType, String operator) {
+        log.warn("正在清理 stage_type={} 的旧明细数据, operator ={} ", stageType, operator);
+        this.refundRuleDetailService.clearDetailsByStage(stageType, operator);
+    }
+
+    /**
+     * 处理复杂阶段(未出发前)
+     * 逻辑:根据时间段列表生成多条明细,并动态生成 refundDesc
+     */
+    private void handleComplexStageDetails(Long masterId, List<RegulationConfigDTO.TimeRangeRuleItem> list, Integer stageType, List<RefundRuleDetail> targetList) {
+        if (CollUtil.isEmpty(list)) {
+            throw new ServiceException("未出发阶段的退款规则不能为空");
+        }
+
+        // 按开始时间排序,确保生成的文案顺序正确(可选,视前端是否已排好序而定)
+        list.sort(Comparator.comparing(RegulationConfigDTO.TimeRangeRuleItem::getTimeStartHours));
+
+        int sortIndex = 1;
+        for (RegulationConfigDTO.TimeRangeRuleItem item : list) {
+            RefundRuleDetail detail = new RefundRuleDetail();
+            detail.setMasterId(masterId);
+            detail.setStageType(stageType);
+            detail.setRefundType(1); // 1代表部分退款/自定义
+            detail.setRefundPercent(item.getRefundPercent());
+            detail.setSortOrder(sortIndex++);
+
+            // ================= 核心修改:动态生成描述文案 =================
+            String desc = generatePreDepartureDesc(item);
+            detail.setRefundDesc(desc);
+            // ==========================================================
+
+            targetList.add(detail);
+        }
+    }
+
+    /**
+     * 根据时间段规则项生成对应的中文描述
+     *
+     * @param item 规则项(包含开始时间、结束时间、比例)
+     * @return 格式化后的文案
+     */
+    private String generatePreDepartureDesc(RegulationConfigDTO.TimeRangeRuleItem item) {
+        BigDecimal startHour = item.getTimeStartHours();
+        BigDecimal endHour = item.getTimeEndHours();
+        BigDecimal percent = item.getRefundPercent();
+
+        // 基础文案模板
+        String prefix = "距离服务开始前";
+        String middle = "小时申请退款,只退付金额的";
+        String suffix = "%";
+
+        // 场景 1:标准的区间(例如:24-48小时)
+        // 注意:这里需要判断 startHour 是否有值。
+        // 如果业务定义 startHour 为 null 或 0 代表“不足X小时”,则走场景 2
+        if (startHour != null && startHour.compareTo(BigDecimal.ZERO) > 0) {
+            return String.format("%s%s至%s%s%s%s",
+                    prefix,
+                    formatNumber(startHour), // 去除小数点后的 .0
+                    formatNumber(endHour),
+                    middle,
+                    formatNumber(percent),
+                    suffix
+            );
+        }
+        // 场景 2:兜底区间(例如:不足 24 小时)
+        else {
+            return String.format("距离服务开始不足%s%s%s%s",
+                    formatNumber(endHour),
+                    middle,
+                    formatNumber(percent),
+                    suffix
+            );
+        }
+    }
+
+    /**
+     * 辅助方法:格式化数字,如果是整数则去掉小数点(24.0 -> 24)
+     */
+    private String formatNumber(BigDecimal number) {
+        if (number == null) return "";
+        return number.stripTrailingZeros().toPlainString();
+    }
+
 }

+ 71 - 0
nightFragrance-massage/src/main/java/com/ylx/order/service/impl/RegulationServiceImpl.java

@@ -0,0 +1,71 @@
+package com.ylx.order.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.ylx.order.domain.RefundRuleDetail;
+import com.ylx.order.domain.dto.RegulationConfigDTO;
+import com.ylx.order.domain.vo.RegulationConfigVO;
+import com.ylx.order.service.AutoFlowConfigService;
+import com.ylx.order.service.RefundRuleDetailService;
+import com.ylx.order.service.RefundRuleMasterService;
+import com.ylx.order.service.RegulationService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class RegulationServiceImpl implements RegulationService {
+
+    @Resource
+    private AutoFlowConfigService autoFlowConfigService;
+    @Resource
+    private RefundRuleMasterService refundRuleMasterService;
+    @Resource
+    private RefundRuleDetailService refundRuleDetailService;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void saveFullConfig(RegulationConfigDTO dto) {
+        // 1. 保存/更新自动流转配置 (auto_flow_config)
+        handleAutoFlowConfig(dto);
+
+        // 2. 保存/更新退款规则 (refund_rule_master + detail)
+        handleRefundRules(dto);
+    }
+
+    private void handleAutoFlowConfig(RegulationConfigDTO dto) {
+        this.autoFlowConfigService.handleAutoFlowConfig(dto);
+    }
+
+    private void handleRefundRules(RegulationConfigDTO dto) {
+        this.refundRuleMasterService.handleRefundRules(dto);
+    }
+
+    @Override
+    public RegulationConfigDTO getFullConfig() {
+        RegulationConfigDTO dto = new RegulationConfigDTO();
+        this.autoFlowConfigService.loadAutoFlowConfig(dto);
+        this.refundRuleMasterService.loadRefundRules(dto);
+        return dto;
+    }
+
+    @Override
+    public List<RegulationConfigVO> getDescListByExecStatus(Integer execStatus) {
+        LambdaQueryWrapper<RefundRuleDetail> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(RefundRuleDetail::getStageType, execStatus)
+                .orderByAsc(RefundRuleDetail::getSortOrder);
+        List<RefundRuleDetail> list = this.refundRuleDetailService.list(wrapper);
+        if (CollUtil.isNotEmpty(list)){
+            return list.stream()
+                    .map(RegulationConfigVO::new)
+                    .collect(Collectors.toList());
+        }
+        return Collections.emptyList();
+    }
+}

+ 59 - 0
nightFragrance-massage/src/main/java/com/ylx/order/service/impl/TCommentPictureServiceImpl.java

@@ -0,0 +1,59 @@
+package com.ylx.order.service.impl;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ylx.order.domain.TCommentPicture;
+import com.ylx.order.mapper.TCommentPictureMapper;
+import com.ylx.order.service.TCommentPictureService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 类描述:
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/9 16:56
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class TCommentPictureServiceImpl extends ServiceImpl<TCommentPictureMapper, TCommentPicture> implements TCommentPictureService {
+
+    private final TCommentPictureMapper pictureMapper;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void batchSavePictures(String commentId, List<String> pictureUrls) {
+        if (commentId == null || CollectionUtil.isEmpty(pictureUrls)) {
+            return;
+        }
+        List<TCommentPicture> pictureList = new ArrayList<>();
+        for (int i = 0; i < pictureUrls.size(); i++) {
+            TCommentPicture picture = new TCommentPicture();
+            picture.setCommentId(commentId);
+            picture.setPictureUrl(pictureUrls.get(i));
+            picture.setSortOrder(i);
+            picture.setCreateTime(new Date());
+            pictureList.add(picture);
+        }
+        this.saveBatch(pictureList);
+        log.info("批量保存评论图片成功,commentId: {},图片数量: {}", commentId, pictureUrls.size());
+    }
+
+    @Override
+    public List<TCommentPicture> getByCommentId(String commentId) {
+        LambdaQueryWrapper<TCommentPicture> wrapper = Wrappers.lambdaQuery(TCommentPicture.class)
+                .eq(TCommentPicture::getCommentId, commentId)
+                .orderByAsc(TCommentPicture::getSortOrder);
+        return this.list(wrapper);
+    }
+}

+ 3 - 1
nightFragrance-massage/src/main/java/com/ylx/order/service/impl/TOrderServiceImpl.java

@@ -660,7 +660,9 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
         vo.setTrafficFee(order.getTrafficFee());
         vo.setCouponDiscount(order.getCouponDiscount());
         vo.setOrderNo(order.getOrderNo());
-
+        vo.setOrderId(String.valueOf(order.getId()));
+        vo.setMerchantName(order.getMerchantNickName());
+        vo.setMerchantId(order.getMerchantId());
         // 时间处理
         if (order.getAppointmentStartTime() != null) {
             LocalDateTime start = order.getAppointmentStartTime();

+ 5 - 5
nightFragrance-massage/src/main/resources/mapper/massage/TCommentUserMapper.xml

@@ -2,12 +2,12 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.ylx.massage.mapper.TCommentUserMapper">
 
-    <resultMap type="com.ylx.massage.domain.TCommentUser" id="TCommentUserMap">
+    <resultMap type="com.ylx.order.domain.TCommentUser" id="TCommentUserMap">
         <result property="id" column="id" jdbcType="VARCHAR"/>
         <result property="text" column="text" jdbcType="VARCHAR"/>
-        <result property="orderNo" column="order_no" jdbcType="VARCHAR"/>
-        <result property="jsId" column="js_id" jdbcType="VARCHAR"/>
-        <result property="openId" column="open_id" jdbcType="VARCHAR"/>
+        <result property="orderId" column="order_id" jdbcType="VARCHAR"/>
+        <result property="merchantId" column="merchant_id" jdbcType="INTEGER"/>
+        <result property="user_id" column="user_id" jdbcType="VARCHAR"/>
         <result property="commentTime" column="comment_time" jdbcType="TIMESTAMP"/>
         <result property="name" column="name" jdbcType="VARCHAR"/>
         <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
@@ -37,7 +37,7 @@
     </insert>
 
     <!-- 分页查询用户评论 -->
-    <select id="selectAll" resultType="com.ylx.massage.domain.TCommentUser">
+    <select id="selectAll" resultType="com.ylx.order.domain.TCommentUser">
         SELECT
             tcu.id as id,
             tcu.nick_name as nickName,

+ 13 - 0
nightFragrance-massage/src/main/resources/mapper/order/TCommentPictureMapper.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ylx.order.mapper.TCommentPictureMapper">
+    <!-- 通用结果映射 -->
+    <resultMap id="BaseResultMap" type="com.ylx.order.domain.TCommentPicture">
+        <id column="id" property="id"/>
+        <result column="comment_id" property="commentId"/>
+        <result column="picture_url" property="pictureUrl"/>
+        <result column="sort_order" property="sortOrder"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_time" property="updateTime"/>
+    </resultMap>
+</mapper>