Browse Source

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

郭子栋 5 days ago
parent
commit
58ba9d321d
28 changed files with 1268 additions and 318 deletions
  1. 3 2
      nightFragrance-admin/src/main/java/com/ylx/web/controller/massage/AreaController.java
  2. 43 21
      nightFragrance-admin/src/main/java/com/ylx/web/controller/massage/MaTechnicianController.java
  3. 4 4
      nightFragrance-admin/src/main/java/com/ylx/web/controller/massage/TLbtController.java
  4. 87 0
      nightFragrance-massage/src/main/java/com/ylx/massage/controller/MerchantDailyAttendanceController.java
  5. 2 1
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/MaProject.java
  6. 2 2
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/MaTeProject.java
  7. 80 58
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/MaTechnician.java
  8. 74 0
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/MerchantApplyFile.java
  9. 82 0
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/MerchantDailyAttendance.java
  10. 42 47
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/TLbt.java
  11. 1 1
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/dto/MaTechnicianMerchantAddDTO.java
  12. 63 0
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/dto/MaTechnicianPendingAuditSubmitDTO.java
  13. 21 0
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/dto/MerchantApplyFileDto.java
  14. 59 59
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/vo/MaTechnicianAppAddVo.java
  15. 6 2
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/vo/MaTechnicianCertificateVO.java
  16. 112 0
      nightFragrance-massage/src/main/java/com/ylx/massage/enums/FileTypeEnum.java
  17. 24 0
      nightFragrance-massage/src/main/java/com/ylx/massage/enums/TechnicianStatusEnum.java
  18. 1 1
      nightFragrance-massage/src/main/java/com/ylx/massage/mapper/MaTeProjectMapper.java
  19. 10 0
      nightFragrance-massage/src/main/java/com/ylx/massage/mapper/MaTechnicianMapper.java
  20. 18 0
      nightFragrance-massage/src/main/java/com/ylx/massage/mapper/MerchantApplyFileMapper.java
  21. 17 0
      nightFragrance-massage/src/main/java/com/ylx/massage/mapper/MerchantDailyAttendanceMapper.java
  22. 24 1
      nightFragrance-massage/src/main/java/com/ylx/massage/service/IMaTechnicianService.java
  23. 18 0
      nightFragrance-massage/src/main/java/com/ylx/massage/service/MerchantDailyAttendanceService.java
  24. 427 93
      nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/MaTechnicianServiceImpl.java
  25. 19 0
      nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/MerchantDailyAttendanceServiceImpl.java
  26. 11 11
      nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/TLbtServiceImpl.java
  27. 8 8
      nightFragrance-massage/src/main/java/com/ylx/massage/utils/MassageUtil.java
  28. 10 7
      nightFragrance-massage/src/main/resources/mapper/massage/TLbtMapper.xml

+ 3 - 2
nightFragrance-admin/src/main/java/com/ylx/web/controller/massage/AreaController.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ylx.common.core.domain.R;
 import com.ylx.massage.domain.Area;
 import com.ylx.massage.domain.Area;
 import com.ylx.massage.domain.dto.CoordinateDTO;
 import com.ylx.massage.domain.dto.CoordinateDTO;
 import com.ylx.massage.domain.vo.AreaTreeNode;
 import com.ylx.massage.domain.vo.AreaTreeNode;
@@ -14,11 +15,10 @@ import com.ylx.massage.service.AreaService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
-import com.ylx.common.core.domain.R;
+
 import javax.annotation.Resource;
 import javax.annotation.Resource;
 import java.io.Serializable;
 import java.io.Serializable;
 import java.util.List;
 import java.util.List;
-import java.util.Map;
 
 
 /**
 /**
  * 区域数据(Area)表控制层
  * 区域数据(Area)表控制层
@@ -131,5 +131,6 @@ public class AreaController {
         CityInfoVo cityInfoVo = this.areaService.getCityInfoByCoordinates(dto);
         CityInfoVo cityInfoVo = this.areaService.getCityInfoByCoordinates(dto);
         return R.ok(cityInfoVo);
         return R.ok(cityInfoVo);
     }
     }
+
 }
 }
 
 

+ 43 - 21
nightFragrance-admin/src/main/java/com/ylx/web/controller/massage/MaTechnicianController.java

@@ -21,12 +21,14 @@ import com.ylx.common.core.domain.model.aliyun.SendSmsComponents;
 import com.ylx.common.core.domain.model.aliyun.SendSmsEnum;
 import com.ylx.common.core.domain.model.aliyun.SendSmsEnum;
 import com.ylx.common.utils.StringUtils;
 import com.ylx.common.utils.StringUtils;
 import com.ylx.massage.domain.MaProject;
 import com.ylx.massage.domain.MaProject;
+import com.ylx.massage.domain.dto.*;
 import com.ylx.massage.domain.dto.MaProjectSaveDto;
 import com.ylx.massage.domain.dto.MaProjectSaveDto;
 import com.ylx.massage.domain.dto.MaProjectUpdateDto;
 import com.ylx.massage.domain.dto.MaProjectUpdateDto;
 import com.ylx.massage.domain.dto.MaTechnicianAuditQueryDTO;
 import com.ylx.massage.domain.dto.MaTechnicianAuditQueryDTO;
 import com.ylx.massage.domain.dto.MaTechnicianAuditSubmitDTO;
 import com.ylx.massage.domain.dto.MaTechnicianAuditSubmitDTO;
 import com.ylx.massage.domain.dto.MaTechnicianMerchantAddDTO;
 import com.ylx.massage.domain.dto.MaTechnicianMerchantAddDTO;
 import com.ylx.massage.domain.dto.MaTechnicianMerchantQueryDTO;
 import com.ylx.massage.domain.dto.MaTechnicianMerchantQueryDTO;
+import com.ylx.massage.domain.dto.MaTechnicianPendingAuditSubmitDTO;
 import com.ylx.massage.domain.vo.*;
 import com.ylx.massage.domain.vo.*;
 import com.ylx.massage.service.IMaProjectService;
 import com.ylx.massage.service.IMaProjectService;
 import com.ylx.project.domain.Project;
 import com.ylx.project.domain.Project;
@@ -199,7 +201,24 @@ public class MaTechnicianController extends BaseController {
         maTechnicianService.apply(req);
         maTechnicianService.apply(req);
         return Result.ok("提交成功,进入审核流程");
         return Result.ok("提交成功,进入审核流程");
     }
     }
-
+    /**
+     * 申请技师文件
+     * @param req
+     */
+    @PostMapping("/applyFile")
+    public  Result applyFile(MerchantApplyFileDto req){
+        maTechnicianService.applyFile(req);
+        return Result.ok("上传成功");
+    }
+    /**
+     * 技师状态切换
+     *
+     * @param
+     */
+    @GetMapping("/switchToOffline")
+    public Result switchToOffline(@RequestParam Long userId, @RequestParam Boolean forceConfirm){
+        return maTechnicianService.switchToOffline(userId, forceConfirm);
+    }
     /**
     /**
      * 查询商户信息接口
      * 查询商户信息接口
      */
      */
@@ -219,30 +238,11 @@ public class MaTechnicianController extends BaseController {
         if (req.getAuditStatus() == 0 || req.getAuditStatus() == 3) {
         if (req.getAuditStatus() == 0 || req.getAuditStatus() == 3) {
             //修改基本信息
             //修改基本信息
             updateMaTechnician(req);
             updateMaTechnician(req);
-        } else if (req.getAuditStatus() == 1 || req.getAuditStatus() == 2) {
-            //上传商户资料信息
-            extractedUpdate(req);
         }
         }
         return Result.ok("修改成功");
         return Result.ok("修改成功");
     }
     }
 
 
-    private void extractedUpdate(MaTechnicianAppAddVo req) {
-        LambdaUpdateWrapper<MaTechnician> updateWrapper = new LambdaUpdateWrapper<>();
-        updateWrapper.eq(MaTechnician::getId, req.getId());
-        updateWrapper.set(MaTechnician::getTeAvatar, req.getTeAvatar());
-        updateWrapper.set(MaTechnician::getTeNickName, req.getTeNickName());
-        updateWrapper.set(MaTechnician::getTeBrief, req.getTeBrief());
-        updateWrapper.set(MaTechnician::getLifePhotos, req.getLifePhotos());
-        updateWrapper.set(MaTechnician::getIdCard, req.getIdCard());
-        updateWrapper.set(MaTechnician::getHealthCertificate, req.getHealthCertificate());
-        updateWrapper.set(MaTechnician::getQualificationCertificate, req.getQualificationCertificate());
-        updateWrapper.set(MaTechnician::getNoCrimeRecord, req.getNoCrimeRecord());
-        updateWrapper.set(MaTechnician::getPromoVideo, req.getPromoVideo());
-        updateWrapper.set(MaTechnician::getCommitmentAudio, req.getCommitmentAudio());
-        updateWrapper.set(MaTechnician::getCommitmentPdf, req.getCommitmentPdf());
-        updateWrapper.set(MaTechnician::getCommitmentVideo, req.getCommitmentVideo());
-        maTechnicianService.update(updateWrapper);
-    }
+
 
 
     private void updateMaTechnician(MaTechnicianAppAddVo req) {
     private void updateMaTechnician(MaTechnicianAppAddVo req) {
         LambdaUpdateWrapper<MaTechnician> updateWrapper = new LambdaUpdateWrapper<>();
         LambdaUpdateWrapper<MaTechnician> updateWrapper = new LambdaUpdateWrapper<>();
@@ -401,6 +401,28 @@ public class MaTechnicianController extends BaseController {
         }
         }
     }
     }
 
 
+    /**
+     * 待审核页面审核通过商户
+     *
+     * @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);
+        }
+    }
+
     /**
     /**
      * 查询商户列表
      * 查询商户列表
      *
      *

+ 4 - 4
nightFragrance-admin/src/main/java/com/ylx/web/controller/massage/TLbtController.java

@@ -44,7 +44,7 @@ public class TLbtController {
     public R<List<TLbt>> getAll() {
     public R<List<TLbt>> getAll() {
         try {
         try {
             QueryWrapper<TLbt> wrapper = new QueryWrapper<>();
             QueryWrapper<TLbt> wrapper = new QueryWrapper<>();
-            wrapper.lambda().orderByAsc(TLbt::getCSort);
+            wrapper.lambda().orderByAsc(TLbt::getSort);
             List<TLbt> list = lbtService.list(wrapper);
             List<TLbt> list = lbtService.list(wrapper);
             return R.ok(list);
             return R.ok(list);
         } catch (Exception e) {
         } catch (Exception e) {
@@ -87,8 +87,8 @@ public class TLbtController {
     public R<Page<TLbt>> selectSpfl(Page<TLbt> page, TLbt lbt) {
     public R<Page<TLbt>> selectSpfl(Page<TLbt> page, TLbt lbt) {
         try {
         try {
             LambdaQueryWrapper<TLbt> tLbtLambdaQueryWrapper = new LambdaQueryWrapper<>();
             LambdaQueryWrapper<TLbt> tLbtLambdaQueryWrapper = new LambdaQueryWrapper<>();
-            tLbtLambdaQueryWrapper.like(StringUtils.isNotBlank(lbt.getCDescribe()), TLbt::getCDescribe, lbt.getCDescribe())
-                    .orderByAsc(TLbt::getCSort);
+            tLbtLambdaQueryWrapper.like(StringUtils.isNotBlank(lbt.getTitle()), TLbt::getTitle, lbt.getTitle())
+                    .orderByAsc(TLbt::getSort);
             // 获取查询返回结果
             // 获取查询返回结果
             Page<TLbt> pageSelect = lbtService.page(page, tLbtLambdaQueryWrapper);
             Page<TLbt> pageSelect = lbtService.page(page, tLbtLambdaQueryWrapper);
             return R.ok(pageSelect);
             return R.ok(pageSelect);
@@ -128,6 +128,6 @@ public class TLbtController {
     @ApiOperation("根据id查询轮播图")
     @ApiOperation("根据id查询轮播图")
     @RequestMapping(value = "/wx/getByid", method = RequestMethod.POST)
     @RequestMapping(value = "/wx/getByid", method = RequestMethod.POST)
     public R getById(@RequestBody TLbt tLbt) {
     public R getById(@RequestBody TLbt tLbt) {
-        return R.ok(lbtService.getById(tLbt.getCId()));
+        return R.ok(lbtService.getById(tLbt.getId()));
     }
     }
 }
 }

+ 87 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/controller/MerchantDailyAttendanceController.java

@@ -0,0 +1,87 @@
+package com.ylx.massage.controller;
+
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ylx.common.core.domain.R;
+import com.ylx.massage.domain.MerchantDailyAttendance;
+import com.ylx.massage.service.MerchantDailyAttendanceService;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 商户每日考勤统计表(MerchantDailyAttendance)表控制层
+ *
+ * @author makejava
+ * @since 2026-06-05 11:16:04
+ */
+@RestController
+@RequestMapping("merchantDailyAttendance")
+public class MerchantDailyAttendanceController  {
+    /**
+     * 服务对象
+     */
+    @Resource
+    private MerchantDailyAttendanceService merchantDailyAttendanceService;
+
+    /**
+     * 分页查询所有数据
+     *
+     * @param page 分页对象
+     * @param merchantDailyAttendance 查询实体
+     * @return 所有数据
+     */
+    @GetMapping
+    public R selectAll(Page<MerchantDailyAttendance> page, MerchantDailyAttendance merchantDailyAttendance) {
+        return R.ok(this.merchantDailyAttendanceService.page(page, new QueryWrapper<>(merchantDailyAttendance)));
+    }
+
+    /**
+     * 通过主键查询单条数据
+     *
+     * @param id 主键
+     * @return 单条数据
+     */
+    @GetMapping("{id}")
+    public R selectOne(@PathVariable Serializable id) {
+        return R.ok(this.merchantDailyAttendanceService.getById(id));
+    }
+
+    /**
+     * 新增数据
+     *
+     * @param merchantDailyAttendance 实体对象
+     * @return 新增结果
+     */
+    @PostMapping
+    public R insert(@RequestBody MerchantDailyAttendance merchantDailyAttendance) {
+        return R.ok(this.merchantDailyAttendanceService.save(merchantDailyAttendance));
+    }
+
+    /**
+     * 修改数据
+     *
+     * @param merchantDailyAttendance 实体对象
+     * @return 修改结果
+     */
+    @PutMapping
+    public R update(@RequestBody MerchantDailyAttendance merchantDailyAttendance) {
+        return R.ok(this.merchantDailyAttendanceService.updateById(merchantDailyAttendance));
+    }
+
+    /**
+     * 删除数据
+     *
+     * @param idList 主键结合
+     * @return 删除结果
+     */
+    @DeleteMapping
+    public R delete(@RequestParam("idList") List<Long> idList) {
+        return R.ok(this.merchantDailyAttendanceService.removeByIds(idList));
+    }
+}
+

+ 2 - 1
nightFragrance-massage/src/main/java/com/ylx/massage/domain/MaProject.java

@@ -7,6 +7,7 @@ import io.swagger.annotations.ApiModelProperty;
 import com.ylx.common.annotation.Excel;
 import com.ylx.common.annotation.Excel;
 import com.ylx.common.core.domain.BaseEntity;
 import com.ylx.common.core.domain.BaseEntity;
 import lombok.Data;
 import lombok.Data;
+import java.util.Date;
 
 
 /**
 /**
  * 服务项目对象 ma_project
  * 服务项目对象 ma_project
@@ -147,7 +148,7 @@ public class MaProject extends BaseEntity {
     /** 申请时间 */
     /** 申请时间 */
     @Excel(name = "申请时间")
     @Excel(name = "申请时间")
     @ApiModelProperty("申请时间")
     @ApiModelProperty("申请时间")
-    private Data applyTime;
+    private Date applyTime;
     /**
     /**
      * 修改人
      * 修改人
      */
      */

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

@@ -15,11 +15,11 @@ public class MaTeProject {
      * 商户ID
      * 商户ID
      */
      */
     @TableField("te_id")
     @TableField("te_id")
-    private Long teId;
+    private Integer teId;
 
 
     /**
     /**
      * 项目ID
      * 项目ID
      */
      */
     @TableField("project_id")
     @TableField("project_id")
-    private Long projectId;
+    private Integer projectId;
 }
 }

+ 80 - 58
nightFragrance-massage/src/main/java/com/ylx/massage/domain/MaTechnician.java

@@ -10,6 +10,7 @@ import lombok.experimental.Accessors;
 import com.ylx.common.annotation.Excel;
 import com.ylx.common.annotation.Excel;
 import com.ylx.common.core.domain.BaseEntity;
 import com.ylx.common.core.domain.BaseEntity;
 
 
+import java.time.LocalDate;
 import java.util.Date;
 import java.util.Date;
 
 
 
 
@@ -124,12 +125,12 @@ public class MaTechnician extends BaseEntity {
     @TableField("te_project")
     @TableField("te_project")
     private String teProject;
     private String teProject;
 
 
-    /**
-     * 生活照
-     */
-    @Excel(name = "生活照")
-    @TableField("life_photos")
-    private String lifePhotos;
+//    /**
+//     * 生活照
+//     */
+//    @Excel(name = "生活照")
+//    @TableField("life_photos")
+//    private String lifePhotos;
 
 
     /**
     /**
      * 形象照
      * 形象照
@@ -137,58 +138,65 @@ public class MaTechnician extends BaseEntity {
     @Excel(name = "形象照")
     @Excel(name = "形象照")
     @TableField("avatar")
     @TableField("avatar")
     private String avatar;
     private String avatar;
-
-    /**
-     * 身份证
-     */
-    @Excel(name = "身份证")
-    @TableField("id_card")
-    private String idCard;
-
-    /**
-     * 健康证
-     */
-    @Excel(name = "健康证")
-    @TableField("health_certificate")
-    private String healthCertificate;
-
-    /**
-     * 从业资格证
-     */
-    @Excel(name = "从业资格证")
-    @TableField("qualification_certificate")
-    private String qualificationCertificate;
-
-    /**
-     * 无犯罪证明
-     */
-    @Excel(name = "无犯罪证明")
-    @TableField("no_crime_record")
-    private String noCrimeRecord;
-    /**
-     * 宣传视频
-     */
-    @Excel(name = "宣传视频")
-    @TableField("promo_video")
-    private String promoVideo;
-    /**
-     * 承诺书
-     */
-    @Excel(name = "承诺书")
-    @TableField("commitment_pdf")
-    private String commitmentPdf;
-    /**
-     * 承诺录音
-     */
-    @Excel(name = "承诺录音")
-    @TableField("commitment_audio")
-    private String commitmentAudio;
-    /**
-     * 承诺录像
-     */
-    @Excel(name = "承诺录像")
-    @TableField("commitment_video")
-    private String commitmentVideo;
+//
+//    /**
+//     * 身份证
+//     */
+//    @Excel(name = "身份证")
+//    @TableField("id_card")
+//    private String idCard;
+//
+//    /**
+//     * 健康证
+//     */
+//    @Excel(name = "健康证")
+//    @TableField("health_certificate")
+//    private String healthCertificate;
+//
+//    /**
+//     * 从业资格证
+//     */
+//    @Excel(name = "从业资格证")
+//    @TableField("qualification_certificate")
+//    private String qualificationCertificate;
+//
+//    /**
+//     * 无犯罪证明
+//     */
+//    @Excel(name = "无犯罪证明")
+//    @TableField("no_crime_record")
+//    private String noCrimeRecord;
+//    /**
+//     * 宣传视频
+//     */
+//    @Excel(name = "宣传视频")
+//    @TableField("promo_video")
+//    private String promoVideo;
+//    /**
+//     * 承诺书
+//     */
+//    @Excel(name = "承诺书")
+//    @TableField("commitment_pdf")
+//    private String commitmentPdf;
+//    /**
+//     * 承诺录音
+//     */
+//    @Excel(name = "承诺录音")
+//    @TableField("commitment_audio")
+//    private String commitmentAudio;
+//    /**
+//     * 承诺录像
+//     */
+//    @Excel(name = "承诺录像")
+//    @TableField("commitment_video")
+//    private String commitmentVideo;
+
+    /**
+     * 身份证过期日期
+     */
+    @Excel(name = "身份证过期日期")
+    @TableField("id_card_expiration_date")
+    private LocalDate idCardExpirationDate;
 
 
     /**
     /**
      * 简介
      * 简介
@@ -197,12 +205,26 @@ public class MaTechnician extends BaseEntity {
     @TableField("te_brief")
     @TableField("te_brief")
     private String teBrief;
     private String teBrief;
 
 
+    /**
+     * 健康证过期日期
+     */
+    @Excel(name = "健康证过期日期")
+    @TableField("health_certificate_expiration_date")
+    private LocalDate healthCertificateExpirationDate;
+
     /**
     /**
      * 服务状态(0服务中,1可服务)
      * 服务状态(0服务中,1可服务)
      */
      */
     @Excel(name = "服务状态(0服务中,1可服务)")
     @Excel(name = "服务状态(0服务中,1可服务)")
     private Integer serviceState;
     private Integer serviceState;
 
 
+    /**
+     * 从业资格证过期日期
+     */
+    @Excel(name = "从业资格证过期日期")
+    @TableField("qualification_certificate_expiration_date")
+    private LocalDate qualificationCertificateExpirationDate;
+
     /**
     /**
      * 上岗状态 (-1:未上岗 0:已上岗 1:已申请)
      * 上岗状态 (-1:未上岗 0:已上岗 1:已申请)
      */
      */

+ 74 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/MerchantApplyFile.java

@@ -0,0 +1,74 @@
+package com.ylx.massage.domain;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 入驻申请附件表(MerchantApplyFile)表实体类
+ *
+ * @author makejava
+ * @since 2026-06-05 16:12:22
+ */
+@SuppressWarnings("serial")
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName(value = "merchant_apply_file", autoResultMap = true)
+public class MerchantApplyFile implements Serializable {
+    //主键ID
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+    //商户ID
+    @TableField("merchant_id")
+    private Integer merchantId;
+    //文件类型//文件类型1-形象照,2-生活照,3-身份证正面
+    //    // 4-身份证反面 5-手持身份证 6-健康证,
+    //    // 7-从业资格证,8-无犯罪证明,9-承诺书,10-承诺录音,11-承诺录像,12-其他 默认为:'',
+    @TableField("file_type")
+    private String fileType;
+    //原始文件名
+    @TableField("file_name")
+    private String fileName;
+    //文件访问地址
+    @TableField("file_url")
+    private String fileUrl;
+    //文件大小,单位字节
+    @TableField("file_size")
+    private Long fileSize;
+    //文件MIME类型,如 image/jpeg
+    @TableField("content_type")
+    private String contentType;
+    //创建人
+    @TableField("create_by")
+    private String createBy;
+    /**
+     * 创建时间
+     */
+    @TableField(value = "create_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
+    private LocalDateTime updateTime;
+    //修改人
+    @TableField("update_by")
+    private String updateBy;
+    //是否删除(0否1是)
+    @TableField("is_delete")
+    private Integer isDelete;
+
+}
+

+ 82 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/MerchantDailyAttendance.java

@@ -0,0 +1,82 @@
+package com.ylx.massage.domain;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 商户每日考勤统计表(MerchantDailyAttendance)表实体类
+ *
+ * @author makejava
+ * @since 2026-06-05 11:16:08
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName(value = "merchant_daily_attendance", autoResultMap = true)
+public class MerchantDailyAttendance implements Serializable {
+//主键ID
+    /**
+     * 主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+    //关联商户ID
+    @TableField("merchant_id")
+    private Integer merchantId;
+    //关联商户姓名
+    @TableField("merchant_name")
+    private String merchantName;
+    //考勤日期 (对应UI中的"日期")
+    @TableField("attendance_date")
+    private Date attendanceDate;
+    //当日首次打卡/上线时间
+    @TableField("attendance_start_time")
+    private Date attendanceStartTime;
+    //当日末次打卡/下线时间
+    @TableField("attendance_end_time")
+    private Date attendanceEndTime;
+    //日累计工作时长(分钟),方便精确计算
+    @TableField("total_work_minutes")
+    private Integer totalWorkMinutes;
+    //考勤状态: 1-正常, 2-异常
+    @TableField("attendance_status")
+    private Integer attendanceStatus;
+    //扣款金额
+    @TableField("deduction_amount")
+    private Double deductionAmount;
+    //备注
+    @TableField("remark")
+    private String remark;
+    //创建人
+    @TableField("create_by")
+    private String createBy;
+    /**
+     * 创建时间
+     */
+    @TableField(value = "create_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
+    private LocalDateTime updateTime;
+    //修改人
+    @TableField("update_by")
+    private String updateBy;
+    //是否删除(0否1是)
+    @TableField("is_delete")
+    private Integer isDelete;
+}
+

+ 42 - 47
nightFragrance-massage/src/main/java/com/ylx/massage/domain/TLbt.java

@@ -5,7 +5,6 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Getter;
 import lombok.Getter;
@@ -16,9 +15,7 @@ import java.io.Serializable;
 import java.util.Date;
 import java.util.Date;
 
 
 /**
 /**
- * <p>
  * 轮播图
  * 轮播图
- * </p>
  *
  *
  * @author YJR
  * @author YJR
  * @since 2023-11-24
  * @since 2023-11-24
@@ -33,70 +30,68 @@ public class TLbt implements Serializable {
     private static final long serialVersionUID = 1L;
     private static final long serialVersionUID = 1L;
 
 
     /**
     /**
-     * 主键
+     * 主键
      */
      */
-    @TableId("c_id")
-    @ApiModelProperty("cId")
-    @JsonProperty("cId")
-    private String cId;
+    @TableId("id")
+    @ApiModelProperty("主键")
+    private String id;
 
 
     /**
     /**
-     * 图片地址
+     * 标题。
      */
      */
-    @TableField("c_img_url")
-    @ApiModelProperty("图片地址")
-    @JsonProperty("cImgUrl")
-    private String cImgUrl;
+    @TableField("title")
+    @ApiModelProperty("标题")
+    private String title;
 
 
-    @TableField("c_jump_url")
-    @ApiModelProperty("跳转地址")
-    @JsonProperty("cJumpUrl")
-    private String cJumpUrl;
+    /**
+     * 图片地址。
+     */
+    @TableField("img_url")
+    @ApiModelProperty("图片地址")
+    private String imgUrl;
 
 
-    @TableField("c_jump_type")
-    @ApiModelProperty("跳转类型")
-    @JsonProperty("cJumpType")
-    private Integer cJumpType;
+    /**
+     * 跳转地址,支持 HTTP 链接或内部路由。
+     */
+    @TableField("jump_url")
+    @ApiModelProperty("跳转地址,支持HTTP链接或内部路由")
+    private String jumpUrl;
 
 
     /**
     /**
-     * 描述
+     * 序号。
      */
      */
-    @TableField("c_describe")
-    @ApiModelProperty("描述")
-    @JsonProperty("cDescribe")
-    private String cDescribe;
+    @TableField("sort")
+    @ApiModelProperty("序号")
+    private Integer sort;
 
 
     /**
     /**
-     * 文本内容
+     * 显示状态:0-隐藏,1-显示。
      */
      */
-    @TableField("c_content")
-    @ApiModelProperty("文本内容")
-    @JsonProperty("cContent")
-    private String cContent;
+    @TableField("status")
+    @ApiModelProperty("显示状态:0-隐藏,1-显示")
+    private Integer status;
 
 
     /**
     /**
-     * 序号
+     * 创建时间。
      */
      */
-    @TableField("c_sort")
-    @ApiModelProperty("序号")
-    @JsonProperty("cSort")
-    private Integer cSort;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField("create_time")
+    @ApiModelProperty("创建时间")
+    private Date createTime;
 
 
-    @TableField("c_status")
-    @ApiModelProperty("显示状态: 0-隐藏, 1-显示")
-    @JsonProperty("cStatus")
-    private String cStatus;
+    /**
+     * 修改时间。
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField("update_time")
+    @ApiModelProperty("修改时间")
+    private Date updateTime;
 
 
     /**
     /**
-     * 是否删除 0否1是
+     * 是否删除:0-否,1-是。
      */
      */
-    @ApiModelProperty("是否删除0否1是")
     @TableLogic
     @TableLogic
     @TableField("is_delete")
     @TableField("is_delete")
-    @JsonProperty("isDelete")
+    @ApiModelProperty("是否删除:0-否,1-是")
     private Integer isDelete;
     private Integer isDelete;
-
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date createTime;
-
 }
 }

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

@@ -47,7 +47,7 @@ public class MaTechnicianMerchantAddDTO {
      * 商户开通的服务项目ID集合。
      * 商户开通的服务项目ID集合。
      */
      */
     @ApiModelProperty("服务项目ID集合")
     @ApiModelProperty("服务项目ID集合")
-    private List<Long> projectIds;
+    private List<Integer> projectIds;
 
 
     /**
     /**
      * 商户类型:0-真实商户,1-虚拟商户。
      * 商户类型:0-真实商户,1-虚拟商户。

+ 63 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/dto/MaTechnicianPendingAuditSubmitDTO.java

@@ -0,0 +1,63 @@
+package com.ylx.massage.domain.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDate;
+
+/**
+ * 后台商户待审核通过参数。
+ */
+@Data
+@ApiModel(value = "MaTechnicianPendingAuditSubmitDTO", description = "后台商户待审核通过参数")
+public class MaTechnicianPendingAuditSubmitDTO {
+
+    /**
+     * 加密后的身份证正面图片文件地址。
+     */
+    @ApiModelProperty("加密后的身份证正面图片文件地址")
+    private String idCardFront;
+
+    /**
+     * 加密后的身份证反面图片文件地址。
+     */
+    @ApiModelProperty("加密后的身份证反面图片文件地址")
+    private String idCardBack;
+
+    /**
+     * 加密后的健康证图片文件地址。
+     */
+    @ApiModelProperty("加密后的健康证图片文件地址")
+    private String healthCertificate;
+
+    /**
+     * 加密后的资格证图片文件地址。
+     */
+    @ApiModelProperty("加密后的资格证图片文件地址")
+    private String qualificationCertificate;
+
+    /**
+     * 身份证到期日期。
+     */
+    @ApiModelProperty("身份证到期日期,格式:yyyy-MM-dd")
+    private LocalDate idCardExpirationDate;
+
+    /**
+     * 健康证到期日期。
+     */
+    @ApiModelProperty("健康证到期日期,格式:yyyy-MM-dd")
+    private LocalDate healthCertificateExpirationDate;
+
+    /**
+     * 资格证到期日期。
+     */
+    @ApiModelProperty("资格证到期日期,格式:yyyy-MM-dd")
+    private LocalDate qualificationCertificateExpirationDate;
+
+    /**
+     * 审核备注。
+     */
+    @ApiModelProperty("审核备注")
+    private String auditRemark;
+}

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

@@ -0,0 +1,21 @@
+package com.ylx.massage.domain.dto;
+
+import lombok.Data;
+
+@Data
+public class MerchantApplyFileDto {
+    //商户ID
+    private Integer merchantId;
+    //文件类型1-形象照,2-生活照,3-身份证正面
+    // 4-身份证反面 5-手持身份证 6-健康证,
+    // 7-从业资格证,8-无犯罪证明,9-承诺书,10-承诺录音,11-承诺录像,12-其他 默认为:'',
+    private String fileType;
+    //原始文件名
+    private String fileName;
+    //文件访问地址
+    private String fileUrl;
+    //文件大小,单位字节
+    private Long fileSize;
+    //文件MIME类型,如 image/jpeg
+    private String contentType;
+}

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

@@ -87,12 +87,12 @@ public class MaTechnicianAppAddVo {
     @ApiModelProperty("头像")
     @ApiModelProperty("头像")
     private String teAvatar;
     private String teAvatar;
 
 
-    /**
-     * 生活照
-     */
-    @Excel(name = "生活照")
-    @ApiModelProperty("生活照")
-    private String lifePhotos;
+//    /**
+//     * 生活照
+//     */
+//    @Excel(name = "生活照")
+//    @ApiModelProperty("生活照")
+//    private String lifePhotos;
 
 
     /**
     /**
      * 简介
      * 简介
@@ -107,58 +107,58 @@ public class MaTechnicianAppAddVo {
     @Excel(name = "形象照")
     @Excel(name = "形象照")
     @ApiModelProperty("形象照")
     @ApiModelProperty("形象照")
     private String avatar;
     private String avatar;
-
-    /**
-     * 身份证
-     */
-    @Excel(name = "身份证")
-    @ApiModelProperty("身份证")
-    private String idCard;
-    /**
-     * 宣传视频
-     */
-    @Excel(name = "宣传视频")
-    @ApiModelProperty("宣传视频")
-    private String promoVideo;
-    /**
-     * 健康证
-     */
-    @Excel(name = "健康证")
-    @ApiModelProperty("健康证")
-    private String healthCertificate;
-
-    /**
-     * 从业资格证
-     */
-    @Excel(name = "从业资格证")
-    @ApiModelProperty("从业资格证")
-    private String qualificationCertificate;
-
-    /**
-     * 无犯罪证明
-     */
-    @Excel(name = "无犯罪证明")
-    @ApiModelProperty("无犯罪证明")
-    private String noCrimeRecord;
-
-    /**
-     * 承诺书
-     */
-    @Excel(name = "承诺书")
-    @ApiModelProperty("承诺书")
-    private String commitmentPdf;
-    /**
-     * 承诺录音
-     */
-    @Excel(name = "承诺录音")
-    @ApiModelProperty("承诺录音")
-    private String commitmentAudio;
-    /**
-     * 承诺录像
-     */
-    @Excel(name = "承诺录像")
-    @ApiModelProperty("承诺录像")
-    private String commitmentVideo;
+//
+//    /**
+//     * 身份证
+//     */
+//    @Excel(name = "身份证")
+//    @ApiModelProperty("身份证")
+//    private String idCard;
+//    /**
+//     * 宣传视频
+//     */
+//    @Excel(name = "宣传视频")
+//    @ApiModelProperty("宣传视频")
+//    private String promoVideo;
+//    /**
+//     * 健康证
+//     */
+//    @Excel(name = "健康证")
+//    @ApiModelProperty("健康证")
+//    private String healthCertificate;
+//
+//    /**
+//     * 从业资格证
+//     */
+//    @Excel(name = "从业资格证")
+//    @ApiModelProperty("从业资格证")
+//    private String qualificationCertificate;
+//
+//    /**
+//     * 无犯罪证明
+//     */
+//    @Excel(name = "无犯罪证明")
+//    @ApiModelProperty("无犯罪证明")
+//    private String noCrimeRecord;
+//
+//    /**
+//     * 承诺书
+//     */
+//    @Excel(name = "承诺书")
+//    @ApiModelProperty("承诺书")
+//    private String commitmentPdf;
+//    /**
+//     * 承诺录音
+//     */
+//    @Excel(name = "承诺录音")
+//    @ApiModelProperty("承诺录音")
+//    private String commitmentAudio;
+//    /**
+//     * 承诺录像
+//     */
+//    @Excel(name = "承诺录像")
+//    @ApiModelProperty("承诺录像")
+//    private String commitmentVideo;
     /**
     /**
      * 审核状态:0-待审核,1-待审核,2-审核通过,3-审核驳回
      * 审核状态:0-待审核,1-待审核,2-审核通过,3-审核驳回
      */
      */
@@ -172,6 +172,6 @@ public class MaTechnicianAppAddVo {
     @ApiModelProperty("审批时间")
     @ApiModelProperty("审批时间")
     private Date approveTime;
     private Date approveTime;
     @ApiModelProperty("项目id集合")
     @ApiModelProperty("项目id集合")
-    private ArrayList<Long> projectIds;
+    private ArrayList<Integer> projectIds;
 
 
 }
 }

+ 6 - 2
nightFragrance-massage/src/main/java/com/ylx/massage/domain/vo/MaTechnicianCertificateVO.java

@@ -20,8 +20,12 @@ public class MaTechnicianCertificateVO {
     @ApiModelProperty("生活照")
     @ApiModelProperty("生活照")
     private String lifePhotos;
     private String lifePhotos;
 
 
-    @ApiModelProperty("身份证")
-    private String idCard;
+    @ApiModelProperty("身份证人像面")
+    private String idCardFrout;
+    @ApiModelProperty("身份证国徽面")
+    private String idCardBack;
+    @ApiModelProperty("手持身份证照片")
+    private String idCardHandheld;
 
 
     @ApiModelProperty("健康证")
     @ApiModelProperty("健康证")
     private String healthCertificate;
     private String healthCertificate;

+ 112 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/enums/FileTypeEnum.java

@@ -0,0 +1,112 @@
+package com.ylx.massage.enums;
+
+import com.alibaba.druid.sql.dialect.odps.ast.OdpsAddFileStatement;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 商户申请附件 - 文件类型枚举
+ */
+@Getter
+@AllArgsConstructor
+public enum FileTypeEnum {
+
+    /**
+     * 1-形象照
+     */
+    PORTRAIT("1", "形象照"),
+
+    /**
+     * 2-生活照
+     */
+    LIFE_PHOTO("2", "生活照"),
+
+    /**
+     * 3-身份证正面
+     */
+    ID_CARD_FRONT("3", "身份证正面"),
+
+    /**
+     * 4-身份证反面
+     */
+    ID_CARD_BACK("4", "身份证反面"),
+
+    /**
+     * 5-手持身份证
+     */
+    ID_CARD_HANDHELD("5", "手持身份证"),
+
+    /**
+     * 6-健康证
+     */
+    HEALTH_CERT("6", "健康证"),
+
+    /**
+     * 7-从业资格证
+     */
+    QUALIFICATION_CERT("7", "从业资格证"),
+
+    /**
+     * 8-无犯罪证明
+     */
+    NO_CRIME_RECORD("8", "无犯罪证明"),
+
+    /**
+     * 9-承诺书
+     */
+    COMMITMENT_LETTER("9", "承诺书"),
+
+    /**
+     * 10-承诺录音
+     */
+    COMMITMENT_AUDIO("10", "承诺录音"),
+
+    /**
+     * 11-承诺录像
+     */
+    COMMITMENT_VIDEO("11", "承诺录像"),
+
+    /**
+     * 12-其他
+     */
+    OTHER("12", "其他");
+
+    /**
+     * 类型代码 (String)
+     */
+    private  String code;
+
+    /**
+     * 描述信息
+     */
+    private  String desc;
+
+    /**
+     * 根据 code 获取对应的枚举对象
+     *
+     * @param code 类型代码
+     * @return 对应的枚举对象,如果未找到则返回 null
+     */
+    public static FileTypeEnum getByCode(String code) {
+        if (code == null) {
+            return null;
+        }
+        for (FileTypeEnum type : FileTypeEnum.values()) {
+            if (type.getCode().equals(code)) {
+                return type;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 根据 code 获取对应的描述信息
+     *
+     * @param code 类型代码
+     * @return 描述信息,如果未找到则返回空字符串或原值
+     */
+    public static String getDescByCode(String code) {
+       FileTypeEnum type = getByCode(code);
+        return type != null ? type.getDesc() : "";
+    }
+}

+ 24 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/enums/TechnicianStatusEnum.java

@@ -0,0 +1,24 @@
+package com.ylx.massage.enums;
+
+import lombok.Data;
+
+
+public enum TechnicianStatusEnum {
+    ONLINE(1,"接单中"),
+    RESTING(0,"休息中");
+
+    private final Integer code;
+    private final String desc;
+
+    TechnicianStatusEnum(Integer code,String desc) {
+        this.desc = desc;
+        this.code = code;
+    }
+    public Integer getCode() {
+        return code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

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

@@ -28,7 +28,7 @@ public interface MaTeProjectMapper extends BaseMapper<MaTeProject> {
      * @param technicianId 商户ID
      * @param technicianId 商户ID
      * @return 影响行数
      * @return 影响行数
      */
      */
-    default int deleteByTechnicianId(Long technicianId) {
+    default int deleteByTechnicianId(Integer technicianId) {
         return delete(new LambdaQueryWrapper<MaTeProject>().eq(MaTeProject::getTeId, technicianId));
         return delete(new LambdaQueryWrapper<MaTeProject>().eq(MaTeProject::getTeId, technicianId));
     }
     }
 }
 }

+ 10 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/mapper/MaTechnicianMapper.java

@@ -161,6 +161,16 @@ public interface MaTechnicianMapper extends BaseMapper<MaTechnician>
         return updateById(maTechnician);
         return updateById(maTechnician);
     }
     }
 
 
+    /**
+     * 根据商户ID审核通过待审核商户。
+     *
+     * @param maTechnician 商户审核信息
+     * @return 影响行数
+     */
+    default int approvePendingMerchantAuditById(MaTechnician maTechnician) {
+        return updateById(maTechnician);
+    }
+
     List<MerchantVo> getMerchantRecommend(@Param("dto") MassageMerchantRecommendDto dto);
     List<MerchantVo> getMerchantRecommend(@Param("dto") MassageMerchantRecommendDto dto);
 
 
     /**
     /**

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

@@ -0,0 +1,18 @@
+package com.ylx.massage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ylx.massage.domain.MerchantApplyFile;
+import org.apache.ibatis.annotations.Mapper;
+
+
+/**
+ * 入驻申请附件表(MerchantApplyFile)表数据库访问层
+ *
+ * @author makejava
+ * @since 2026-06-05 16:26:47
+ */
+@Mapper
+public interface MerchantApplyFileMapper extends BaseMapper<MerchantApplyFile> {
+
+}
+

+ 17 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/mapper/MerchantDailyAttendanceMapper.java

@@ -0,0 +1,17 @@
+package com.ylx.massage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ylx.massage.domain.MerchantDailyAttendance;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 商户每日考勤统计表(MerchantDailyAttendance)表数据库访问层
+ *
+ * @author makejava
+ * @since 2026-06-05 11:16:04
+ */
+@Mapper
+public interface MerchantDailyAttendanceMapper extends BaseMapper<MerchantDailyAttendance> {
+
+}
+

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

@@ -8,12 +8,15 @@ import com.ylx.common.core.domain.AjaxResult;
 import com.ylx.common.core.domain.model.LoginUser;
 import com.ylx.common.core.domain.model.LoginUser;
 import com.ylx.massage.domain.MaProject;
 import com.ylx.massage.domain.MaProject;
 import com.ylx.massage.domain.MaTechnician;
 import com.ylx.massage.domain.MaTechnician;
+import com.ylx.massage.domain.dto.*;
+import com.ylx.massage.domain.vo.*;
 import com.ylx.massage.domain.dto.MaProjectSaveDto;
 import com.ylx.massage.domain.dto.MaProjectSaveDto;
 import com.ylx.massage.domain.dto.MaTechnicianAuditQueryDTO;
 import com.ylx.massage.domain.dto.MaTechnicianAuditQueryDTO;
 import com.ylx.massage.domain.dto.MaTechnicianAuditSubmitDTO;
 import com.ylx.massage.domain.dto.MaTechnicianAuditSubmitDTO;
 import com.ylx.massage.domain.dto.MassageMerchantRecommendDto;
 import com.ylx.massage.domain.dto.MassageMerchantRecommendDto;
 import com.ylx.massage.domain.dto.MaTechnicianMerchantAddDTO;
 import com.ylx.massage.domain.dto.MaTechnicianMerchantAddDTO;
 import com.ylx.massage.domain.dto.MaTechnicianMerchantQueryDTO;
 import com.ylx.massage.domain.dto.MaTechnicianMerchantQueryDTO;
+import com.ylx.massage.domain.dto.MaTechnicianPendingAuditSubmitDTO;
 import com.ylx.massage.domain.vo.MaTechnicianAppAddVo;
 import com.ylx.massage.domain.vo.MaTechnicianAppAddVo;
 import com.ylx.massage.domain.vo.MaTechnicianAuditListVO;
 import com.ylx.massage.domain.vo.MaTechnicianAuditListVO;
 import com.ylx.massage.domain.vo.MaTechnicianCertificateVO;
 import com.ylx.massage.domain.vo.MaTechnicianCertificateVO;
@@ -103,6 +106,16 @@ public interface IMaTechnicianService extends IService<MaTechnician> {
      */
      */
     int submitMerchantAudit(Integer id, MaTechnicianAuditSubmitDTO dto, LoginUser loginUser);
     int submitMerchantAudit(Integer id, MaTechnicianAuditSubmitDTO dto, LoginUser loginUser);
 
 
+    /**
+     * 后台待审核页面审核通过商户。
+     *
+     * @param id        商户ID
+     * @param dto       待审核通过参数
+     * @param loginUser 当前登录用户
+     * @return 结果
+     */
+    int approvePendingMerchantAudit(Integer id, MaTechnicianPendingAuditSubmitDTO dto, LoginUser loginUser);
+
     /**
     /**
      * 后台查询商户列表
      * 后台查询商户列表
      *
      *
@@ -169,7 +182,17 @@ public interface IMaTechnicianService extends IService<MaTechnician> {
      * @param req
      * @param req
      */
      */
     void apply(MaTechnicianAppAddVo req);
     void apply(MaTechnicianAppAddVo req);
-
+    /**
+     * 申请技师文件
+     * @param req
+     */
+    void applyFile(MerchantApplyFileDto req);
+    /**
+     * 技师状态切换
+     *
+     * @param
+     */
+    Result switchToOffline(Long userId, Boolean forceConfirm);
     /**
     /**
      * 技师列表
      * 技师列表
      *
      *

+ 18 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/service/MerchantDailyAttendanceService.java

@@ -0,0 +1,18 @@
+package com.ylx.massage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ylx.massage.domain.MerchantDailyAttendance;
+import org.springframework.stereotype.Service;
+
+
+/**
+ * 商户每日考勤统计表(MerchantDailyAttendance)表服务接口
+ *
+ * @author makejava
+ * @since 2026-06-05 11:16:10
+ */
+@Service
+public interface MerchantDailyAttendanceService extends IService<MerchantDailyAttendance> {
+
+}
+

+ 427 - 93
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/MaTechnicianServiceImpl.java

@@ -1,17 +1,33 @@
 package com.ylx.massage.service.impl;
 package com.ylx.massage.service.impl;
 
 
+import java.math.BigDecimal;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.util.*;
 import java.util.*;
 import java.util.function.Function;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ylx.attendanceconfig.domain.AttendanceRule;
+import com.ylx.attendanceconfig.mapper.AttendanceRuleMapper;
 import com.ylx.common.core.domain.AjaxResult;
 import com.ylx.common.core.domain.AjaxResult;
 import com.ylx.common.core.domain.model.LoginUser;
 import com.ylx.common.core.domain.model.LoginUser;
 import com.ylx.common.exception.ServiceException;
 import com.ylx.common.exception.ServiceException;
 import com.ylx.common.utils.DateUtils;
 import com.ylx.common.utils.DateUtils;
 import com.ylx.common.utils.StringUtils;
 import com.ylx.common.utils.StringUtils;
+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.ProjectCategoryEnum;
+import com.ylx.massage.enums.TechnicianStatusEnum;
+import com.ylx.massage.mapper.*;
 import com.ylx.massage.domain.ContractRecord;
 import com.ylx.massage.domain.ContractRecord;
 import com.ylx.massage.domain.MaProject;
 import com.ylx.massage.domain.MaProject;
 import com.ylx.massage.domain.MaTeProject;
 import com.ylx.massage.domain.MaTeProject;
@@ -37,12 +53,14 @@ import lombok.Data;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
-import com.ylx.massage.mapper.MaTechnicianMapper;
-import com.ylx.massage.domain.MaTechnician;
 import com.ylx.massage.service.IMaTechnicianService;
 import com.ylx.massage.service.IMaTechnicianService;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.MultipartFile;
 
 
+import javax.annotation.Resource;
+
+import static com.ylx.massage.enums.FileTypeEnum.*;
+
 /**
 /**
  * 技师Service业务层处理
  * 技师Service业务层处理
  *
  *
@@ -65,12 +83,12 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
     private static final Integer NOT_DELETED = 0;
     private static final Integer NOT_DELETED = 0;
     private static final String MERCHANT_STATUS_NORMAL = "0";
     private static final String MERCHANT_STATUS_NORMAL = "0";
 
 
-    @Autowired
+    @Resource
     private MaTechnicianMapper maTechnicianMapper;
     private MaTechnicianMapper maTechnicianMapper;
 
 
-    @Autowired
+    @Resource
     private MaTeProjectMapper maTeProjectMapper;
     private MaTeProjectMapper maTeProjectMapper;
-    @Autowired
+    @Resource
     private MaProjectMapper maProjectMapper;
     private MaProjectMapper maProjectMapper;
 
 
     @Autowired
     @Autowired
@@ -79,8 +97,17 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
     @Autowired
     @Autowired
     private TbFileService fileService;
     private TbFileService fileService;
 
 
-    @Autowired
+    @Resource
     private ContractRecordMapper contractRecordMapper;
     private ContractRecordMapper contractRecordMapper;
+    @Resource
+    private MerchantDailyAttendanceMapper merchantDailyAttendanceMapper;
+    @Resource
+    private AttendanceRuleMapper attendanceRuleMapper;
+    @Resource
+    private TAddressMapper addressMapper;
+    @Resource
+    private MerchantApplyFileMapper merchantApplyFileMapper;
+
 
 
     /**
     /**
      * 商户入驻申请注册
      * 商户入驻申请注册
@@ -101,6 +128,18 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
         maTechnicianMapper.insert(maTechnician);
         maTechnicianMapper.insert(maTechnician);
 
 
     }
     }
+    /**
+     * 商户入驻申请文件上传
+     * @param req
+     */
+    @Override
+    public  void applyFile(MerchantApplyFileDto req){
+        MerchantApplyFile maTechnician = new MerchantApplyFile();
+        BeanUtils.copyProperties(req, maTechnician);
+        maTechnician.setCreateBy(req.getMerchantId().toString());
+        maTechnician.setUpdateBy(req.getMerchantId().toString());
+        merchantApplyFileMapper.insert(maTechnician);
+    }
 
 
     /**
     /**
      * 商户入住前置条件校验
      * 商户入住前置条件校验
@@ -146,7 +185,7 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
         queryWrapper.eq(MaTechnician::getIsDelete, 0);
         queryWrapper.eq(MaTechnician::getIsDelete, 0);
         queryWrapper.eq(MaTechnician::getAuditStatus, 2);
         queryWrapper.eq(MaTechnician::getAuditStatus, 2);
         //queryWrapper.eq(MaTechnician::getOpenService, req.getOpenService());
         //queryWrapper.eq(MaTechnician::getOpenService, req.getOpenService());
-        queryWrapper.eq(MaTechnician::getServiceTag,req.getServiceTag());
+        queryWrapper.eq(MaTechnician::getServiceTag, req.getServiceTag());
         MaTechnician userProfile = maTechnicianMapper.selectOne(queryWrapper);
         MaTechnician userProfile = maTechnicianMapper.selectOne(queryWrapper);
         return userProfile;
         return userProfile;
     }
     }
@@ -282,7 +321,7 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
         if (id == null) {
         if (id == null) {
             throw new ServiceException("商户ID不能为空");
             throw new ServiceException("商户ID不能为空");
         }
         }
-        MaTechnician existsMerchant = maTechnicianMapper.selectMerchantById(id);
+        MaTechnician existsMerchant = maTechnicianMapper.selectMerchantById(id.intValue());
         if (existsMerchant == null || !NOT_DELETED.equals(existsMerchant.getIsDelete())) {
         if (existsMerchant == null || !NOT_DELETED.equals(existsMerchant.getIsDelete())) {
             throw new ServiceException("商户不存在或已删除");
             throw new ServiceException("商户不存在或已删除");
         }
         }
@@ -357,45 +396,6 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
         }
         }
         return uploadResult;
         return uploadResult;
     }
     }
-
-    /**
-     * 全量替换商户与服务项目关联关系。
-     *
-     * @param technicianId 商户ID
-     * @param projectIds   服务项目ID集合
-     */
-    private void replaceProjectRelations(Integer technicianId, Set<Long> projectIds) {
-        if (technicianId == null) {
-            throw new ServiceException("商户ID不能为空");
-        }
-        maTeProjectMapper.deleteByTechnicianId(technicianId.longValue());
-        for (Long projectId : projectIds) {
-            MaTeProject relation = new MaTeProject();
-            relation.setTeId(technicianId.longValue());
-            relation.setProjectId(projectId);
-            int rows = maTeProjectMapper.insert(relation);
-            if (rows <= 0) {
-                throw new ServiceException("编辑商户服务项目失败");
-            }
-        }
-    }
-
-    /**
-     * 后台查询商户入驻审核列表
-     *
-     * @param page 分页参数
-     * @param dto  查询条件
-     * @return 商户入驻审核分页列表
-     */
-    @Override
-    public Page<MaTechnicianAuditListVO> selectMerchantAuditList(Page<MaTechnicianAuditListVO> page, MaTechnicianAuditQueryDTO dto) {
-        if (dto != null && dto.getAuditStatus() != null) {
-            checkEnumValue(dto.getAuditStatus(), "审核状态", 0, 1, 2, 3);
-        }
-        Page<MaTechnicianAuditListVO> pageParam = page == null ? new Page<>(1, 10) : page;
-        return maTechnicianMapper.selectMerchantAuditList(pageParam, dto);
-    }
-
     /**
     /**
      * 商户入驻审核。
      * 商户入驻审核。
      *
      *
@@ -448,6 +448,92 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
         }
         }
         return rows;
         return rows;
     }
     }
+    /**
+     * 后台查询商户证照
+     *
+     * @param id 商户ID
+     * @return 商户证照
+     */
+    @Override
+    public MaTechnicianCertificateVO selectMerchantCertificate(Integer id) {
+        if (id == null) {
+            throw new ServiceException("商户ID不能为空");
+        }
+        LambdaQueryWrapper<MerchantApplyFile> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.eq(MerchantApplyFile::getMerchantId, id);
+        List<MerchantApplyFile> merchantApplyFiles = merchantApplyFileMapper.selectList(queryWrapper);
+        if (merchantApplyFiles == null) {
+            throw new ServiceException("商户不存在或已删除");
+        }
+        MaTechnicianCertificateVO certificate = new MaTechnicianCertificateVO();
+        certificate.setMerchantId(merchantApplyFiles.get(0).getMerchantId());
+        merchantApplyFiles.forEach(merchant -> {
+            certificate.setAvatar( typeFIleUrl(merchant,PORTRAIT.getCode()));
+            certificate.setLifePhotos( typeFIleUrl(merchant,LIFE_PHOTO.getCode()));
+            certificate.setIdCardFrout( typeFIleUrl(merchant,ID_CARD_FRONT.getCode()));
+            certificate.setIdCardBack( typeFIleUrl(merchant,ID_CARD_BACK.getCode()));
+            certificate.setIdCardHandheld( typeFIleUrl(merchant,ID_CARD_HANDHELD.getCode()));
+            certificate.setHealthCertificate( typeFIleUrl(merchant,HEALTH_CERT.getCode()));
+            certificate.setQualificationCertificate( typeFIleUrl(merchant,QUALIFICATION_CERT.getCode()));
+            certificate.setNoCrimeRecord( typeFIleUrl(merchant,NO_CRIME_RECORD.getCode()));
+            certificate.setCommitmentPdf( typeFIleUrl(merchant,COMMITMENT_LETTER.getCode()));
+            certificate.setCommitmentVideo( typeFIleUrl(merchant,COMMITMENT_VIDEO.getCode()));
+            certificate.setCommitmentAudio( typeFIleUrl(merchant,COMMITMENT_AUDIO.getCode()));
+
+        });
+
+        return certificate;
+    }
+
+    private String typeFIleUrl(MerchantApplyFile merchant, String type) {
+
+        LambdaQueryWrapper<MerchantApplyFile> queryWrapper1 = Wrappers.lambdaQuery();
+        queryWrapper1.eq(MerchantApplyFile::getMerchantId, merchant.getMerchantId());
+        queryWrapper1.eq(MerchantApplyFile::getFileType, type);
+        MerchantApplyFile merchantApplyFiles = merchantApplyFileMapper.selectOne(queryWrapper1);
+        if (merchantApplyFiles == null) {
+            return null;
+        }
+        return merchantApplyFiles.getFileUrl();
+    }
+
+    /**
+     * 全量替换商户与服务项目关联关系。
+     *
+     * @param technicianId 商户ID
+     * @param projectIds   服务项目ID集合
+     */
+    private void replaceProjectRelations(Integer technicianId, Set<Integer> projectIds) {
+        if (technicianId == null) {
+            throw new ServiceException("商户ID不能为空");
+        }
+        maTeProjectMapper.deleteByTechnicianId(technicianId);
+        for (Integer projectId : projectIds) {
+            MaTeProject relation = new MaTeProject();
+            relation.setTeId(technicianId);
+            relation.setProjectId(projectId);
+            int rows = maTeProjectMapper.insert(relation);
+            if (rows <= 0) {
+                throw new ServiceException("编辑商户服务项目失败");
+            }
+        }
+    }
+
+    /**
+     * 后台查询商户入驻审核列表
+     *
+     * @param page 分页参数
+     * @param dto  查询条件
+     * @return 商户入驻审核分页列表
+     */
+    @Override
+    public Page<MaTechnicianAuditListVO> selectMerchantAuditList(Page<MaTechnicianAuditListVO> page, MaTechnicianAuditQueryDTO dto) {
+        if (dto != null && dto.getAuditStatus() != null) {
+            checkEnumValue(dto.getAuditStatus(), "审核状态", 0, 1, 2, 3);
+        }
+        Page<MaTechnicianAuditListVO> pageParam = page == null ? new Page<>(1, 10) : page;
+        return maTechnicianMapper.selectMerchantAuditList(pageParam, dto);
+    }
 
 
     /**
     /**
      * 后台查询商户列表
      * 后台查询商户列表
@@ -481,36 +567,6 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
         return detail;
         return detail;
     }
     }
 
 
-    /**
-     * 后台查询商户证照
-     *
-     * @param id 商户ID
-     * @return 商户证照
-     */
-    @Override
-    public MaTechnicianCertificateVO selectMerchantCertificate(Integer id) {
-        if (id == null) {
-            throw new ServiceException("商户ID不能为空");
-        }
-        MaTechnician merchant = maTechnicianMapper.selectMerchantCertificateById(id);
-        if (merchant == null || !NOT_DELETED.equals(merchant.getIsDelete())) {
-            throw new ServiceException("商户不存在或已删除");
-        }
-
-        MaTechnicianCertificateVO certificate = new MaTechnicianCertificateVO();
-        certificate.setMerchantId(merchant.getId());
-        certificate.setAvatar(merchant.getAvatar());
-        certificate.setLifePhotos(merchant.getLifePhotos());
-        certificate.setIdCard(merchant.getIdCard());
-        certificate.setHealthCertificate(merchant.getHealthCertificate());
-        certificate.setQualificationCertificate(merchant.getQualificationCertificate());
-        certificate.setNoCrimeRecord(merchant.getNoCrimeRecord());
-        certificate.setCommitmentPdf(merchant.getCommitmentPdf());
-        certificate.setCommitmentVideo(merchant.getCommitmentVideo());
-        certificate.setCommitmentAudio(merchant.getCommitmentAudio());
-        return certificate;
-    }
-
     /**
     /**
      * 修改技师
      * 修改技师
      *
      *
@@ -622,13 +678,13 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
      * @param categoryIds 服务类目ID集合
      * @param categoryIds 服务类目ID集合
      * @return 有效服务项目ID集合
      * @return 有效服务项目ID集合
      */
      */
-    private MerchantProjectSelection checkProjectIds(List<Long> projectIds, Set<Integer> categoryIds) {
+    private MerchantProjectSelection checkProjectIds(List<Integer> projectIds, Set<Integer> categoryIds) {
         if (projectIds == null || projectIds.isEmpty()) {
         if (projectIds == null || projectIds.isEmpty()) {
             throw new ServiceException("服务项目不能为空");
             throw new ServiceException("服务项目不能为空");
         }
         }
 
 
-        Set<Long> distinctProjectIds = new LinkedHashSet<>();
-        for (Long projectId : projectIds) {
+        Set<Integer> distinctProjectIds = new LinkedHashSet<>();
+        for (Integer projectId : projectIds) {
             if (projectId == null) {
             if (projectId == null) {
                 throw new ServiceException("服务项目ID不能为空");
                 throw new ServiceException("服务项目ID不能为空");
             }
             }
@@ -642,10 +698,10 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
             throw new ServiceException("服务项目不存在或已删除");
             throw new ServiceException("服务项目不存在或已删除");
         }
         }
 
 
-        Map<Long, Project> projectMap = projects.stream()
-                                                .collect(Collectors.toMap(project -> project.getId().longValue(), Function.identity(), (left, right) -> left));
+        Map<Integer, Project> projectMap = projects.stream()
+                                                .collect(Collectors.toMap(project -> project.getId(), Function.identity(), (left, right) -> left));
         Set<Integer> projectCategoryIds = new LinkedHashSet<>();
         Set<Integer> projectCategoryIds = new LinkedHashSet<>();
-        for (Long projectId : distinctProjectIds) {
+        for (Integer projectId : distinctProjectIds) {
             Project project = projectMap.get(projectId);
             Project project = projectMap.get(projectId);
             if (project == null || project.getCategoryId() == null) {
             if (project == null || project.getCategoryId() == null) {
                 throw new ServiceException("服务项目类目不能为空");
                 throw new ServiceException("服务项目类目不能为空");
@@ -687,7 +743,7 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
                        .collect(Collectors.joining(","));
                        .collect(Collectors.joining(","));
     }
     }
 
 
-    private String joinProjectTitles(Set<Long> projectIds, Map<Long, Project> projectMap) {
+    private String joinProjectTitles(Set<Integer> projectIds, Map<Integer, Project> projectMap) {
         return projectIds.stream()
         return projectIds.stream()
                        .map(projectMap::get)
                        .map(projectMap::get)
                        .map(Project::getTitle)
                        .map(Project::getTitle)
@@ -701,15 +757,15 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
      * @param technicianId
      * @param technicianId
      * @param projectIds
      * @param projectIds
      */
      */
-    private void insertProjectRelations(Integer technicianId, Set<Long> projectIds) {
+    private void insertProjectRelations(Integer technicianId, Set<Integer> projectIds) {
         if (technicianId == null) {
         if (technicianId == null) {
             throw new ServiceException("商户ID不能为空");
             throw new ServiceException("商户ID不能为空");
         }
         }
 
 
         List<MaTeProject> relations = new ArrayList<>();
         List<MaTeProject> relations = new ArrayList<>();
-        for (Long projectId : projectIds) {
+        for (Integer projectId : projectIds) {
             MaTeProject relation = new MaTeProject();
             MaTeProject relation = new MaTeProject();
-            relation.setTeId(technicianId.longValue());
+            relation.setTeId(technicianId);
             relation.setProjectId(projectId);
             relation.setProjectId(projectId);
             relations.add(relation);
             relations.add(relation);
         }
         }
@@ -721,10 +777,10 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
 
 
     private static class MerchantProjectSelection {
     private static class MerchantProjectSelection {
         private final Set<Integer> categoryIds;
         private final Set<Integer> categoryIds;
-        private final Set<Long> projectIds;
-        private final Map<Long, Project> projectMap;
+        private final Set<Integer> projectIds;
+        private final Map<Integer, Project> projectMap;
 
 
-        private MerchantProjectSelection(Set<Integer> categoryIds, Set<Long> projectIds, Map<Long, Project> projectMap) {
+        private MerchantProjectSelection(Set<Integer> categoryIds, Set<Integer> projectIds, Map<Integer, Project> projectMap) {
             this.categoryIds = categoryIds;
             this.categoryIds = categoryIds;
             this.projectIds = projectIds;
             this.projectIds = projectIds;
             this.projectMap = projectMap;
             this.projectMap = projectMap;
@@ -734,11 +790,11 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
             return categoryIds;
             return categoryIds;
         }
         }
 
 
-        private Set<Long> getProjectIds() {
+        private Set<Integer> getProjectIds() {
             return projectIds;
             return projectIds;
         }
         }
 
 
-        private Map<Long, Project> getProjectMap() {
+        private Map<Integer, Project> getProjectMap() {
             return projectMap;
             return projectMap;
         }
         }
     }
     }
@@ -799,9 +855,287 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
             maProject.setProjectLowestPrice(project.getPriceMin());
             maProject.setProjectLowestPrice(project.getPriceMin());
             maProject.setCreateBy(dto.getUserId());
             maProject.setCreateBy(dto.getUserId());
             maProject.setMerchantId(dto.getUserId());
             maProject.setMerchantId(dto.getUserId());
-            maProject.setApplyTime((Data) new Date());
+            maProject.setApplyTime(DateUtils.getNowDate());
             maProject.setMerchantPhone(dto.getMerchantPhone());
             maProject.setMerchantPhone(dto.getMerchantPhone());
+            maProject.setCreateTime(DateUtils.getNowDate());
             maProjectMapper.insert(maProject);
             maProjectMapper.insert(maProject);
         }
         }
     }
     }
+
+    /**
+     * 状态切换
+     *
+     * @param userId
+     * @param forceConfirm
+     * @return
+     */
+    @Override
+    public Result switchToOffline(Long userId, Boolean forceConfirm) {
+        MaTechnician technician = getTechnician(userId);
+
+        // 1. 基础权限校验 (对应流程图左下角)
+        if (!hasActiveSkills(userId)) {
+            throw new RuntimeException("请先申请开通技能");
+        }
+        if (!hasHomeAddress(userId)) {
+            // 这里通常会触发前端弹窗要求添加地址,或者直接阻断
+            throw new RuntimeException("请完善家庭地址");
+        }
+        if (ProjectCategoryEnum.MASSAGE.getCode().equals(technician.getServiceTag())) {
+            // 2. 状态判断逻辑 (对应流程图中间的菱形判断)
+            // 只有处于“在线接单”状态才需要检查疲劳度/时长限制
+            if (TechnicianStatusEnum.ONLINE.getCode().equals(technician.getPostState())) {
+                // 获取今日的商户考勤记录
+                MerchantDailyAttendance attendance = getTodayAttendance(userId);
+
+                long minutesOnline = 0;
+                if (attendance != null && attendance.getAttendanceStartTime() != null) {
+                    LocalDateTime localDateTime = attendance.getAttendanceStartTime().toInstant()
+                                                          .atZone(ZoneId.systemDefault())
+                                                          .toLocalDateTime();
+                    //计算截止现在的时长,单位为分钟
+                    minutesOnline = Duration.between(localDateTime, LocalDateTime.now()).toMinutes();
+                    // 计算今日的累加在线时长
+                    minutesOnline = minutesOnline + getWorkDuration(userId);
+                }
+                AttendanceRule rule = getAttendanceRule();
+                if (rule != null) {
+                    // 将小时转换为分钟进行比较
+                    BigDecimal minutes = rule.getBasicWorkHours().multiply(new BigDecimal(60));
+                    // 2. 精确转换成 long(无小数、无溢出才成功)
+                    long requiredMinutes = minutes.longValueExact();
+                    // 判断是否超过了平台规定的在线时间 (X小时)
+                    if (minutesOnline < requiredMinutes) {
+                        // 情况 A: 超时了,且用户还没有点击“确认下线”(forceConfirm=false)
+                        if (!forceConfirm) {
+                            // 返回特定错误码或数据结构,告诉前端弹出“我在想想/确认下线”的模态框
+                            return Result.ok("平台对您的在线时间做了约定,每日在线需满足"
+                                                     + (requiredMinutes / 60) + "小时,距离您下线时间还剩余" + ((requiredMinutes / 60) - minutesOnline) + "小时"
+                                                     + "不满足在线时间将收到平台处罚,是否确认下线?");
+                        }
+                        // 情况 B: 超时了,但用户已经点击了“确认下线”,允许通过
+                    }
+                }
+            }
+
+            // 3. 执行状态更新 (更新为休息中状态)
+            updateStatus(userId, TechnicianStatusEnum.RESTING);
+            if (!forceConfirm) {
+                // 查询商户今日的最近考勤记录
+                LambdaQueryWrapper<MerchantDailyAttendance> query = new LambdaQueryWrapper<>();
+                query.eq(MerchantDailyAttendance::getMerchantId, userId)
+                        .eq(MerchantDailyAttendance::getAttendanceDate, DateUtils.getNowDate())
+                        .orderByDesc(MerchantDailyAttendance::getCreateTime);
+                MerchantDailyAttendance update = merchantDailyAttendanceMapper.selectOne(query);
+                if (update != null) {
+                    LocalDateTime localDateTime = update.getAttendanceStartTime().toInstant()
+                                                          .atZone(ZoneId.systemDefault())
+                                                          .toLocalDateTime();
+                    LambdaUpdateWrapper<MerchantDailyAttendance> updateWrapper = new LambdaUpdateWrapper<>();
+                    updateWrapper.eq(MerchantDailyAttendance::getId, update.getId())
+                            .set(MerchantDailyAttendance::getAttendanceEndTime, DateUtils.getNowDate())
+                            .set(MerchantDailyAttendance::getTotalWorkMinutes, Duration.between(localDateTime, LocalDateTime.now()).toMinutes())
+                            .set(MerchantDailyAttendance::getUpdateTime, DateUtils.getNowDate());
+                    merchantDailyAttendanceMapper.update(update, updateWrapper);
+                }
+
+
+            }
+        } else {
+            //更新状态为在线接单
+            updateStatus(userId, TechnicianStatusEnum.ONLINE);
+            // 插入今日考勤记录
+            MerchantDailyAttendance merchantDailyAttendance = new MerchantDailyAttendance()
+                                                                      .setMerchantId(userId.intValue())
+                                                                      .setAttendanceDate(DateUtils.getNowDate())
+                                                                      .setMerchantName(technician.getTeName())
+                                                                      .setAttendanceStartTime(DateUtils.getNowDate())
+                                                                      .setCreateBy(technician.getTeName())
+                                                                      .setCreateTime(LocalDateTime.now());
+            merchantDailyAttendanceMapper.insert(merchantDailyAttendance);
+        }
+        return Result.ok("状态已切换成功");
+    }
+
+    /**
+     * 获取今天商户的考勤记录
+     *
+     * @param userId 技师ID
+     * @return 考勤记录
+     */
+    private MerchantDailyAttendance getTodayAttendance(Long userId) {
+        LambdaQueryWrapper<MerchantDailyAttendance> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(MerchantDailyAttendance::getMerchantId, userId)
+                .eq(MerchantDailyAttendance::getAttendanceDate, DateUtils.getNowDate())
+                .orderByDesc(MerchantDailyAttendance::getCreateTime)
+                .last("LIMIT 1");
+
+        return merchantDailyAttendanceMapper.selectOne(wrapper);
+    }
+
+    /**
+     * 获取商户的累计工作时长
+     *
+     * @param userId 技师ID
+     * @return 工作时长(分钟)
+     */
+    private long getWorkDuration(Long userId) {
+        LambdaQueryWrapper<MerchantDailyAttendance> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(MerchantDailyAttendance::getMerchantId, userId)
+                .eq(MerchantDailyAttendance::getAttendanceDate, DateUtils.getNowDate());
+        List<MerchantDailyAttendance> attendances = merchantDailyAttendanceMapper.selectList(wrapper);
+        if (attendances == null || attendances.isEmpty()) return 0;
+        // 计算指定日期的总分钟数
+        long totalMinutes = attendances.stream()
+                                    .filter(attendance -> DateUtils.getNowDate().toString().equals(attendance.getAttendanceDate().toString()))
+                                    .mapToLong(MerchantDailyAttendance::getTotalWorkMinutes)
+                                    .sum();
+        return totalMinutes;
+    }
+
+    /**
+     * 获取商户的考勤规则
+     *
+     * @return 考勤规则
+     */
+    private AttendanceRule getAttendanceRule() {
+        LambdaQueryWrapper<AttendanceRule> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(AttendanceRule::getIsDelete, 0);
+        wrapper.eq(AttendanceRule::getWorkDurationRuleEnabled, 1);
+        wrapper.last("LIMIT 1");
+        return attendanceRuleMapper.selectOne(wrapper);
+    }
+
+    /**
+     * 判断用户是否有生效中的技能
+     *
+     * @param userId 技师ID
+     * @return true: 有可用技能, false: 无
+     */
+    public boolean hasActiveSkills(Long userId) {
+        if (userId == null) return false;
+
+        // 构建查询条件:用户ID匹配 AND 状态为已发布/生效中
+        LambdaQueryWrapper<MaProject> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(MaProject::getMerchantId, userId)
+                .eq(MaProject::getAuditStatus, 1); // 假设 1 代表 "生效/已审核"
+        // 只要查到一条记录即返回 true
+        return maProjectMapper.selectCount(wrapper) > 0;
+    }
+
+    /**
+     * 判断用户是否有家庭地址(通常指设置为默认的地址)
+     *
+     * @param userId 技师ID
+     * @return true: 有地址, false: 无
+     */
+    public boolean hasHomeAddress(Long userId) {
+        if (userId == null) return false;
+
+        // 构建查询条件:用户ID匹配 AND 是默认地址(可选) AND 未删除
+        LambdaQueryWrapper<TAddress> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(TAddress::getMerchantId, userId)
+                .eq(TAddress::getUserType, 2)  // 商户类型
+                .eq(TAddress::getIsDelete, 0);  // 逻辑未删除
+
+        // 统计数量是否大于0
+        long count = addressMapper.selectCount(wrapper);
+        return count > 0;
+    }
+
+    // 辅助方法:模拟获取用户
+    private MaTechnician getTechnician(Long userId) {
+        // ... DB查询逻辑
+        LambdaQueryWrapper<MaTechnician> query = new LambdaQueryWrapper<>();
+        query.eq(MaTechnician::getId, userId);
+        return maTechnicianMapper.selectOne(query);
+    }
+
+    // 辅助方法:更新状态
+    private void updateStatus(Long userId, TechnicianStatusEnum status) {
+        LambdaUpdateWrapper<MaTechnician> update = new LambdaUpdateWrapper<>();
+        update.eq(MaTechnician::getId, userId);
+        update.set(MaTechnician::getPostState, status.getCode());
+        // ... DB Update逻辑,同时记录上线/下线时间
+        maTechnicianMapper.update(null, update);
+
+    }
+
+    /**
+     * 后台待审核页面审核通过商户。
+     *
+     * @param id        商户ID
+     * @param dto       待审核通过参数
+     * @param loginUser 当前登录用户
+     * @return 结果
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int approvePendingMerchantAudit(Integer id, MaTechnicianPendingAuditSubmitDTO dto, LoginUser loginUser) {
+        if (id == null) {
+            throw new ServiceException("商户ID不能为空");
+        }
+        if (dto == null) {
+            throw new ServiceException("审核参数不能为空");
+        }
+
+        String idCardFront = checkRequiredFileUrl(dto.getIdCardFront(), "身份证正面加密图片");
+        String idCardBack = checkRequiredFileUrl(dto.getIdCardBack(), "身份证反面加密图片");
+        String healthCertificate = checkRequiredFileUrl(dto.getHealthCertificate(), "健康证加密图片");
+        String qualificationCertificate = checkRequiredFileUrl(dto.getQualificationCertificate(), "资格证加密图片");
+        checkRequiredExpirationDate(dto.getIdCardExpirationDate(), "身份证到期时间");
+        checkRequiredExpirationDate(dto.getHealthCertificateExpirationDate(), "健康证到期时间");
+        checkRequiredExpirationDate(dto.getQualificationCertificateExpirationDate(), "资格证到期时间");
+
+        String auditRemark = dto.getAuditRemark() == null ? "" : dto.getAuditRemark().trim();
+        if (auditRemark.length() > AUDIT_REMARK_MAX_LENGTH) {
+            throw new ServiceException("审核备注长度不能超过" + AUDIT_REMARK_MAX_LENGTH + "个字符");
+        }
+
+        MaTechnician existsMerchant = maTechnicianMapper.selectMerchantById(id);
+        if (existsMerchant == null || !NOT_DELETED.equals(existsMerchant.getIsDelete())) {
+            throw new ServiceException("商户不存在或已删除");
+        }
+        if (!Integer.valueOf(AUDIT_WAIT_REVIEW).equals(existsMerchant.getAuditStatus())) {
+            throw new ServiceException("当前商户不是待审核状态,不能审核通过");
+        }
+
+        MaTechnician maTechnician = new MaTechnician();
+        maTechnician.setId(id);
+        /*maTechnician.setIdCard(String.join(",", idCardFront, idCardBack));
+        maTechnician.setHealthCertificate(healthCertificate);
+        maTechnician.setQualificationCertificate(qualificationCertificate);*/
+        maTechnician.setIdCardExpirationDate(dto.getIdCardExpirationDate());
+        maTechnician.setHealthCertificateExpirationDate(dto.getHealthCertificateExpirationDate());
+        maTechnician.setQualificationCertificateExpirationDate(dto.getQualificationCertificateExpirationDate());
+        maTechnician.setAuditStatus(AUDIT_APPROVED);
+        maTechnician.setAuditRemark(auditRemark);
+        maTechnician.setApproveTime(DateUtils.getNowDate());
+        if (loginUser != null && loginUser.getUser() != null) {
+            maTechnician.setUpdateBy(loginUser.getUser().getUserName());
+        }
+        maTechnician.setUpdateTime(DateUtils.getNowDate());
+
+        int rows = maTechnicianMapper.approvePendingMerchantAuditById(maTechnician);
+        if (rows <= 0) {
+            throw new ServiceException("待审核商户审核通过失败");
+        }
+        return rows;
+    }
+
+    private String checkRequiredFileUrl(String value, String fieldName) {
+        if (StringUtils.isBlank(value)) {
+            throw new ServiceException(fieldName + "不能为空");
+        }
+        return value.trim();
+    }
+
+    private void checkRequiredExpirationDate(LocalDate value, String fieldName) {
+        if (value == null) {
+            throw new ServiceException(fieldName + "不能为空");
+        }
+        if (value.isBefore(LocalDate.now())) {
+            throw new ServiceException(fieldName + "不能早于当前日期");
+        }
+    }
 }
 }

+ 19 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/MerchantDailyAttendanceServiceImpl.java

@@ -0,0 +1,19 @@
+package com.ylx.massage.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ylx.massage.domain.MerchantDailyAttendance;
+import com.ylx.massage.mapper.MerchantDailyAttendanceMapper;
+import com.ylx.massage.service.MerchantDailyAttendanceService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 商户每日考勤统计表(MerchantDailyAttendance)表服务实现类
+ *
+ * @author makejava
+ * @since 2026-06-05 11:16:10
+ */
+@Service("merchantDailyAttendanceService")
+public class MerchantDailyAttendanceServiceImpl extends ServiceImpl<MerchantDailyAttendanceMapper, MerchantDailyAttendance> implements MerchantDailyAttendanceService {
+
+}
+

+ 11 - 11
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/TLbtServiceImpl.java

@@ -2,7 +2,6 @@ package com.ylx.massage.service.impl;
 
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ylx.common.constant.MassageConstants;
 import com.ylx.common.exception.ServiceException;
 import com.ylx.common.exception.ServiceException;
 import com.ylx.common.utils.uuid.IdUtils;
 import com.ylx.common.utils.uuid.IdUtils;
 import com.ylx.massage.domain.TLbt;
 import com.ylx.massage.domain.TLbt;
@@ -21,23 +20,24 @@ public class TLbtServiceImpl extends ServiceImpl<TLbtMapper, TLbt> implements TL
 
 
     @Override
     @Override
     public Boolean addOrUpdate(TLbt lbt) {
     public Boolean addOrUpdate(TLbt lbt) {
-        if (StringUtils.isBlank(lbt.getCImgUrl())) {
+        if (StringUtils.isBlank(lbt.getImgUrl())) {
             throw new ServiceException("图片不能为空");
             throw new ServiceException("图片不能为空");
         }
         }
-        if (lbt.getCSort() == null) {
+        if (lbt.getSort() == null) {
             throw new ServiceException("序号不能为空");
             throw new ServiceException("序号不能为空");
         }
         }
-        Integer i = lbt.getCSort();
-        LambdaQueryWrapper<TLbt> query = new LambdaQueryWrapper<TLbt>().eq(TLbt::getCSort, i);
+        Integer i = lbt.getSort();
+        LambdaQueryWrapper<TLbt> query = new LambdaQueryWrapper<TLbt>().eq(TLbt::getSort, i);
         TLbt one = getOne(query);
         TLbt one = getOne(query);
-        if (StringUtils.isBlank(lbt.getCId())) {
+        if (StringUtils.isBlank(lbt.getId())) {
             //新增
             //新增
+            lbt.setId(IdUtils.simpleUUID());
             if (one != null) {
             if (one != null) {
                 batchLbt(i);
                 batchLbt(i);
             }
             }
         } else {
         } else {
             //修改
             //修改
-            query.ne(TLbt::getCId, lbt.getCId());
+            query.ne(TLbt::getId, lbt.getId());
             if (getOne(query) != null) {
             if (getOne(query) != null) {
                 batchLbt(i);
                 batchLbt(i);
             }
             }
@@ -50,17 +50,17 @@ public class TLbtServiceImpl extends ServiceImpl<TLbtMapper, TLbt> implements TL
      * @param i
      * @param i
      */
      */
     private void batchLbt(Integer i) {
     private void batchLbt(Integer i) {
-        LambdaQueryWrapper<TLbt> query1 = new LambdaQueryWrapper<TLbt>().ge(TLbt::getCSort, i);
+        LambdaQueryWrapper<TLbt> query1 = new LambdaQueryWrapper<TLbt>().ge(TLbt::getSort, i);
         List<TLbt> lbts = list(query1);
         List<TLbt> lbts = list(query1);
-        lbts.forEach(tLbt1 -> tLbt1.setCSort(tLbt1.getCSort() + 1));
+        lbts.forEach(tLbt1 -> tLbt1.setSort(tLbt1.getSort() + 1));
         updateBatchById(lbts);
         updateBatchById(lbts);
     }
     }
 
 
     @Override
     @Override
     public Boolean del(TLbt tLbt) {
     public Boolean del(TLbt tLbt) {
-        if (StringUtils.isBlank(tLbt.getCId())) {
+        if (StringUtils.isBlank(tLbt.getId())) {
             throw new ServiceException("ID不能为空");
             throw new ServiceException("ID不能为空");
         }
         }
-        return this.removeById(tLbt.getCId());
+        return this.removeById(tLbt.getId());
     }
     }
 }
 }

+ 8 - 8
nightFragrance-massage/src/main/java/com/ylx/massage/utils/MassageUtil.java

@@ -45,14 +45,14 @@ public class MassageUtil {
         BigDecimal BASE_DISTANCE_KM = baseDistanceKm; // 起步距离(公里)
         BigDecimal BASE_DISTANCE_KM = baseDistanceKm; // 起步距离(公里)
         LambdaQueryWrapper<TFareSetting> tFareSettingLambdaQueryWrapper = new LambdaQueryWrapper<>();
         LambdaQueryWrapper<TFareSetting> tFareSettingLambdaQueryWrapper = new LambdaQueryWrapper<>();
         log.info("部门{}", deptId);
         log.info("部门{}", deptId);
-        tFareSettingLambdaQueryWrapper.eq(TFareSetting::getDeptId, deptId).eq(TFareSetting::getEnable, 1);
-        TFareSetting fareSetting = fareSettingService.getOne(tFareSettingLambdaQueryWrapper);
-        log.info("配置{}", fareSetting);
-        if (null != fareSetting) {
-            BASE_FARE = fareSetting.getBaseFare();
-            ADDITIONAL_FARE_PER_KM = fareSetting.getAdditionalFarePer();
-            BASE_DISTANCE_KM = fareSetting.getBaseDistance();
-        }
+//        tFareSettingLambdaQueryWrapper.eq(TFareSetting::getDeptId, deptId).eq(TFareSetting::getEnable, 1);
+//        TFareSetting fareSetting = fareSettingService.getOne(tFareSettingLambdaQueryWrapper);
+//        log.info("配置{}", fareSetting);
+//        if (null != fareSetting) {
+//            BASE_FARE = fareSetting.getBaseFare();
+//            ADDITIONAL_FARE_PER_KM = fareSetting.getAdditionalFarePer();
+//            BASE_DISTANCE_KM = fareSetting.getBaseDistance();
+//        }
         log.info("起步价:{},超出起步价后每公里费用:{},起步距离{}", BASE_FARE, ADDITIONAL_FARE_PER_KM, BASE_DISTANCE_KM);
         log.info("起步价:{},超出起步价后每公里费用:{},起步距离{}", BASE_FARE, ADDITIONAL_FARE_PER_KM, BASE_DISTANCE_KM);
 
 
         // 计算超出起步价的公里数,注意应该向上取整,因为不足1公里也要按1公里计费
         // 计算超出起步价的公里数,注意应该向上取整,因为不足1公里也要按1公里计费

+ 10 - 7
nightFragrance-massage/src/main/resources/mapper/massage/TLbtMapper.xml

@@ -4,17 +4,20 @@
 
 
     <!-- 通用查询映射结果 -->
     <!-- 通用查询映射结果 -->
     <resultMap id="BaseResultMap" type="com.ylx.massage.domain.TLbt">
     <resultMap id="BaseResultMap" type="com.ylx.massage.domain.TLbt">
-        <id column="c_id" property="cId" />
-        <result column="c_img_url" property="cImgUrl" />
-        <result column="n_del" property="nDel" />
-        <result column="c_describe" property="cDescribe" />
-        <result column="c_content" property="cContent" />
-        <result column="c_sort" property="cSort" />
+        <id column="id" property="id" />
+        <result column="title" property="title" />
+        <result column="img_url" property="imgUrl" />
+        <result column="jump_url" property="jumpUrl" />
+        <result column="sort" property="sort" />
+        <result column="status" property="status" />
+        <result column="create_time" property="createTime" />
+        <result column="update_time" property="updateTime" />
+        <result column="is_delete" property="isDelete" />
     </resultMap>
     </resultMap>
 
 
     <!-- 通用查询结果列 -->
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
     <sql id="Base_Column_List">
-        c_id, c_img_url, n_del, c_describe, c_content, c_sort
+        id, title, img_url, jump_url, sort, status, create_time, update_time, is_delete
     </sql>
     </sql>
 
 
 </mapper>
 </mapper>