1
0

2 کامیت‌ها c2fe370273 ... 943505df14

نویسنده SHA1 پیام تاریخ
  jinwenhai 943505df14 Merge remote-tracking branch 'origin/dev' into dev 6 روز پیش
  jinwenhai 55d6f22c51 广誉源商户端-登录-我的技能,城市管理 6 روز پیش

+ 317 - 11
nightFragrance-admin/src/main/java/com/ylx/web/controller/massage/MaTechnicianController.java

@@ -1,28 +1,42 @@
 package com.ylx.web.controller.massage;
 
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import cn.hutool.json.JSONObject;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ylx.common.core.domain.R;
 import com.ylx.common.core.domain.model.LoginUser;
+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;
+import com.ylx.common.utils.StringUtils;
+import com.ylx.massage.domain.MaProject;
+import com.ylx.massage.domain.dto.MaProjectSaveDto;
+import com.ylx.massage.domain.dto.MaProjectUpdateDto;
 import com.ylx.massage.domain.dto.MaTechnicianMerchantAddDTO;
 import com.ylx.massage.domain.dto.MaTechnicianMerchantQueryDTO;
-import com.ylx.massage.domain.vo.MaTechnicianAppAddVo;
-import com.ylx.massage.domain.vo.MaTechnicianMerchantDetailVO;
-import com.ylx.massage.domain.vo.MaTechnicianMerchantListVO;
+import com.ylx.massage.domain.vo.*;
+import com.ylx.massage.service.IMaProjectService;
+import com.ylx.project.domain.Project;
+import com.ylx.servicecategory.domain.ServiceCategory;
+import com.ylx.servicecategory.service.ServiceCategoryService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.ObjectUtils;
+import org.springframework.web.bind.annotation.*;
 import com.ylx.common.annotation.Log;
 import com.ylx.common.core.controller.BaseController;
 import com.ylx.common.core.domain.AjaxResult;
@@ -44,6 +58,194 @@ import com.ylx.common.core.page.TableDataInfo;
 public class MaTechnicianController extends BaseController {
     @Autowired
     private IMaTechnicianService maTechnicianService;
+    @Autowired
+    private StringRedisTemplate redisTemplate;
+
+    @Autowired
+    private SendSmsComponents sendSms;
+    @Autowired
+    private ServiceCategoryService serviceCategoryService;
+    @Autowired
+    private IMaProjectService maProjectService;
+
+    public static final String PHONE_THREEUSERPARTCLIENT_CODE_KEY = "sys:threeUserPartClient:phone:";
+
+    @GetMapping("/sendMsg")
+    @ApiOperation(value = "短信发送", notes = "短信发送")
+    public Result sendMsg(@RequestParam String phone, HttpServletRequest request) {
+        if (org.apache.commons.lang3.StringUtils.isEmpty(phone)) {
+            return Result.error("手机号不能为空");
+        }
+        Random rand = new Random();
+        // randNumber 将被赋值为一个 MIN 和 MAX 范围内的随机数
+        int randNumber = rand.nextInt(9999 - 1000 + 1) + 1000;
+        // 保存验证码到redis
+        redisTemplate.opsForValue()
+                .set("userH5:order:phone:" + phone, String.valueOf(randNumber), 5L
+                        , TimeUnit.MINUTES);
+        try {
+            SMSVerificationCode smsVerificationCode = new SMSVerificationCode(String.valueOf(randNumber));
+            String jsonString = JSON.toJSONString(smsVerificationCode);
+            sendSms.sendSms(phone, SendSmsEnum.SMS_220650024, jsonString);
+            return Result.ok("发送成功");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return Result.ok("发送失败");
+    }
+
+    /**
+     * 商户登录接口
+     *
+     * @param thirdPartyLoginsVo
+     * @return
+     */
+    @ApiOperation(value = "商户登录", notes = "商户登录")
+    @PostMapping(value = "/clientLogin")
+    @Transactional
+    public Result<JSONObject> login(@RequestBody ThirdPartyLoginsVo thirdPartyLoginsVo) throws Exception {
+        // 获取登录用户信息
+        Result<JSONObject> result = new Result<>();
+
+        // 校验手机号是否为空
+        if (StringUtils.isEmpty(thirdPartyLoginsVo.getPhone())) {
+            return result.error500("请输入手机号");
+        }
+
+        // 校验用户是否存在且有效
+        LambdaQueryWrapper<MaTechnician> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(MaTechnician::getTePhone, thirdPartyLoginsVo.getPhone());
+        MaTechnician maTechnician = maTechnicianService.getBaseMapper().selectOne(queryWrapper);
+        // 校验用户是否有效
+        if (ObjectUtils.isEmpty(maTechnician)) {
+            return result.error500("商户不存在,请先注册");
+
+        }
+
+        if (thirdPartyLoginsVo.getCodeSwitch()) {
+            // 短信验证
+            String msg = redisTemplate.opsForValue().get(PHONE_THREEUSERPARTCLIENT_CODE_KEY + thirdPartyLoginsVo.getPhone());
+            if (StringUtils.isEmpty(msg)) {
+                return Result.error("验证码已失效");
+            }
+
+            if (!thirdPartyLoginsVo.getPhoneMsg().equals(msg)) {
+                return Result.error("短信验证码不正确");
+            }
+        } else {
+            if (!thirdPartyLoginsVo.getPassWord().equals(maTechnician.getTePassword())) {
+                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.getPhoneMsg());
+        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 (!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("/apply")
+    public Result<?> apply(@RequestBody MaTechnicianAppAddVo req) {
+        // 1. 基础参数校验
+        if (StringUtils.isAnyBlank(req.getTeName(), req.getTePhone(), req.getTeAddress(), req.getTeAvatar(), req.getLifePhotos(), req.getTeBrief(), req.getAvatar(), req.getIdCard())) {
+            return Result.error("必填项不能为空");
+        }
+        // 2. 调用业务层处理入驻申请
+        maTechnicianService.apply(req);
+        return Result.ok("提交成功,进入审核流程");
+    }
+
+    /**
+     * 查询商户信息接口
+     */
+    @GetMapping("/getTechnician")
+    public Result<?> getTechnician(@RequestParam String phone) {
+        LambdaQueryWrapper<MaTechnician> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(MaTechnician::getTePhone, phone);
+        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);
+        } else if (req.getAuditStatus() == 1 || req.getAuditStatus() == 2) {
+            //上传商户资料信息
+            extractedUpdate(req);
+        }
+        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) {
+        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.getOpenService());
+        updateWrapper.set(MaTechnician::getTeAddress, req.getTeAddress());
+        updateWrapper.set(MaTechnician::getTeAge, req.getTeAge());
+        updateWrapper.set(MaTechnician::getAvatar, req.getAvatar());
+        maTechnicianService.update(updateWrapper);
+    }
 
     /**
      * 查询技师列表
@@ -164,4 +366,108 @@ public class MaTechnicianController extends BaseController {
     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)
+     * 支持 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) {
+
+        return Result.ok(maTechnicianService.getNotApplyList(req.getUserId(), req.getTypeId()));
+
+    }
+
+    /**
+     * 申请开通新服务
+     */
+    @PostMapping("/applyForService")
+    public AjaxResult applyForService(@RequestBody MaProjectSaveDto 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("/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);
+    }
+
 }

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

@@ -0,0 +1,87 @@
+package com.ylx.massage.controller;
+
+
+
+import cn.hutool.core.collection.CollectionUtil;
+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.ylx.common.core.domain.R;
+import com.ylx.massage.domain.Area;
+import com.ylx.massage.domain.CityOperationApplication;
+import com.ylx.massage.service.CityOperationApplicationService;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 城市管理表(CityOperationApplication)表控制层
+ *
+ * @author makejava
+ * @since 2026-06-04 14:19:49
+ */
+@RestController
+@RequestMapping("cityOperationApplication")
+public class CityOperationApplicationController {
+    /**
+     * 服务对象
+     */
+    @Autowired
+    private CityOperationApplicationService cityOperationApplicationService;
+
+    /**
+     * 分页查询所有数据
+     *
+     * @param page 分页对象
+     * @param cityOperationApplication 查询实体
+     * @return 所有数据
+     */
+    @GetMapping("/list")
+    public R selectAll(Page<CityOperationApplication> page, CityOperationApplication cityOperationApplication) {
+        return R.ok(this.cityOperationApplicationService.page(page, new QueryWrapper<>(cityOperationApplication)));
+    }
+
+    /**
+     * 通过主键查询单条数据
+     *
+     * @param id 主键
+     * @return 单条数据
+     */
+    @GetMapping("{id}")
+    public R selectOne(@PathVariable Serializable id) {
+        return R.ok(this.cityOperationApplicationService.getById(id));
+    }
+
+    /**
+     * 新增数据
+     *
+     * @param cityOperationApplication 实体对象
+     * @return 新增结果
+     */
+    @PostMapping("/saveCity")
+    public R insert(@RequestBody CityOperationApplication cityOperationApplication) {
+        return R.ok(this.cityOperationApplicationService.save(cityOperationApplication));
+    }
+    /**
+     * 根据商户ID查询城市管理列表
+     * @param merchantId
+     * @return R
+     */
+    @GetMapping("/getCityList")
+    @ApiOperation("根据商户ID查询城市管理列表")
+    public R getCityList(@RequestParam String merchantId) {
+        LambdaQueryWrapper<CityOperationApplication> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(CityOperationApplication::getMerchantId, merchantId);
+        List<CityOperationApplication> list = this.cityOperationApplicationService.list(queryWrapper);
+        if (CollectionUtil.isEmpty(list)) {
+            return R.fail("未找到此数据");
+        }
+        return R.ok(list);
+    }
+
+
+
+}
+

+ 88 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/CityOperationApplication.java

@@ -0,0 +1,88 @@
+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;
+
+/**
+ * 城市管理表(CityOperationApplication)表实体类
+ *
+ * @author makejava
+ * @since 2026-06-04 14:27:32
+ */
+@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)
+    private Long id;
+//城市编码 (例如: 110000)
+@TableField("city_code")
+    private String cityCode;
+//城市名称 (冗余字段,方便查询,例如: 北京市)
+@TableField("city_name")
+    private String cityName;
+//运营中心ID
+@TableField("operation_center_id")
+    private Long operationCenterId;
+//运营中心名称
+@TableField("operation_center_name")
+    private String operationCenterName;
+//实际审批通过时间
+@TableField("actual_approval_time")
+    private Date actualApprovalTime;
+//申请原因 (限制500字以内)
+    @TableField("apply_reason")
+    private String applyReason;
+
+//状态 (0:待审核, 1:已通过, 2:已驳回)
+    @TableField("status")
+    private Integer status;
+//商户ID
+    @TableField("merchant_id")
+    private String merchantId;
+    /**
+     * 创建时间
+     */
+    @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(value = "create_by")
+    private String createBy;
+
+    /**
+     * 更新时间
+     */
+    @TableField(value = "update_by")
+    private String updateBy;
+
+    /**
+     * 逻辑删除:1已删除 0未删除
+     */
+    @TableField("is_delete")
+    private Integer isDelete;
+
+
+
+}
+

+ 89 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/ContractRecords.java

@@ -0,0 +1,89 @@
+package com.ylx.massage.domain;
+
+
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 合同记录表(ContractRecords)表实体类
+ *
+ * @author makejava
+ * @since 2026-06-04 16:45:28
+ */
+@SuppressWarnings("serial")
+public class ContractRecords {
+//主键ID
+    private Object id;
+//商户ID
+    private Integer merchantId;
+//合同名称
+    private String contractName;
+//上传文件URL
+    private String fileUrl;
+//合同签定时间
+    private Date signTime;
+//签订人姓名
+    private String signerName;
+//创建时间
+    private Date createTime;
+
+
+    public Object getId() {
+        return id;
+    }
+
+    public void setId(Object id) {
+        this.id = id;
+    }
+
+    public Integer getMerchantId() {
+        return merchantId;
+    }
+
+    public void setMerchantId(Integer merchantId) {
+        this.merchantId = merchantId;
+    }
+
+    public String getContractName() {
+        return contractName;
+    }
+
+    public void setContractName(String contractName) {
+        this.contractName = contractName;
+    }
+
+    public String getFileUrl() {
+        return fileUrl;
+    }
+
+    public void setFileUrl(String fileUrl) {
+        this.fileUrl = fileUrl;
+    }
+
+    public Date getSignTime() {
+        return signTime;
+    }
+
+    public void setSignTime(Date signTime) {
+        this.signTime = signTime;
+    }
+
+    public String getSignerName() {
+        return signerName;
+    }
+
+    public void setSignerName(String signerName) {
+        this.signerName = signerName;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+}
+

+ 16 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/mapper/CityOperationApplicationMapper.java

@@ -0,0 +1,16 @@
+package com.ylx.massage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ylx.massage.domain.CityOperationApplication;
+
+
+/**
+ * 城市管理表(CityOperationApplication)表数据库访问层
+ *
+ * @author makejava
+ * @since 2026-06-04 15:53:41
+ */
+public interface CityOperationApplicationMapper extends BaseMapper<CityOperationApplication> {
+
+}
+

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

@@ -2,6 +2,7 @@ package com.ylx.massage.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.ylx.massage.domain.MaTeProject;
+import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
@@ -9,6 +10,7 @@ import java.util.List;
 /**
  * 商户服务项目关联Mapper接口
  */
+@Mapper
 public interface MaTeProjectMapper extends BaseMapper<MaTeProject> {
 
     /**

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

@@ -0,0 +1,18 @@
+package com.ylx.massage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ylx.massage.domain.CityOperationApplication;
+import org.springframework.stereotype.Service;
+
+
+/**
+ * 城市管理表(CityOperationApplication)表服务接口
+ *
+ * @author makejava
+ * @since 2026-06-04 14:23:52
+ */
+@Service("cityOperationApplicationService")
+public interface CityOperationApplicationService extends IService<CityOperationApplication> {
+
+}
+

+ 46 - 2
nightFragrance-massage/src/main/java/com/ylx/massage/service/IMaTechnicianService.java

@@ -5,7 +5,9 @@ import java.util.List;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ylx.common.core.domain.model.LoginUser;
+import com.ylx.massage.domain.MaProject;
 import com.ylx.massage.domain.MaTechnician;
+import com.ylx.massage.domain.dto.MaProjectSaveDto;
 import com.ylx.massage.domain.dto.MassageMerchantRecommendDto;
 import com.ylx.massage.domain.dto.MaTechnicianMerchantAddDTO;
 import com.ylx.massage.domain.dto.MaTechnicianMerchantQueryDTO;
@@ -13,6 +15,8 @@ import com.ylx.massage.domain.vo.MaTechnicianAppAddVo;
 import com.ylx.massage.domain.vo.MaTechnicianMerchantDetailVO;
 import com.ylx.massage.domain.vo.MaTechnicianMerchantListVO;
 import com.ylx.massage.domain.vo.MerchantVo;
+import com.ylx.project.domain.Project;
+import org.springframework.stereotype.Service;
 
 /**
  * 技师Service接口
@@ -40,7 +44,7 @@ public interface IMaTechnicianService extends IService<MaTechnician> {
     /**
      * 新增技师
      *
-     * @param maTechnician 技师
+     * @param
      * @return 结果
      */
     public int insertMaTechnician(MaTechnicianAppAddVo maTechnicianAppAddVo);
@@ -75,7 +79,7 @@ public interface IMaTechnicianService extends IService<MaTechnician> {
     /**
      * 修改技师
      *
-     * @param maTechnician 技师
+     * @param
      * @return 结果
      */
     public int updateMaTechnician(MaTechnicianAppAddVo maTechnicianAppAddVo);
@@ -105,4 +109,44 @@ public interface IMaTechnicianService extends IService<MaTechnician> {
     Boolean isHasMerchantCity(String areaCode);
 
     List<MerchantVo> getMerchantRecommend(MassageMerchantRecommendDto dto);
+
+    /**
+     * 申请技师
+     *
+     * @param req
+     */
+    void apply(MaTechnicianAppAddVo req);
+
+    /**
+     * 技师列表
+     *
+     * @param userId
+     * @param auditStatus
+     * @return
+     */
+    List<MaProject> selectMaTechnicianListBy(String userId, String auditStatus);
+
+    /**
+     * 服务项目列表
+     *
+     * @param typeId
+     * @return
+     */
+    List<Project> selectTechnicianListBy(String typeId);
+
+    /**
+     * 技师未申请项目列表
+     *
+     * @param userId
+     * @param typeId
+     * @return
+     */
+    List<Project> getNotApplyList(String userId, String typeId);
+
+    /**
+     * 申请开通新服务
+     * @param dto
+     * @return
+     */
+    int applyForService(MaProjectSaveDto dto);
 }

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

@@ -0,0 +1,19 @@
+package com.ylx.massage.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ylx.massage.domain.CityOperationApplication;
+import com.ylx.massage.mapper.CityOperationApplicationMapper;
+import com.ylx.massage.service.CityOperationApplicationService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 城市管理表(CityOperationApplication)表服务实现类
+ *
+ * @author makejava
+ * @since 2026-06-04 14:24:35
+ */
+@Service("cityOperationApplicationService")
+public class CityOperationApplicationServiceImpl extends ServiceImpl<CityOperationApplicationMapper, CityOperationApplication> implements CityOperationApplicationService {
+
+}
+

+ 174 - 14
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/MaTechnicianServiceImpl.java

@@ -1,12 +1,9 @@
 package com.ylx.massage.service.impl;
 
-import java.util.ArrayList;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
+
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -14,7 +11,9 @@ import com.ylx.common.core.domain.model.LoginUser;
 import com.ylx.common.exception.ServiceException;
 import com.ylx.common.utils.DateUtils;
 import com.ylx.common.utils.StringUtils;
+import com.ylx.massage.domain.MaProject;
 import com.ylx.massage.domain.MaTeProject;
+import com.ylx.massage.domain.dto.MaProjectSaveDto;
 import com.ylx.massage.domain.dto.MaTechnicianMerchantAddDTO;
 import com.ylx.massage.domain.dto.MaTechnicianMerchantQueryDTO;
 import com.ylx.massage.domain.dto.MassageMerchantRecommendDto;
@@ -22,9 +21,11 @@ import com.ylx.massage.domain.vo.MaTechnicianAppAddVo;
 import com.ylx.massage.domain.vo.MaTechnicianMerchantDetailVO;
 import com.ylx.massage.domain.vo.MaTechnicianMerchantListVO;
 import com.ylx.massage.domain.vo.MerchantVo;
+import com.ylx.massage.mapper.MaProjectMapper;
 import com.ylx.massage.mapper.MaTeProjectMapper;
 import com.ylx.project.domain.Project;
 import com.ylx.project.mapper.ProjectMapper;
+import lombok.Data;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -57,9 +58,106 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
     @Autowired
     private MaTeProjectMapper maTeProjectMapper;
 
+    private MaProjectMapper maProjectMapper;
     @Autowired
     private ProjectMapper projectMapper;
 
+    /**
+     * 商户入驻申请注册
+     *
+     * @param req 申请参数
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void apply(MaTechnicianAppAddVo req) {
+        String phone = req.getTePhone();
+        //商户入住前置条件校验
+        getMaTechnician(req, phone);
+        MaTechnician maTechnician = new MaTechnician();
+        BeanUtils.copyProperties(req, maTechnician);
+        //技师类型默认为真实商户
+        maTechnician.setTechType(0);
+        maTechnicianMapper.insert(maTechnician);
+
+    }
+
+    /**
+     * 商户入住前置条件校验
+     *
+     * @param req
+     * @param phone
+     */
+    private void getMaTechnician(MaTechnicianAppAddVo req, String phone) {
+        // 1. 判断当前用户是否已入驻
+        MaTechnician userProfile = getMaTechnician(req);
+        if (userProfile != null) {
+            throw new RuntimeException("当前用户已入驻,请勿重复提交");
+        }
+
+        // 2. 判断手机号是否已存在
+        LambdaQueryWrapper<MaTechnician> queryPhoneWrapper = new LambdaQueryWrapper<>();
+        queryPhoneWrapper.eq(MaTechnician::getTePhone, phone);
+        queryPhoneWrapper.eq(MaTechnician::getIsDelete, 0);
+        MaTechnician maTechnicianPhone = maTechnicianMapper.selectOne(queryPhoneWrapper);
+        if (maTechnicianPhone != null) {
+            throw new RuntimeException("手机号已存在,请更换手机号");
+        }
+        //3、判断手机号是否已绑定其他用户
+        LambdaQueryWrapper<MaTechnician> queryTePhoneWrapper = new LambdaQueryWrapper<>();
+        queryTePhoneWrapper.eq(MaTechnician::getTePhone, phone);
+        queryTePhoneWrapper.eq(MaTechnician::getIsDelete, 0);
+        queryTePhoneWrapper.eq(MaTechnician::getAuditStatus, 2);
+        MaTechnician maTechnicianTePhone = maTechnicianMapper.selectOne(queryTePhoneWrapper);
+        if (maTechnicianPhone != null) {
+            throw new RuntimeException("手机号已被其他用户绑定,请更换手机号");
+        }
+
+    }
+
+    /**
+     * 判断当前用户是否已入驻
+     *
+     * @return
+     */
+    private MaTechnician getMaTechnician(MaTechnicianAppAddVo req) {
+        LambdaQueryWrapper<MaTechnician> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(MaTechnician::getTePhone, req.getTePhone());
+        queryWrapper.eq(MaTechnician::getIsDelete, 0);
+        queryWrapper.eq(MaTechnician::getAuditStatus, 2);
+        queryWrapper.eq(MaTechnician::getOpenService, req.getOpenService());
+        MaTechnician userProfile = maTechnicianMapper.selectOne(queryWrapper);
+        return userProfile;
+    }
+
+    /**
+     * 查询商户服务项目列表
+     *
+     * @param userId      商户id
+     * @param auditStatus 审核状态
+     * @return 技师列表
+     */
+    @Override
+    public List<MaProject> selectMaTechnicianListBy(String userId, String auditStatus) {
+
+        LambdaQueryWrapper<MaProject> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(MaProject::getMerchantId, userId);
+        queryWrapper.eq(MaProject::getAuditStatus, auditStatus);
+        return maProjectMapper.selectList(queryWrapper);
+    }
+
+    /**
+     * 查询技师列表
+     *
+     * @param typeId 技师类型
+     * @return 技师列表
+     */
+    @Override
+    public List<Project> selectTechnicianListBy(String typeId) {
+        LambdaQueryWrapper<Project> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(Project::getType, typeId);
+        return projectMapper.selectList(queryWrapper);
+    }
+
     /**
      * 查询技师
      *
@@ -305,14 +403,14 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
         }
 
         List<Project> projects = projectMapper.selectList(new LambdaQueryWrapper<Project>()
-                .in(Project::getId, distinctProjectIds)
-                .eq(Project::getIsDelete, 0));
+                                                                  .in(Project::getId, distinctProjectIds)
+                                                                  .eq(Project::getIsDelete, 0));
         if (projects.size() != distinctProjectIds.size()) {
             throw new ServiceException("服务项目不存在或已删除");
         }
 
         Map<Long, Project> projectMap = projects.stream()
-                .collect(Collectors.toMap(project -> project.getId().longValue(), Function.identity(), (left, right) -> left));
+                                                .collect(Collectors.toMap(project -> project.getId().longValue(), Function.identity(), (left, right) -> left));
         Set<Integer> projectCategoryIds = new LinkedHashSet<>();
         for (Long projectId : distinctProjectIds) {
             Project project = projectMap.get(projectId);
@@ -352,16 +450,16 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
 
     private String joinIds(Set<Integer> ids) {
         return ids.stream()
-                .map(String::valueOf)
-                .collect(Collectors.joining(","));
+                       .map(String::valueOf)
+                       .collect(Collectors.joining(","));
     }
 
     private String joinProjectTitles(Set<Long> projectIds, Map<Long, Project> projectMap) {
         return projectIds.stream()
-                .map(projectMap::get)
-                .map(Project::getTitle)
-                .filter(StringUtils::isNotBlank)
-                .collect(Collectors.joining(","));
+                       .map(projectMap::get)
+                       .map(Project::getTitle)
+                       .filter(StringUtils::isNotBlank)
+                       .collect(Collectors.joining(","));
     }
 
     /**
@@ -411,4 +509,66 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
             return projectMap;
         }
     }
+
+    /**
+     * 获取未申请技能列表
+     *
+     * @param userId
+     * @param typeId
+     * @return
+     */
+    @Override
+    public List<Project> getNotApplyList(String userId, String typeId) {
+        LambdaQueryWrapper<MaProject> query = new LambdaQueryWrapper<>();
+        query.eq(MaProject::getMerchantId, userId);
+        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);
+    }
+
+    /**
+     * 申请开通新服务
+     *
+     * @param dto
+     * @return
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public int applyForService(MaProjectSaveDto dto) {
+        if (Objects.isNull(dto)) {
+            return 0;
+        }
+        if (dto.getProjectIdList().size() > 0) {
+            // 插入商户技能
+            extracted(dto);
+        } else {
+            return 0;
+        }
+        return 1;
+    }
+
+    private void extracted(MaProjectSaveDto dto) {
+        LambdaQueryWrapper<Project> query = new LambdaQueryWrapper<>();
+        query.in(Project::getId, dto.getProjectIdList());
+        List<Project> projectList = projectMapper.selectList(query);
+        for (Project project : projectList) {
+            MaProject maProject = new MaProject();
+            maProject.setProjectId(project.getId().toString());
+            maProject.setProjectName(project.getTitle());
+            maProject.setProjectDescribe(project.getDetail());
+            maProject.setProjectDuration(project.getStandardDuration());
+            maProject.setProjectOriginalPrice(project.getPrice());
+            maProject.setProjectMaxPrice(project.getPriceMax());
+            maProject.setProjectLowestPrice(project.getPriceMin());
+            maProject.setCreateBy(dto.getUserId());
+            maProject.setMerchantId(dto.getUserId());
+            maProject.setApplyTime((Data) new Date());
+            maProject.setMerchantPhone(dto.getMerchantPhone());
+            maProjectMapper.insert(maProject);
+        }
+    }
 }

+ 16 - 13
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/TFareFreeRuleServiceImpl.java

@@ -6,12 +6,14 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ylx.common.exception.ServiceException;
 import com.ylx.common.utils.SecurityUtils;
 import com.ylx.common.utils.StringUtils;
+import com.ylx.massage.domain.MaTechnician;
 import com.ylx.massage.domain.TFareFreeRule;
 import com.ylx.massage.domain.TJs;
 import com.ylx.massage.domain.TXiangmu;
 import com.ylx.massage.domain.vo.FareFreeRuleVo;
 import com.ylx.massage.domain.vo.TimeRangeVo;
 import com.ylx.massage.mapper.TFareFreeRuleMapper;
+import com.ylx.massage.service.IMaTechnicianService;
 import com.ylx.massage.service.TFareFreeRuleService;
 import com.ylx.massage.service.TJsService;
 import com.ylx.massage.service.TXiangmuService;
@@ -41,7 +43,7 @@ public class TFareFreeRuleServiceImpl extends ServiceImpl<TFareFreeRuleMapper, T
     private TXiangmuService xiangmuService;
 
     @Resource
-    private TJsService jsService;
+    private IMaTechnicianService jsService;
 
     /**
      * 新增免车费规则
@@ -125,11 +127,12 @@ public class TFareFreeRuleServiceImpl extends ServiceImpl<TFareFreeRuleMapper, T
         } else {
             // ========== 新增场景 ==========
             //根据openID获取技师的信息
-            TJs js = jsService.getOne(new LambdaQueryWrapper<TJs>().eq(TJs::getcOpenId, fareFreeRule.getOpenId()));
+//            TJs js = jsService.getOne(new LambdaQueryWrapper<TJs>().eq(TJs::getcOpenId, fareFreeRule.getOpenId()));
+            MaTechnician js = jsService.getOne(new LambdaQueryWrapper<MaTechnician>().eq(MaTechnician::getId, fareFreeRule.getTechId()));
             if (js == null) {
                 throw new ServiceException("技师不存在");
             }
-            fareFreeRule.setTechId(js.getId());
+            fareFreeRule.setTechId(js.getId().toString());
 
             // 2.5 检查是否存在启用的规则(同一技师、同一项目)
             if ("1".equals(fareFreeRule.getEnable())) {
@@ -154,18 +157,18 @@ public class TFareFreeRuleServiceImpl extends ServiceImpl<TFareFreeRuleMapper, T
      /**
      * 禁用免车费规则(H5 技师端)
      *
-     * @param id 主键ID
+     * @param
      * @return 是否成功
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
     public boolean disableFareFreeRule(String openId,String enable) {
         //根据openId查询技师信息
-        TJs js = jsService.getOne(new LambdaQueryWrapper<TJs>().eq(TJs::getcOpenId, openId));
+        MaTechnician js = jsService.getOne(new LambdaQueryWrapper<MaTechnician>().eq(MaTechnician::getId, openId));
         if (js == null) {
             throw new ServiceException("技师不存在");
         }
-        String techId = js.getId();
+        String techId = js.getId().toString();
         LambdaQueryWrapper<TFareFreeRule> eq = new LambdaQueryWrapper<TFareFreeRule>().eq(TFareFreeRule::getTechId, techId).orderByDesc(TFareFreeRule::getCreateTime).last("limit 1");
         TFareFreeRule existingRule = this.getOne(eq);
         if (existingRule == null) {
@@ -180,17 +183,17 @@ public class TFareFreeRuleServiceImpl extends ServiceImpl<TFareFreeRuleMapper, T
     /**
      * 查询免车费规则列表
      *
-     * @param techId 技师ID
+     * @param openId 技师ID
      * @return List<FareFreeRuleVo> 免车费规则VO列表
      */
     @Override
     public FareFreeRuleVo listFareFreeRules(String openId) {
         //根据openId查询技师信息
-        TJs js = jsService.getOne(new LambdaQueryWrapper<TJs>().eq(TJs::getcOpenId, openId));
+        MaTechnician js = jsService.getOne(new LambdaQueryWrapper<MaTechnician>().eq(MaTechnician::getId, openId));
         if (js == null) {
             throw new ServiceException("技师不存在");
         }
-        String techId = js.getId();
+        String techId = js.getId().toString();
         // 1. 查询规则列表
         LambdaQueryWrapper<TFareFreeRule> wrapper = new LambdaQueryWrapper<>();
         wrapper.eq(TFareFreeRule::getTechId, techId).eq(TFareFreeRule::getEnable, 1)
@@ -268,10 +271,10 @@ public class TFareFreeRuleServiceImpl extends ServiceImpl<TFareFreeRuleMapper, T
      * @param fareFreeRule 免车费规则
      */
     private void validateFareFreeRule(TFareFreeRule fareFreeRule) {
-        // 校验openID
-        if(StringUtils.isBlank(fareFreeRule.getOpenId())){
-            throw new ServiceException("openID不能为空");
-        }
+//        // 校验openID
+//        if(StringUtils.isBlank(fareFreeRule.getOpenId())){
+//            throw new ServiceException("openID不能为空");
+//        }
         // 校验服务项目
         if (StringUtils.isBlank(fareFreeRule.getProjectId())) {
             throw new ServiceException("请至少选择一个服务项目");