refactor(doctor/submissions): 合并到 biz_project_plan + 删除 biz_submission 死代码

- /doctor/submissions 改走 biz_project_plan,与 /manager/plans 字段/组件/状态字典完全对齐
- BizProjectPlan 加 submitter_id (BIGINT) + submitter_name (LEFT JOIN 查询字段)
- mapper 改 LEFT JOIN biz_person + sys_user,COALESCE(bp.name, u.user_name) 兜底
- biz_person.user_id 加 UNIQUE 索引 (1:1 LEFT JOIN 无笛卡尔积)
- controller 加 doctor 角色自动过滤: list 按 submitter_id, add/edit 强制 submitter_id
- 删除 7 个 BizSubmission 死代码 (Controller/Service/Mapper/Domain/XML/Enum) + 1 utils
- 路由参数 :subId → :planId (路径名 submission 保留产品文案)
- 新增 migration_submission_to_projectPlan_2026_08_18.sql
This commit is contained in:
郭庆泰
2026-08-18 00:28:40 +08:00
parent b41cf77cac
commit c9fc6ebdb8
17 changed files with 245 additions and 562 deletions
@@ -8,11 +8,16 @@ import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.business.domain.BizProjectPlan;
import com.ruoyi.business.service.IBizProjectPlanService;
/**
* 项目策划方案Controller
*
* 角色权限:
* - doctor: 只看自己投的稿 (submitter_id = 当前用户); 新建/编辑强制 submitter_id 写自己, status 默认 '0'
* - manager / leader / sponsor / admin: 全部可见, 不强制 submitter
*/
@RestController
@RequestMapping("/business/projectPlan")
@@ -23,6 +28,11 @@ public class BizProjectPlanController extends BaseController
@GetMapping("/list")
public TableDataInfo list(BizProjectPlan BizProjectPlan)
{
// 医生角色: 后端兜底只查自己投的稿
String roleType = SecurityUtils.getLoginUser().getUser().getRoleType();
if ("doctor".equals(roleType)) {
BizProjectPlan.setSubmitterId(SecurityUtils.getUserId());
}
startPage();
List<BizProjectPlan> list = BizProjectPlanService.selectList(BizProjectPlan);
return getDataTable(list);
@@ -36,12 +46,25 @@ public class BizProjectPlanController extends BaseController
@PostMapping
public AjaxResult add(@RequestBody BizProjectPlan BizProjectPlan)
{
// 医生角色: 强制 submitter_id 写自己 + 状态兜底 '0' (未提交), 防止绕过
String roleType = SecurityUtils.getLoginUser().getUser().getRoleType();
if ("doctor".equals(roleType)) {
BizProjectPlan.setSubmitterId(SecurityUtils.getUserId());
if (BizProjectPlan.getStatus() == null || BizProjectPlan.getStatus().isEmpty()) {
BizProjectPlan.setStatus("0");
}
}
return toAjax(BizProjectPlanService.insert(BizProjectPlan));
}
@Log(title = "项目策划方案", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody BizProjectPlan BizProjectPlan)
{
// 医生角色: 修改时也强制覆盖 submitter_id, 防止越权篡改
String roleType = SecurityUtils.getLoginUser().getUser().getRoleType();
if ("doctor".equals(roleType)) {
BizProjectPlan.setSubmitterId(SecurityUtils.getUserId());
}
return toAjax(BizProjectPlanService.updateByPrimaryKey(BizProjectPlan));
}
@Log(title = "项目策划方案", businessType = BusinessType.DELETE)
@@ -1,79 +0,0 @@
package com.ruoyi.business.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
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.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.business.domain.BizSubmission;
import com.ruoyi.business.enums.SubmissionStatus;
import com.ruoyi.business.service.IBizSubmissionService;
/**
* 投稿Controller
*/
@RestController
@RequestMapping("/business/submission")
public class BizSubmissionController extends BaseController
{
@Autowired
private IBizSubmissionService bizSubmissionService;
@GetMapping("/list")
public TableDataInfo list(BizSubmission bizSubmission)
{
// 后端兜底: 只查当前登录用户提交的; admin 跳过此限制
if (!SecurityUtils.isAdmin()) {
bizSubmission.setSubmitterId(SecurityUtils.getUserId());
}
startPage();
List<BizSubmission> list = bizSubmissionService.selectList(bizSubmission);
return getDataTable(list);
}
@GetMapping("/{submissionId}")
public AjaxResult getInfo(@PathVariable("submissionId") String submissionId)
{
return success(bizSubmissionService.getById(submissionId));
}
@Log(title = "投稿", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody BizSubmission bizSubmission)
{
// 后端兜底: 强制写入当前登录用户, 防止前端漏传/绕过导致列表过滤查不到
bizSubmission.setSubmitterId(SecurityUtils.getUserId());
bizSubmission.setSubmitterName(SecurityUtils.getUsername());
bizSubmission.setCreateBy(getUsername());
bizSubmission.setUpdateBy(getUsername());
// 状态: 新建默认 DRAFT(待提交); 校验必须是英文 code 之一
if (bizSubmission.getStatus() == null || bizSubmission.getStatus().isEmpty()) {
bizSubmission.setStatus(SubmissionStatus.DRAFT.getCode());
} else if (!SubmissionStatus.isValid(bizSubmission.getStatus())) {
return AjaxResult.error("状态值非法: " + bizSubmission.getStatus());
}
return toAjax(bizSubmissionService.insert(bizSubmission));
}
@Log(title = "投稿", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody BizSubmission bizSubmission)
{
// 修改时也强制覆盖 submitterId/submitterName, 防止越权篡改为他人
bizSubmission.setSubmitterId(SecurityUtils.getUserId());
bizSubmission.setSubmitterName(SecurityUtils.getUsername());
bizSubmission.setUpdateBy(getUsername());
// 状态校验 (英文 code)
if (bizSubmission.getStatus() != null && !bizSubmission.getStatus().isEmpty()
&& !SubmissionStatus.isValid(bizSubmission.getStatus())) {
return AjaxResult.error("状态值非法: " + bizSubmission.getStatus());
}
return toAjax(bizSubmissionService.updateByPrimaryKey(bizSubmission));
}
@Log(title = "投稿", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable String[] ids)
{
return toAjax(bizSubmissionService.deleteByPrimaryKeys(ids));
}
}
@@ -17,6 +17,10 @@ public class BizProjectPlan extends BaseEntity {
/** plan_direction */
@Excel(name = "plan_direction")
private String planDirection;
/** 项目方向-专项计划ID (关联 biz_special_plan.id) */
private Long planDirectionId;
/** 项目方向-专项计划名称 (LEFT JOIN biz_special_plan.title, 列表展示用) */
private String planDirectionTitle;
/** plan_category */
@Excel(name = "plan_category")
private String planCategory;
@@ -61,12 +65,20 @@ public class BizProjectPlan extends BaseEntity {
private String auditBy;
/** 审核时间 */
private String auditTime;
/** 投稿人用户ID (医生侧投稿归属, 经理/admin 录入为 NULL) */
private Long submitterId;
/** 投稿人姓名 (LEFT JOIN biz_person.name 优先, sys_user.user_name 兜底; biz_person.user_id 已 UNIQUE, 1:1 无笛卡尔积) */
private String submitterName;
public String getPlanId() { return planId; }
public void setPlanId(String planId) { this.planId = planId; }
public String getPlanName() { return planName; }
public void setPlanName(String planName) { this.planName = planName; }
public String getPlanDirection() { return planDirection; }
public void setPlanDirection(String planDirection) { this.planDirection = planDirection; }
public Long getPlanDirectionId() { return planDirectionId; }
public void setPlanDirectionId(Long planDirectionId) { this.planDirectionId = planDirectionId; }
public String getPlanDirectionTitle() { return planDirectionTitle; }
public void setPlanDirectionTitle(String planDirectionTitle) { this.planDirectionTitle = planDirectionTitle; }
public String getPlanCategory() { return planCategory; }
public void setPlanCategory(String planCategory) { this.planCategory = planCategory; }
public String getProjectForm() { return projectForm; }
@@ -91,4 +103,8 @@ public class BizProjectPlan extends BaseEntity {
public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
public Date getUpdateTime() { return updateTime; }
public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
public Long getSubmitterId() { return submitterId; }
public void setSubmitterId(Long submitterId) { this.submitterId = submitterId; }
public String getSubmitterName() { return submitterName; }
public void setSubmitterName(String submitterName) { this.submitterName = submitterName; }
}
@@ -1,86 +0,0 @@
package com.ruoyi.business.domain;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
/** 投稿对象 BizSubmission */
public class BizSubmission extends BaseEntity {
private static final long serialVersionUID = 1L;
/** subId */
private String subId;
/** title */
@Excel(name = "title")
private String title;
/** direction */
@Excel(name = "direction")
private String direction;
/** project_form */
@Excel(name = "project_form")
private String projectForm;
/** design_file_url */
@Excel(name = "design_file_url")
private String designFileUrl;
/** status */
@Excel(name = "status")
private String status;
/** remark */
@Excel(name = "remark")
private String remark;
/** create_by */
@Excel(name = "create_by")
private String createBy;
/** create_time */
@Excel(name = "create_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/** update_by */
@Excel(name = "update_by")
private String updateBy;
/** update_time */
@Excel(name = "update_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
/** 投稿人用户ID */
private Long submitterId;
/** 投稿人姓名 */
private String submitterName;
/** 项目类别 学术会议类/专项科研类/调研征集类/慈善帮扶类/标准制定类/患者援助类/专业培训类 */
private String projectCategory;
/** 审核意见 */
private String auditOpinion;
/** 审核人 */
private String auditBy;
/** 审核时间 */
private String auditTime;
public String getSubId() { return subId; }
public void setSubId(String subId) { this.subId = subId; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getDirection() { return direction; }
public void setDirection(String direction) { this.direction = direction; }
public String getProjectForm() { return projectForm; }
public void setProjectForm(String projectForm) { this.projectForm = projectForm; }
public String getProjectCategory() { return projectCategory; }
public void setProjectCategory(String projectCategory) { this.projectCategory = projectCategory; }
public String getDesignFileUrl() { return designFileUrl; }
public void setDesignFileUrl(String designFileUrl) { this.designFileUrl = designFileUrl; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getRemark() { return remark; }
public void setRemark(String remark) { this.remark = remark; }
public Long getSubmitterId() { return submitterId; }
public void setSubmitterId(Long submitterId) { this.submitterId = submitterId; }
public String getSubmitterName() { return submitterName; }
public void setSubmitterName(String submitterName) { this.submitterName = submitterName; }
public String getCreateBy() { return createBy; }
public void setCreateBy(String createBy) { this.createBy = createBy; }
public Date getCreateTime() { return createTime; }
public void setCreateTime(Date createTime) { this.createTime = createTime; }
public String getUpdateBy() { return updateBy; }
public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
public Date getUpdateTime() { return updateTime; }
public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
}
@@ -1,43 +0,0 @@
package com.ruoyi.business.enums;
import java.util.HashMap;
import java.util.Map;
/**
* 投稿状态枚举
*
* 数据库存储英文 code (PENDING/APPROVED/REJECTED/DRAFT), 不存中文也不存数字.
* 字典映射集中在这里避免散落. 前端 utils/submissionStatus.js 同步这份字典.
*/
public enum SubmissionStatus
{
PENDING("PENDING", "待审核"),
APPROVED("APPROVED", "审核通过"),
REJECTED("REJECTED", "已退回"),
DRAFT("DRAFT", "待提交");
private final String code;
private final String label;
SubmissionStatus(String code, String label) {
this.code = code;
this.label = label;
}
public String getCode() { return code; }
public String getLabel() { return label; }
private static final Map<String, SubmissionStatus> BY_CODE = new HashMap<>();
static {
for (SubmissionStatus s : values()) BY_CODE.put(s.code, s);
}
public static SubmissionStatus fromCode(String val) {
if (val == null) return null;
return BY_CODE.get(val.trim().toUpperCase());
}
public static boolean isValid(String val) {
return fromCode(val) != null;
}
}
@@ -1,16 +0,0 @@
package com.ruoyi.business.mapper;
import java.util.List;
import com.ruoyi.business.domain.BizSubmission;
/**
* 投稿Mapper接口
*/
public interface BizSubmissionMapper
{
BizSubmission selectByPrimaryKey(String subId);
List<BizSubmission> selectList(BizSubmission entity);
int insert(BizSubmission entity);
int updateByPrimaryKey(BizSubmission entity);
int deleteByPrimaryKey(String subId);
int deleteByPrimaryKeys(String[] subIds);
}
@@ -1,17 +0,0 @@
package com.ruoyi.business.service;
import java.util.List;
import com.ruoyi.business.domain.BizSubmission;
/**
* 投稿Service接口
*/
public interface IBizSubmissionService
{
BizSubmission getById(String submissionId);
List<BizSubmission> selectList(BizSubmission entity);
int insert(BizSubmission entity);
int updateByPrimaryKey(BizSubmission entity);
int deleteByPrimaryKey(String submissionId);
int deleteByPrimaryKeys(String[] submissionId);
}
@@ -1,33 +0,0 @@
package com.ruoyi.business.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.business.domain.BizSubmission;
import com.ruoyi.business.mapper.BizSubmissionMapper;
import com.ruoyi.business.service.IBizSubmissionService;
@Service
public class BizSubmissionServiceImpl implements IBizSubmissionService
{
@Autowired
private BizSubmissionMapper bizSubmissionMapper;
@Override
public BizSubmission getById(String submissionId)
{ return bizSubmissionMapper.selectByPrimaryKey(submissionId); }
@Override
public List<BizSubmission> selectList(BizSubmission entity)
{ return bizSubmissionMapper.selectList(entity); }
@Override
public int insert(BizSubmission entity) { com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "subId"); return bizSubmissionMapper.insert(entity); }
@Override
public int updateByPrimaryKey(BizSubmission entity)
{ return bizSubmissionMapper.updateByPrimaryKey(entity); }
@Override
public int deleteByPrimaryKey(String submissionId)
{ return bizSubmissionMapper.deleteByPrimaryKey(submissionId); }
@Override
public int deleteByPrimaryKeys(String[] submissionId)
{ return bizSubmissionMapper.deleteByPrimaryKeys(submissionId); }
}
@@ -5,6 +5,8 @@
<id property="planId" column="plan_id" />
<result property="planName" column="plan_name" />
<result property="planDirection" column="plan_direction" />
<result property="planDirectionId" column="plan_direction_id" />
<result property="planDirectionTitle" column="plan_direction_title" />
<result property="planCategory" column="plan_category" />
<result property="projectForm" column="project_form" />
<result property="designFileUrl" column="design_file_url" />
@@ -12,38 +14,59 @@
<result property="isSettled" column="is_settled" />
<result property="projectNo" column="project_no" />
<result property="remark" column="remark" />
<result property="submitterId" column="submitter_id" />
<result property="submitterName" column="submitter_name" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectFields">
select plan_id, plan_name, plan_direction, plan_category, project_form, design_file_url, status, is_settled, project_no, remark, create_by, create_time, update_by, update_time
from biz_project_plan
select p.plan_id, p.plan_name, p.plan_direction, p.plan_direction_id,
s.title as plan_direction_title,
p.plan_category, p.project_form, p.design_file_url, p.status, p.is_settled,
p.project_no, p.remark, p.submitter_id,
COALESCE(bp.name, u.user_name) as submitter_name,
p.create_by, p.create_time, p.update_by, p.update_time
from biz_project_plan p
left join biz_special_plan s on s.id = p.plan_direction_id
left join sys_user u on u.user_id = p.submitter_id
left join biz_person bp on bp.user_id = u.user_id
</sql>
<select id="selectByPrimaryKey" resultMap="BizProjectPlanResult" parameterType="String">
<include refid="selectFields"/>
where plan_id = #{planId}
where p.plan_id = #{planId}
</select>
<select id="selectList" resultMap="BizProjectPlanResult" parameterType="BizProjectPlan">
<include refid="selectFields"/>
<where>
<if test="status != null and status != ''"> and status = #{status}</if>
<if test="remark != null and remark != ''"> and remark = #{remark}</if>
<if test="planDirectionId != null"> and p.plan_direction_id = #{planDirectionId}</if>
<if test="planCategory != null and planCategory != ''"> and p.plan_category = #{planCategory}</if>
<if test="submitterId != null"> and p.submitter_id = #{submitterId}</if>
<choose>
<!-- 选了具体状态: 等值匹配 -->
<when test="status != null and status != ''"> and p.status = #{status}</when>
<!-- 未选: 不加 status 过滤, 由前端按角色决定默认值 (经理侧默认查 1/2/3, 医生侧默认查全部含 0) -->
</choose>
<if test="remark != null and remark != ''"> and p.remark = #{remark}</if>
</where>
order by plan_id desc
order by p.plan_id desc
</select>
<insert id="insert" parameterType="BizProjectPlan">
insert into biz_project_plan
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="planId != null and planId != ''">plan_id,</if>
<if test="planDirectionId != null">plan_direction_id,</if>
<if test="status != null">status,</if>
<if test="remark != null">remark,</if>
<if test="submitterId != null">submitter_id,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="planId != null and planId != ''">#{planId},</if>
<if test="planDirectionId != null">#{planDirectionId},</if>
<if test="status != null">#{status},</if>
<if test="remark != null">#{remark},</if>
<if test="submitterId != null">#{submitterId},</if>
</trim>
</insert>
<update id="updateByPrimaryKey" parameterType="BizProjectPlan">
@@ -51,6 +74,7 @@
<trim prefix="SET" suffixOverrides=",">
<if test="planName != null and planName != ''">plan_name = #{planName},</if>
<if test="planDirection != null and planDirection != ''">plan_direction = #{planDirection},</if>
<if test="planDirectionId != null">plan_direction_id = #{planDirectionId},</if>
<if test="planCategory != null and planCategory != ''">plan_category = #{planCategory},</if>
<if test="projectForm != null and projectForm != ''">project_form = #{projectForm},</if>
<if test="designFileUrl != null and designFileUrl != ''">design_file_url = #{designFileUrl},</if>
@@ -61,6 +85,7 @@
<if test="auditTime != null and auditTime != ''">audit_time = #{auditTime},</if>
<if test="status != null">status = #{status},</if>
<if test="remark != null">remark = #{remark},</if>
<if test="submitterId != null">submitter_id = #{submitterId},</if>
</trim>
where plan_id = #{planId}
</update>
@@ -1,103 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.business.mapper.BizSubmissionMapper">
<resultMap type="BizSubmission" id="BizSubmissionResult">
<id property="subId" column="sub_id" />
<result property="title" column="title" />
<result property="direction" column="direction" />
<result property="projectForm" column="project_form" />
<result property="projectCategory" column="project_category" />
<result property="designFileUrl" column="design_file_url" />
<result property="submitterId" column="submitter_id" />
<result property="submitterName" column="submitter_name" />
<result property="status" column="status" />
<result property="remark" column="remark" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectFields">
select sub_id, title, direction, project_form, project_category, design_file_url, submitter_id, submitter_name, status, remark, create_by, create_time, update_by, update_time
from biz_submission
</sql>
<select id="selectByPrimaryKey" resultMap="BizSubmissionResult" parameterType="String">
<include refid="selectFields"/>
where sub_id = #{subId}
</select>
<select id="selectList" resultMap="BizSubmissionResult" parameterType="BizSubmission">
<include refid="selectFields"/>
<where>
<if test="submitterId != null and submitterId != ''"> and submitter_id = #{submitterId}</if>
<if test="title != null and title != ''"> and title = #{title}</if>
<if test="direction != null and direction != ''"> and direction = #{direction}</if>
<if test="status != null and status != ''"> and status = #{status}</if>
<if test="remark != null and remark != ''"> and remark = #{remark}</if>
</where>
order by sub_id desc
</select>
<insert id="insert" parameterType="BizSubmission">
insert into biz_submission
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="subId != null and subId != ''">sub_id,</if>
<if test="title != null">title,</if>
<if test="direction != null">direction,</if>
<if test="projectForm != null">project_form,</if>
<if test="projectCategory != null">project_category,</if>
<if test="designFileUrl != null">design_file_url,</if>
<if test="submitterId != null">submitter_id,</if>
<if test="submitterName != null">submitter_name,</if>
<if test="status != null">status,</if>
<if test="remark != null">remark,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
create_time,
<if test="updateBy != null and updateBy != ''">update_by,</if>
update_time,
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="subId != null and subId != ''">#{subId},</if>
<if test="title != null">#{title},</if>
<if test="direction != null">#{direction},</if>
<if test="projectForm != null">#{projectForm},</if>
<if test="projectCategory != null">#{projectCategory},</if>
<if test="designFileUrl != null">#{designFileUrl},</if>
<if test="submitterId != null">#{submitterId},</if>
<if test="submitterName != null">#{submitterName},</if>
<if test="status != null">#{status},</if>
<if test="remark != null">#{remark},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
sysdate(),
<if test="updateBy != null and updateBy != ''">#{updateBy},</if>
sysdate(),
</trim>
</insert>
<update id="updateByPrimaryKey" parameterType="BizSubmission">
update biz_submission
<trim prefix="SET" suffixOverrides=",">
<if test="submitterId != null and submitterId != ''">submitter_id = #{submitterId},</if>
<if test="submitterName != null and submitterName != ''">submitter_name = #{submitterName},</if>
<if test="projectForm != null and projectForm != ''">project_form = #{projectForm},</if>
<if test="projectCategory != null and projectCategory != ''">project_category = #{projectCategory},</if>
<if test="designFileUrl != null and designFileUrl != ''">design_file_url = #{designFileUrl},</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="title != null">title = #{title},</if>
<if test="direction != null">direction = #{direction},</if>
<if test="status != null">status = #{status},</if>
<if test="remark != null">remark = #{remark},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
update_time = sysdate(),
</trim>
where sub_id = #{subId}
</update>
<delete id="deleteByPrimaryKey" parameterType="String">
delete from biz_submission where sub_id = #{subId}
</delete>
<delete id="deleteByPrimaryKeys" parameterType="String">
delete from biz_submission where sub_id in
<foreach collection="subIds" item="subId" open="(" separator="," close=")">
#{subId}
</foreach>
</delete>
</mapper>
@@ -0,0 +1,32 @@
-- ============================================================
-- 迁移脚本: biz_submission → biz_project_plan
-- 时间: 2026-08-18
-- 说明:
-- 1. 医生侧 /doctor/submissions 原本走 biz_submission 表
-- (controller: BizSubmissionController)
-- 2. 整改后与经理侧 /manager/plans 共用 biz_project_plan 表
-- 3. 测试数据不迁 (用户确认价值不高)
-- 4. 测试/生产库请先备份再执行
-- ============================================================
-- ============== 段 1: biz_project_plan 加投稿人字段 ==============
ALTER TABLE biz_project_plan
ADD COLUMN submitter_id BIGINT NULL COMMENT '投稿人用户ID (医生侧投稿归属, 经理/admin 录入为 NULL)';
CREATE INDEX idx_plan_submitter ON biz_project_plan(submitter_id);
-- ============== 段 1.5: biz_person.user_id 加 UNIQUE,保证 LEFT JOIN 1:1 无笛卡尔积 ==============
-- 当前 dump 已确认 biz_person.user_id 无重复 (12 条数据,user_id 非空 2 条且 user_id=106/107 各一条)
ALTER TABLE biz_person
ADD UNIQUE KEY uk_person_user_id (user_id);
-- ============== 段 2: 数据迁移 (测试数据不迁,故 0 行) ==============
-- 旧 biz_submission.status 是英文 enum:
-- DRAFT → '0' 未提交
-- PENDING → '1' 待审核
-- APPROVED → '2' 通过
-- REJECTED → '3' 拒绝
-- (用户已确认测试数据不迁)
-- ============== 段 3: 删 biz_submission 表 ==============
DROP TABLE IF EXISTS biz_submission;