批量推送
This commit is contained in:
+75
-10
@@ -18,13 +18,15 @@ import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
/**
|
||||
* 业务登录 - 角色选择
|
||||
* registerExecutor 完整实现 (2026-08-15 重构, 原 registerSupplier):
|
||||
* registerExecutor / registerSponsor 完整实现 (2026-08-15 重构, 原 registerSupplier):
|
||||
* 1. 校验短信验证码
|
||||
* 2. 检查手机号/用户名是否已注册
|
||||
* 3. 加密密码
|
||||
* 4. 插入 sys_user (用户名=前端传入, role_type=executor, 主账号)
|
||||
* 5. 插入 biz_org (executor 类型, business_nature/contact_phone 从表单)
|
||||
* 注: 主账号不建 biz_person, 跟 sponsor 主账号保持一致
|
||||
* 4. 插入 sys_user (用户名=前端传入, sys_user.role_type 写入 executor/sponsor, 主账号)
|
||||
* 5. 插入 biz_org (对应类型, business_nature/contact_phone 从表单)
|
||||
* 注: 主账号不建 biz_person
|
||||
*
|
||||
* 2026-08-16 重构: 删 biz_user_role_bind, 统一用 sys_user.role_type (见迁移脚本)
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/business/auth")
|
||||
@@ -101,7 +103,7 @@ public class BizAuthController extends BaseController {
|
||||
user.setStatus("0");
|
||||
userService.insertUser(user);
|
||||
Long userId = user.getUserId();
|
||||
// sys_user.role_type 字段需 = executor
|
||||
// 业务角色统一写到 sys_user.role_type (2026-08-16 重构, 删 biz_user_role_bind)
|
||||
userService.updateRoleType(userId, "executor");
|
||||
|
||||
// 5. 插入 biz_org (executor 类型, 主账号自己当 contact)
|
||||
@@ -116,15 +118,78 @@ public class BizAuthController extends BaseController {
|
||||
bizOrgService.insert(org);
|
||||
Long orgId = org.getOrgId();
|
||||
|
||||
// 注: 主账号不建 biz_person (与 sponsor 主账号保持一致, 见 sponsor/Account.vue)
|
||||
// 后续主账号在 [账号信息] 看到 [所属公司] 时, 后端可通过 sys_user.role_type 关联 biz_org 取 org_name
|
||||
// 子账号 (biz_person.unit_type='sponsor' + user_id 关联 sys_user.parent_user_id) 由 [人员管理] 创建
|
||||
|
||||
return success("注册成功, 请等待审核").put("userId", userId).put("orgId", orgId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册赞助方 (主账号), 流程与 executor 一致:
|
||||
* 校验 → 查重 → 写 sys_user + role_type=sponsor → 写 biz_org (sponsor 类型)
|
||||
*/
|
||||
@PostMapping("/registerSponsor")
|
||||
public AjaxResult registerSponsor(@RequestBody Map<String, Object> body) {
|
||||
return success();
|
||||
String username = (String) body.get("username");
|
||||
String unitName = (String) body.get("unitName");
|
||||
String businessNature = (String) body.get("businessNature");
|
||||
String phone = (String) body.get("phone");
|
||||
String code = (String) body.get("smsCode");
|
||||
String password = (String) body.get("password");
|
||||
String confirmPassword = (String) body.get("confirmPassword");
|
||||
String uuid = (String) body.get("uuid");
|
||||
|
||||
// 1. 基础校验 (与 executor 同)
|
||||
if (username == null || username.length() < 4 || username.length() > 20) return error("用户名长度 4-20 位");
|
||||
if (!username.matches("^[A-Za-z0-9_]+$")) return error("用户名只能包含字母/数字/下划线");
|
||||
if (unitName == null || unitName.isEmpty()) return error("企业名称不能为空");
|
||||
if (businessNature == null || businessNature.isEmpty()) return error("企业性质不能为空");
|
||||
if (phone == null || !phone.matches("^1\\d{10}$")) return error("手机号格式错误");
|
||||
if (code == null || code.isEmpty()) return error("请输入短信验证码");
|
||||
if (password == null || password.length() < 6 || password.length() > 20) return error("密码长度 6-20 位");
|
||||
if (!password.equals(confirmPassword)) return error("两次密码输入不一致");
|
||||
|
||||
// 2. 校验短信验证码
|
||||
SmsValidForm smsForm = new SmsValidForm();
|
||||
smsForm.setPhone(phone);
|
||||
smsForm.setSmsCode(code);
|
||||
smsForm.setUuid(uuid);
|
||||
try {
|
||||
smsService.verifyCode(smsForm);
|
||||
} catch (RuntimeException e) {
|
||||
return error("验证码错误或已过期: " + e.getMessage());
|
||||
}
|
||||
|
||||
// 3. 查重
|
||||
if (userService.isPhoneRegistered(phone)) {
|
||||
return error("该手机号已注册, 请直接登录");
|
||||
}
|
||||
SysUser nameCheck = new SysUser();
|
||||
nameCheck.setUserName(username);
|
||||
if (!userService.checkUserNameUnique(nameCheck)) {
|
||||
return error("用户名已被占用: " + username);
|
||||
}
|
||||
|
||||
// 4. 写 sys_user (role_type=sponsor)
|
||||
SysUser user = new SysUser();
|
||||
user.setUserName(username);
|
||||
user.setNickName(unitName);
|
||||
user.setPhonenumber(phone);
|
||||
user.setPassword(passwordEncoder.encode(password));
|
||||
user.setStatus("0");
|
||||
userService.insertUser(user);
|
||||
Long userId = user.getUserId();
|
||||
userService.updateRoleType(userId, "sponsor");
|
||||
|
||||
// 5. 写 biz_org (sponsor 类型)
|
||||
BizOrg org = new BizOrg();
|
||||
org.setOrgId(null);
|
||||
org.setOrgName(unitName);
|
||||
org.setOrgType("sponsor");
|
||||
org.setBusinessNature(businessNature);
|
||||
org.setContactPhone(phone);
|
||||
org.setContactName(unitName);
|
||||
org.setStatus("0");
|
||||
bizOrgService.insert(org);
|
||||
Long orgId = org.getOrgId();
|
||||
|
||||
return success("注册成功, 请等待审核").put("userId", userId).put("orgId", orgId);
|
||||
}
|
||||
}
|
||||
|
||||
+86
-1
@@ -1,15 +1,22 @@
|
||||
package com.ruoyi.business.controller;
|
||||
|
||||
import java.util.List;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.business.domain.BizExpert;
|
||||
import com.ruoyi.business.domain.vo.BizExpertExportVo;
|
||||
import com.ruoyi.business.domain.vo.BizExpertImportVo;
|
||||
import com.ruoyi.business.service.IBizExpertService;
|
||||
|
||||
/**
|
||||
@@ -41,11 +48,16 @@ public class BizExpertController extends BaseController
|
||||
{
|
||||
return success(bizExpertService.getByUserId(SecurityUtils.getUserId()));
|
||||
}
|
||||
/**
|
||||
* admin 创建专家: 同时创建 sys_user (用户名=手机号, 密码=手机号)
|
||||
* 返回 SysUser (含明文 password 给前端 toast 用)
|
||||
*/
|
||||
@Log(title = "专家", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody BizExpert bizExpert)
|
||||
{
|
||||
return toAjax(bizExpertService.insert(bizExpert));
|
||||
SysUser created = bizExpertService.insert(bizExpert);
|
||||
return success(created);
|
||||
}
|
||||
@Log(title = "专家", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
@@ -53,6 +65,16 @@ public class BizExpertController extends BaseController
|
||||
{
|
||||
return toAjax(bizExpertService.updateByPrimaryKey(bizExpert));
|
||||
}
|
||||
/**
|
||||
* 启用/禁用专家: 同步 biz_expert.status + sys_user.status
|
||||
* status='Y' 正常, status='N' 禁用
|
||||
*/
|
||||
@Log(title = "专家启停", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/{expertId}/status")
|
||||
public AjaxResult updateStatus(@PathVariable String expertId, @RequestParam String status)
|
||||
{
|
||||
return toAjax(bizExpertService.updateStatus(expertId, status));
|
||||
}
|
||||
/**
|
||||
* 个人专家信息更新 (走 userId 路由, 后端强制注入当前登录用户)
|
||||
* 不依赖前端传 expertId; 找不到 expert 行时自动 insert
|
||||
@@ -71,4 +93,67 @@ public class BizExpertController extends BaseController
|
||||
{
|
||||
return toAjax(bizExpertService.deleteByPrimaryKeys(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出专家列表 (中文列头)
|
||||
*/
|
||||
@Log(title = "专家", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('business:expert:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, BizExpert bizExpert)
|
||||
{
|
||||
List<BizExpert> list = bizExpertService.selectList(bizExpert);
|
||||
// 转换为导出 VO (中文列头 + 审核状态/状态 可读映射)
|
||||
List<BizExpertExportVo> exportList = new java.util.ArrayList<>(list.size());
|
||||
for (BizExpert e : list) {
|
||||
BizExpertExportVo v = new BizExpertExportVo();
|
||||
v.setName(e.getName());
|
||||
v.setPhone(e.getPhone());
|
||||
v.setWorkUnit(e.getWorkUnit());
|
||||
v.setDepartment(e.getDepartment());
|
||||
v.setTitle(e.getTitle());
|
||||
v.setRegion(e.getRegion());
|
||||
v.setIdCard(e.getIdCard());
|
||||
v.setBankCard(e.getBankCard());
|
||||
v.setBankName(e.getBankName());
|
||||
v.setBankProvince(e.getBankProvince());
|
||||
v.setBankCity(e.getBankCity());
|
||||
v.setBankAddress(e.getBankAddress());
|
||||
v.setStatus(e.getStatus());
|
||||
v.setAuditStatus(e.getAuditStatus());
|
||||
v.setAuditBy(e.getAuditBy());
|
||||
v.setAuditTime(e.getAuditTime());
|
||||
v.setCreateTime(e.getCreateTime());
|
||||
exportList.add(v);
|
||||
}
|
||||
ExcelUtil<BizExpertExportVo> util = new ExcelUtil<BizExpertExportVo>(BizExpertExportVo.class);
|
||||
util.exportExcel(response, exportList, "专家数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载专家导入模板
|
||||
*/
|
||||
@GetMapping("/importTemplate")
|
||||
public void importTemplate(HttpServletResponse response)
|
||||
{
|
||||
ExcelUtil<BizExpertImportVo> util = new ExcelUtil<BizExpertImportVo>(BizExpertImportVo.class);
|
||||
util.importTemplateExcel(response, "专家数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入专家 (Excel), 参考 RuoYi 系统用户导入模式
|
||||
* updateSupport=true: 同一手机号已存在 → 跳过 (按成功计)
|
||||
* 返回 message 含成功/失败计数 + 失败明细
|
||||
*/
|
||||
@Log(title = "专家", businessType = BusinessType.IMPORT)
|
||||
@PreAuthorize("@ss.hasPermi('business:expert:import')")
|
||||
@PostMapping("/importData")
|
||||
public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
|
||||
{
|
||||
ExcelUtil<BizExpertImportVo> util = new ExcelUtil<BizExpertImportVo>(BizExpertImportVo.class);
|
||||
List<BizExpertImportVo> importList = util.importExcel(file.getInputStream());
|
||||
String operName = SecurityUtils.getUsername();
|
||||
String message = bizExpertService.importExpert(importList, updateSupport, operName);
|
||||
return success(message);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ import com.ruoyi.business.service.IBizOrgService;
|
||||
|
||||
/**
|
||||
* 公司Controller (赞助方 + 执行方 共用)
|
||||
* GET /business/org/list?orgType=sponsor|execution
|
||||
* GET /business/org/list?orgType=sponsor|executor
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/business/org")
|
||||
|
||||
+2
-2
@@ -100,8 +100,8 @@ public class BizRegisterController extends BaseController {
|
||||
expert.setTitle(doctorTitle);
|
||||
expert.setPracticeCertUrl(licenseCertUrl);
|
||||
expert.setTitleCertUrl(titleCertUrl);
|
||||
expert.setAuditStatus("0");
|
||||
expert.setStatus("0");
|
||||
expert.setAuditStatus("1"); // BizAuditStatusEnum.PENDING = 待审核
|
||||
expert.setStatus("Y"); // biz_expert.status: Y=正常 N=禁用
|
||||
expertService.insert(expert);
|
||||
|
||||
return success("注册成功, 请等待审核").put("userId", userId);
|
||||
|
||||
@@ -7,7 +7,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* 公司对象 biz_org
|
||||
* 用途: 赞助方(sponsor) + 执行方(execution) 共用
|
||||
* 用途: 赞助方(sponsor) + 执行方(executor) 共用
|
||||
* 重构说明: 原 biz_support_unit + biz_execution_unit 合并, 通过 org_type 区分
|
||||
*/
|
||||
public class BizOrg extends BaseEntity {
|
||||
@@ -17,7 +17,7 @@ public class BizOrg extends BaseEntity {
|
||||
/** org_name */
|
||||
@Excel(name = "org_name")
|
||||
private String orgName;
|
||||
/** org_type: sponsor赞助方 / execution执行方 */
|
||||
/** org_type: sponsor赞助方 / executor执行方 */
|
||||
@Excel(name = "org_type")
|
||||
private String orgType;
|
||||
/** 企业性质 私营/国营/中外合资/外资/其他 */
|
||||
|
||||
@@ -52,7 +52,7 @@ public class BizProject extends BaseEntity {
|
||||
/** org_name (赞助方/执行方, 由 org_type 区分) */
|
||||
@Excel(name = "org_name")
|
||||
private String orgName;
|
||||
/** org_type: sponsor 赞助方 / execution 执行方 */
|
||||
/** org_type: sponsor 赞助方 / executor 执行方 */
|
||||
@Excel(name = "org_type")
|
||||
private String orgType;
|
||||
/** project_form */
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package com.ruoyi.business.domain.vo;
|
||||
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
|
||||
/**
|
||||
* 专家导出 VO (中文列头, 用户友好)
|
||||
*
|
||||
* <p>仅用于 Excel 导出, 不参与业务逻辑.
|
||||
*
|
||||
* @author guoju
|
||||
*/
|
||||
public class BizExpertExportVo {
|
||||
|
||||
@Excel(name = "姓名", sort = 1)
|
||||
private String name;
|
||||
|
||||
@Excel(name = "手机号", sort = 2)
|
||||
private String phone;
|
||||
|
||||
@Excel(name = "工作单位", sort = 3)
|
||||
private String workUnit;
|
||||
|
||||
@Excel(name = "科室", sort = 4)
|
||||
private String department;
|
||||
|
||||
@Excel(name = "职称", sort = 5)
|
||||
private String title;
|
||||
|
||||
@Excel(name = "地区", sort = 6)
|
||||
private String region;
|
||||
|
||||
@Excel(name = "身份证件号码", sort = 7)
|
||||
private String idCard;
|
||||
|
||||
@Excel(name = "银行卡号", sort = 8)
|
||||
private String bankCard;
|
||||
|
||||
@Excel(name = "银行名称", sort = 9)
|
||||
private String bankName;
|
||||
|
||||
@Excel(name = "开户行省份", sort = 10)
|
||||
private String bankProvince;
|
||||
|
||||
@Excel(name = "开户行城市", sort = 11)
|
||||
private String bankCity;
|
||||
|
||||
@Excel(name = "开户行地址", sort = 12)
|
||||
private String bankAddress;
|
||||
|
||||
@Excel(name = "状态", sort = 13, readConverterExp = "Y=正常,N=禁用")
|
||||
private String status;
|
||||
|
||||
@Excel(name = "审核状态", sort = 14, readConverterExp = "0=未提交,1=待审核,2=通过,3=拒绝")
|
||||
private String auditStatus;
|
||||
|
||||
@Excel(name = "审核人", sort = 15)
|
||||
private String auditBy;
|
||||
|
||||
@Excel(name = "审核时间", sort = 16, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date auditTime;
|
||||
|
||||
@Excel(name = "创建时间", sort = 17, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public String getPhone() { return phone; }
|
||||
public void setPhone(String phone) { this.phone = phone; }
|
||||
public String getWorkUnit() { return workUnit; }
|
||||
public void setWorkUnit(String workUnit) { this.workUnit = workUnit; }
|
||||
public String getDepartment() { return department; }
|
||||
public void setDepartment(String department) { this.department = department; }
|
||||
public String getTitle() { return title; }
|
||||
public void setTitle(String title) { this.title = title; }
|
||||
public String getRegion() { return region; }
|
||||
public void setRegion(String region) { this.region = region; }
|
||||
public String getIdCard() { return idCard; }
|
||||
public void setIdCard(String idCard) { this.idCard = idCard; }
|
||||
public String getBankCard() { return bankCard; }
|
||||
public void setBankCard(String bankCard) { this.bankCard = bankCard; }
|
||||
public String getBankName() { return bankName; }
|
||||
public void setBankName(String bankName) { this.bankName = bankName; }
|
||||
public String getBankProvince() { return bankProvince; }
|
||||
public void setBankProvince(String bankProvince) { this.bankProvince = bankProvince; }
|
||||
public String getBankCity() { return bankCity; }
|
||||
public void setBankCity(String bankCity) { this.bankCity = bankCity; }
|
||||
public String getBankAddress() { return bankAddress; }
|
||||
public void setBankAddress(String bankAddress) { this.bankAddress = bankAddress; }
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
public String getAuditStatus() { return auditStatus; }
|
||||
public void setAuditStatus(String auditStatus) { this.auditStatus = auditStatus; }
|
||||
public String getAuditBy() { return auditBy; }
|
||||
public void setAuditBy(String auditBy) { this.auditBy = auditBy; }
|
||||
public Date getAuditTime() { return auditTime; }
|
||||
public void setAuditTime(Date auditTime) { this.auditTime = auditTime; }
|
||||
public Date getCreateTime() { return createTime; }
|
||||
public void setCreateTime(Date createTime) { this.createTime = createTime; }
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
package com.ruoyi.business.domain.vo;
|
||||
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
|
||||
/**
|
||||
* 专家导入 VO
|
||||
*
|
||||
* <p>仅用于 Excel 批量导入 / 模板下载 / 导出, 不参与业务逻辑.
|
||||
* 字段顺序与 Excel 列一致, 调整时同步修改模板下载体验.
|
||||
*
|
||||
* @author guoju
|
||||
*/
|
||||
public class BizExpertImportVo {
|
||||
|
||||
/** 姓名 */
|
||||
@Excel(name = "姓名", sort = 1)
|
||||
private String name;
|
||||
|
||||
/** 手机号 */
|
||||
@Excel(name = "手机号", sort = 2)
|
||||
private String phone;
|
||||
|
||||
/** 工作单位 */
|
||||
@Excel(name = "工作单位", sort = 3)
|
||||
private String workUnit;
|
||||
|
||||
/** 科室 */
|
||||
@Excel(name = "科室", sort = 4)
|
||||
private String department;
|
||||
|
||||
/** 职称 */
|
||||
@Excel(name = "职称", sort = 5)
|
||||
private String title;
|
||||
|
||||
/** 地区 */
|
||||
@Excel(name = "地区", sort = 6)
|
||||
private String region;
|
||||
|
||||
/** 身份证件号码 */
|
||||
@Excel(name = "身份证件号码", sort = 7)
|
||||
private String idCard;
|
||||
|
||||
/** 身份证件照片 正面URL */
|
||||
@Excel(name = "身份证正面URL", sort = 8)
|
||||
private String idCardFrontUrl;
|
||||
|
||||
/** 身份证件照片 反面URL */
|
||||
@Excel(name = "身份证反面URL", sort = 9)
|
||||
private String idCardBackUrl;
|
||||
|
||||
/** 执业医师证书 URL */
|
||||
@Excel(name = "执业医师证书URL", sort = 10)
|
||||
private String practiceCertUrl;
|
||||
|
||||
/** 职称证明 URL */
|
||||
@Excel(name = "职称证明URL", sort = 11)
|
||||
private String titleCertUrl;
|
||||
|
||||
/** 银行卡号 */
|
||||
@Excel(name = "银行卡号", sort = 12)
|
||||
private String bankCard;
|
||||
|
||||
/** 银行名称 */
|
||||
@Excel(name = "银行名称", sort = 13)
|
||||
private String bankName;
|
||||
|
||||
/** 开户行省份 */
|
||||
@Excel(name = "开户行省份", sort = 14)
|
||||
private String bankProvince;
|
||||
|
||||
/** 开户行城市 */
|
||||
@Excel(name = "开户行城市", sort = 15)
|
||||
private String bankCity;
|
||||
|
||||
/** 开户行地址 */
|
||||
@Excel(name = "开户行地址", sort = 16)
|
||||
private String bankAddress;
|
||||
|
||||
/** 状态 (Y=正常 N=禁用, 留空默认 Y) */
|
||||
@Excel(name = "状态", sort = 17, readConverterExp = "Y=正常,N=禁用")
|
||||
private String status;
|
||||
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public String getPhone() { return phone; }
|
||||
public void setPhone(String phone) { this.phone = phone; }
|
||||
public String getWorkUnit() { return workUnit; }
|
||||
public void setWorkUnit(String workUnit) { this.workUnit = workUnit; }
|
||||
public String getDepartment() { return department; }
|
||||
public void setDepartment(String department) { this.department = department; }
|
||||
public String getTitle() { return title; }
|
||||
public void setTitle(String title) { this.title = title; }
|
||||
public String getRegion() { return region; }
|
||||
public void setRegion(String region) { this.region = region; }
|
||||
public String getIdCard() { return idCard; }
|
||||
public void setIdCard(String idCard) { this.idCard = idCard; }
|
||||
public String getIdCardFrontUrl() { return idCardFrontUrl; }
|
||||
public void setIdCardFrontUrl(String idCardFrontUrl) { this.idCardFrontUrl = idCardFrontUrl; }
|
||||
public String getIdCardBackUrl() { return idCardBackUrl; }
|
||||
public void setIdCardBackUrl(String idCardBackUrl) { this.idCardBackUrl = idCardBackUrl; }
|
||||
public String getPracticeCertUrl() { return practiceCertUrl; }
|
||||
public void setPracticeCertUrl(String practiceCertUrl) { this.practiceCertUrl = practiceCertUrl; }
|
||||
public String getTitleCertUrl() { return titleCertUrl; }
|
||||
public void setTitleCertUrl(String titleCertUrl) { this.titleCertUrl = titleCertUrl; }
|
||||
public String getBankCard() { return bankCard; }
|
||||
public void setBankCard(String bankCard) { this.bankCard = bankCard; }
|
||||
public String getBankName() { return bankName; }
|
||||
public void setBankName(String bankName) { this.bankName = bankName; }
|
||||
public String getBankProvince() { return bankProvince; }
|
||||
public void setBankProvince(String bankProvince) { this.bankProvince = bankProvince; }
|
||||
public String getBankCity() { return bankCity; }
|
||||
public void setBankCity(String bankCity) { this.bankCity = bankCity; }
|
||||
public String getBankAddress() { return bankAddress; }
|
||||
public void setBankAddress(String bankAddress) { this.bankAddress = bankAddress; }
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
}
|
||||
+19
-1
@@ -2,6 +2,8 @@ package com.ruoyi.business.service;
|
||||
|
||||
import java.util.List;
|
||||
import com.ruoyi.business.domain.BizExpert;
|
||||
import com.ruoyi.business.domain.vo.BizExpertImportVo;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
|
||||
/**
|
||||
* 专家Service接口
|
||||
@@ -11,10 +13,26 @@ public interface IBizExpertService
|
||||
BizExpert getById(String expertId);
|
||||
BizExpert getByUserId(Long userId);
|
||||
List<BizExpert> selectList(BizExpert entity);
|
||||
int insert(BizExpert entity);
|
||||
/**
|
||||
* 新建专家: 同时创建 sys_user (用户名=手机号, 密码=手机号, role_type=doctor)
|
||||
* 若 sys_user.username(=phone) 已存在, 抛 ServiceException("该手机号已注册")
|
||||
* 返回 SysUser 含 username + 明文 password (仅本次返回,前端 toast 显示后即丢)
|
||||
*/
|
||||
SysUser insert(BizExpert entity);
|
||||
int updateByPrimaryKey(BizExpert entity);
|
||||
/**
|
||||
* 启用/禁用专家: 同步更新 biz_expert.status + sys_user.status
|
||||
* status='Y' 正常, status='N' 禁用
|
||||
*/
|
||||
int updateStatus(String expertId, String status);
|
||||
/** 按 userId 更新或新建 (upsert) */
|
||||
int updateProfileByUserId(BizExpert entity);
|
||||
int deleteByPrimaryKey(String expertId);
|
||||
int deleteByPrimaryKeys(String[] expertId);
|
||||
|
||||
/**
|
||||
* 批量导入专家: 每行调用 insert, updateSupport=true 时跳过已存在手机号(视为成功)
|
||||
* 返回 String 含成功/失败计数 + 失败明细 (前端 toast 显示)
|
||||
*/
|
||||
String importExpert(List<BizExpertImportVo> importList, boolean updateSupport, String operName);
|
||||
}
|
||||
|
||||
+187
-1
@@ -4,8 +4,13 @@ import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.business.domain.BizExpert;
|
||||
import com.ruoyi.business.domain.vo.BizExpertImportVo;
|
||||
import com.ruoyi.business.mapper.BizExpertMapper;
|
||||
import com.ruoyi.business.service.IBizExpertService;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
@Service
|
||||
public class BizExpertServiceImpl implements IBizExpertService
|
||||
@@ -13,6 +18,9 @@ public class BizExpertServiceImpl implements IBizExpertService
|
||||
@Autowired
|
||||
private BizExpertMapper bizExpertMapper;
|
||||
|
||||
@Autowired
|
||||
private ISysUserService sysUserService;
|
||||
|
||||
@Override
|
||||
public BizExpert getById(String expertId)
|
||||
{ return bizExpertMapper.selectByPrimaryKey(expertId); }
|
||||
@@ -22,11 +30,86 @@ public class BizExpertServiceImpl implements IBizExpertService
|
||||
@Override
|
||||
public List<BizExpert> selectList(BizExpert entity)
|
||||
{ return bizExpertMapper.selectList(entity); }
|
||||
|
||||
/**
|
||||
* admin 创建专家: 同时创建 sys_user (用户名=手机号, 密码=手机号, role_type=doctor)
|
||||
* 1. 校验 phone 没注册过 (抛 ServiceException)
|
||||
* 2. 创建 sys_user + bcrypt 加密密码
|
||||
* 3. 设置 role_type=doctor (与公开注册一致)
|
||||
* 4. 创建 biz_expert 绑定 user_id
|
||||
* 5. 返回 SysUser 含明文 password (前端 toast 用完即丢)
|
||||
*/
|
||||
@Override
|
||||
public int insert(BizExpert entity) { com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "expertId"); return bizExpertMapper.insert(entity); }
|
||||
public SysUser insert(BizExpert entity) {
|
||||
String phone = entity.getPhone();
|
||||
if (phone == null || phone.isEmpty()) {
|
||||
throw new ServiceException("手机号不能为空");
|
||||
}
|
||||
// 0. 校验 phone 唯一 (查 sys_user, 若 username=phone 已存在即重复)
|
||||
if (sysUserService.isPhoneRegistered(phone)) {
|
||||
throw new ServiceException("该手机号已注册,请直接登录");
|
||||
}
|
||||
|
||||
// 1. 创建 sys_user (用户名=phone, 密码=phone)
|
||||
SysUser newUser = new SysUser();
|
||||
newUser.setUserName(phone);
|
||||
newUser.setNickName(entity.getName());
|
||||
newUser.setPhonenumber(phone);
|
||||
newUser.setPassword(SecurityUtils.encryptPassword(phone));
|
||||
newUser.setStatus("0");
|
||||
newUser.setDelFlag("0");
|
||||
newUser.setCreateBy(SecurityUtils.getUsername());
|
||||
sysUserService.insertUser(newUser);
|
||||
Long userId = newUser.getUserId();
|
||||
|
||||
// 2. role_type = doctor (跟公开注册一致,DB 默认 executor, 专家需 doctor)
|
||||
sysUserService.updateRoleType(userId, "doctor");
|
||||
|
||||
// 3. 创建 biz_expert 绑定 user_id
|
||||
entity.setUserId(userId);
|
||||
com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "expertId");
|
||||
bizExpertMapper.insert(entity);
|
||||
|
||||
// 4. 把明文密码回填 SysUser (仅本次返回,前端 toast 显示)
|
||||
newUser.setPassword(phone);
|
||||
return newUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateByPrimaryKey(BizExpert entity)
|
||||
{ return bizExpertMapper.updateByPrimaryKey(entity); }
|
||||
|
||||
/**
|
||||
* 启用/禁用专家: 同步 biz_expert.status + sys_user.status
|
||||
* biz_expert.status: 'Y'=正常 'N'=禁用
|
||||
* sys_user.status: '0'=正常 '1'=停用 (RuoYi 框架约定, 同步时转换)
|
||||
*/
|
||||
@Override
|
||||
public int updateStatus(String expertId, String status) {
|
||||
if (status == null || (!"Y".equals(status) && !"N".equals(status))) {
|
||||
throw new ServiceException("status 必须是 'Y'(正常) 或 'N'(禁用)");
|
||||
}
|
||||
BizExpert existed = bizExpertMapper.selectByPrimaryKey(expertId);
|
||||
if (existed == null) {
|
||||
throw new ServiceException("专家不存在");
|
||||
}
|
||||
// 1. 更新 biz_expert.status
|
||||
BizExpert update = new BizExpert();
|
||||
update.setExpertId(expertId);
|
||||
update.setStatus(status);
|
||||
update.setUpdateBy(SecurityUtils.getUsername());
|
||||
int n = bizExpertMapper.updateByPrimaryKey(update);
|
||||
// 2. 同步 sys_user.status (登录账号启停, 'Y'→'0', 'N'→'1')
|
||||
if (n > 0 && existed.getUserId() != null) {
|
||||
SysUser u = new SysUser();
|
||||
u.setUserId(existed.getUserId());
|
||||
u.setStatus("Y".equals(status) ? "0" : "1");
|
||||
u.setUpdateBy(SecurityUtils.getUsername());
|
||||
sysUserService.updateUser(u);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateProfileByUserId(BizExpert entity)
|
||||
{
|
||||
@@ -42,4 +125,107 @@ public class BizExpertServiceImpl implements IBizExpertService
|
||||
@Override
|
||||
public int deleteByPrimaryKeys(String[] expertId)
|
||||
{ return bizExpertMapper.deleteByPrimaryKeys(expertId); }
|
||||
|
||||
/**
|
||||
* 批量导入专家:
|
||||
* 1. 每行 必填校验 (姓名/手机号/工作单位/科室/职称, 手机号正则 1[0-9]{10})
|
||||
* 2. status 留空 → Y (正常); 非法值 → 抛错
|
||||
* 3. sys_user 同步创建 (与单条 insert 共用 sys_userService.insertUser)
|
||||
* 4. updateSupport=true 时: 同一手机号已存在 → 跳过 (按成功计)
|
||||
* 5. 单行失败不中断, 错误信息累计
|
||||
*/
|
||||
@Override
|
||||
public String importExpert(List<BizExpertImportVo> importList, boolean updateSupport, String operName) {
|
||||
if (importList == null || importList.isEmpty()) {
|
||||
throw new ServiceException("导入数据不能为空");
|
||||
}
|
||||
int successNum = 0;
|
||||
int failureNum = 0;
|
||||
StringBuilder successMsg = new StringBuilder();
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < importList.size(); i++) {
|
||||
BizExpertImportVo vo = importList.get(i);
|
||||
int rowNo = i + 2; // Excel 行号 (1=表头)
|
||||
try {
|
||||
// 必填校验
|
||||
if (vo.getName() == null || vo.getName().trim().isEmpty()) {
|
||||
throw new ServiceException("姓名不能为空");
|
||||
}
|
||||
if (vo.getPhone() == null || vo.getPhone().trim().isEmpty()) {
|
||||
throw new ServiceException("手机号不能为空");
|
||||
}
|
||||
if (!vo.getPhone().matches("^1[0-9]\\d{9}$")) {
|
||||
throw new ServiceException("手机号格式不正确");
|
||||
}
|
||||
if (vo.getWorkUnit() == null || vo.getWorkUnit().trim().isEmpty()) {
|
||||
throw new ServiceException("工作单位不能为空");
|
||||
}
|
||||
if (vo.getDepartment() == null || vo.getDepartment().trim().isEmpty()) {
|
||||
throw new ServiceException("科室不能为空");
|
||||
}
|
||||
if (vo.getTitle() == null || vo.getTitle().trim().isEmpty()) {
|
||||
throw new ServiceException("职称不能为空");
|
||||
}
|
||||
// status 校验, 留空 → Y
|
||||
String status = vo.getStatus();
|
||||
if (status == null || status.trim().isEmpty()) {
|
||||
status = "Y";
|
||||
} else if (!"Y".equals(status) && !"N".equals(status)) {
|
||||
throw new ServiceException("状态只能是 Y(正常) 或 N(禁用)");
|
||||
}
|
||||
|
||||
// 同一手机号已存在 → updateSupport=true 跳过, 否则报错
|
||||
if (sysUserService.isPhoneRegistered(vo.getPhone())) {
|
||||
if (updateSupport) {
|
||||
successNum++;
|
||||
successMsg.append("<br/>" + successNum + "、手机号 " + vo.getPhone() + " 已存在, 已跳过");
|
||||
continue;
|
||||
}
|
||||
throw new ServiceException("手机号 " + vo.getPhone() + " 已存在");
|
||||
}
|
||||
|
||||
// 复用单条 insert 逻辑 (含 sys_user 创建)
|
||||
BizExpert entity = new BizExpert();
|
||||
entity.setName(vo.getName());
|
||||
entity.setPhone(vo.getPhone());
|
||||
entity.setWorkUnit(vo.getWorkUnit());
|
||||
entity.setDepartment(vo.getDepartment());
|
||||
entity.setTitle(vo.getTitle());
|
||||
entity.setRegion(vo.getRegion());
|
||||
entity.setIdCard(vo.getIdCard());
|
||||
entity.setIdCardFrontUrl(vo.getIdCardFrontUrl());
|
||||
entity.setIdCardBackUrl(vo.getIdCardBackUrl());
|
||||
entity.setPracticeCertUrl(vo.getPracticeCertUrl());
|
||||
entity.setTitleCertUrl(vo.getTitleCertUrl());
|
||||
entity.setBankCard(vo.getBankCard());
|
||||
entity.setBankName(vo.getBankName());
|
||||
entity.setBankProvince(vo.getBankProvince());
|
||||
entity.setBankCity(vo.getBankCity());
|
||||
entity.setBankAddress(vo.getBankAddress());
|
||||
entity.setStatus(status);
|
||||
// admin 批量导入默认通过审核 (与单条 admin 创建一致)
|
||||
entity.setAuditStatus("2");
|
||||
entity.setAuditBy(operName);
|
||||
entity.setAuditTime(new java.util.Date());
|
||||
entity.setCreateBy(operName);
|
||||
|
||||
insert(entity);
|
||||
successNum++;
|
||||
successMsg.append("<br/>" + successNum + "、账号 " + vo.getPhone() + " 导入成功");
|
||||
} catch (Exception e) {
|
||||
failureNum++;
|
||||
String msg = e.getMessage();
|
||||
if (msg == null) msg = e.getClass().getSimpleName();
|
||||
failureMsg.append("<br/>" + failureNum + "、第 " + rowNo + " 行: " + msg);
|
||||
}
|
||||
}
|
||||
if (failureNum > 0) {
|
||||
failureMsg.insert(0, "很抱歉, 部分导入失败, 共 " + failureNum + " 条:");
|
||||
}
|
||||
if (successNum > 0) {
|
||||
successMsg.insert(0, "恭喜您, 数据已全部导入成功!共 " + successNum + " 条, 数据如下:");
|
||||
}
|
||||
return successMsg.toString() + failureMsg.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<result property="updateTime" column="update_time" />
|
||||
</resultMap>
|
||||
<sql id="selectFields">
|
||||
select expert_id, user_id, name, phone, region, id_card, work_unit, department, title, practice_cert_url, title_cert_url, bank_card, bank_name, bank_province, bank_city, bank_address, id_card_front_url, id_card_back_url, audit_status, audit_by, audit_time, create_by, create_time, update_by, update_time
|
||||
select expert_id, user_id, name, phone, region, id_card, work_unit, department, title, practice_cert_url, title_cert_url, bank_card, bank_name, bank_province, bank_city, bank_address, id_card_front_url, id_card_back_url, audit_status, audit_by, audit_time, status, create_by, create_time, update_by, update_time
|
||||
from biz_expert
|
||||
</sql>
|
||||
<select id="selectByUserId" resultMap="BizExpertResult" parameterType="Long">
|
||||
@@ -197,7 +197,7 @@
|
||||
<if test="auditStatus != null and auditStatus != ''">audit_status = #{auditStatus},</if>
|
||||
<if test="auditOpinion != null and auditOpinion != ''">audit_opinion = #{auditOpinion},</if>
|
||||
<if test="auditBy != null and auditBy != ''">audit_by = #{auditBy},</if>
|
||||
<if test="auditTime != null and auditTime != ''">audit_time = #{auditTime},</if>
|
||||
<if test="auditTime != null">audit_time = #{auditTime},</if>
|
||||
<if test="status != null and status != ''">status = #{status},</if>
|
||||
<if test="name != null">name = #{name},</if>
|
||||
<if test="phone != null">phone = #{phone},</if>
|
||||
|
||||
Reference in New Issue
Block a user