diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizAuthController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizAuthController.java index 1bd5579..7f22f6e 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizAuthController.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizAuthController.java @@ -211,6 +211,7 @@ public class BizAuthController extends BaseController { // 5. 插入 biz_org (executor 类型, 主账号自己当 contact) BizOrg org = new BizOrg(); org.setOrgId(null); + org.setUserId(userId); // 关联主账号, 让系统能反查 "我的公司" org.setOrgName(unitName); org.setOrgType("executor"); org.setBusinessNature(businessNature); @@ -224,7 +225,7 @@ public class BizAuthController extends BaseController { } /** - * 注册赞助方 (主账号), 流程与 executor 一致: + * 注册支持方 (主账号), 流程与 executor 一致: * 校验 → 查重 → 写 sys_user + role_type=sponsor → 写 biz_org (sponsor 类型) */ @PostMapping("/registerSponsor") @@ -283,6 +284,7 @@ public class BizAuthController extends BaseController { // 5. 写 biz_org (sponsor 类型) BizOrg org = new BizOrg(); org.setOrgId(null); + org.setUserId(userId); // 关联主账号, 让系统能反查 "我的公司" org.setOrgName(unitName); org.setOrgType("sponsor"); org.setBusinessNature(businessNature); diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizExecutionIntentController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizExecutionIntentController.java index ee72093..80e8800 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizExecutionIntentController.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizExecutionIntentController.java @@ -1,6 +1,8 @@ package com.ruoyi.business.controller; +import java.util.ArrayList; import java.util.List; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import com.ruoyi.common.annotation.Log; @@ -10,9 +12,11 @@ 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.system.mapper.SysUserMapper; import com.ruoyi.business.domain.BizExecutionIntent; import com.ruoyi.business.domain.BizProject; +import com.ruoyi.business.domain.vo.BizSignupExpertExportVo; import com.ruoyi.business.service.IBizExecutionIntentService; import com.ruoyi.business.service.IBizProjectService; @@ -119,4 +123,32 @@ public class BizExecutionIntentController extends BaseController { return toAjax(bizExecutionIntentService.deleteByPrimaryKeys(ids)); } + + /** + * 导出报名专家 (按 projectNo 过滤, 项目管理-更多-导出报名专家) + * POST /business/executionIntent/export?projectNo=xxx + * 字段: 专家姓名 科室 医院 职称 报名时间 手机号 + */ + @Log(title = "导出报名专家", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void exportSignupExperts(HttpServletResponse response, BizExecutionIntent bizExecutionIntent) + { + if (bizExecutionIntent.getProjectNo() == null || bizExecutionIntent.getProjectNo().isEmpty()) { + throw new IllegalArgumentException("projectNo 不能为空"); + } + List list = bizExecutionIntentService.selectList(bizExecutionIntent); + List exportList = new ArrayList<>(list.size()); + for (BizExecutionIntent e : list) { + BizSignupExpertExportVo v = new BizSignupExpertExportVo(); + v.setName(e.getName()); + v.setDepartment(e.getDepartment()); + v.setWorkUnit(e.getWorkUnit()); + v.setPosition(e.getPosition()); + v.setPhone(e.getPhone()); + v.setCreateTime(e.getCreateTime()); + exportList.add(v); + } + ExcelUtil util = new ExcelUtil<>(BizSignupExpertExportVo.class); + util.exportExcel(response, exportList, "报名专家"); + } } diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizOrgController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizOrgController.java index 048b029..89a8555 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizOrgController.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizOrgController.java @@ -1,6 +1,7 @@ package com.ruoyi.business.controller; import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import com.ruoyi.common.annotation.Log; @@ -12,7 +13,7 @@ import com.ruoyi.business.domain.BizOrg; import com.ruoyi.business.service.IBizOrgService; /** - * 公司Controller (赞助方 + 执行方 共用) + * 公司Controller (支持方 + 执行方 共用) * GET /business/org/list?orgType=sponsor|executor */ @RestController @@ -28,6 +29,34 @@ public class BizOrgController extends BaseController { return getDataTable(list); } + /** + * 支持方下拉选项: JOIN sys_user 取主账号 user_name, 用于 manager 项目分配弹窗 + * GET /business/org/sponsorOptions?orgName=xxx + * 返回 [{ userId, orgName, userName }, ...] (不走分页) + */ + @GetMapping("/sponsorOptions") + public AjaxResult sponsorOptions(BizOrg bizOrg) { + // 强制 orgType=sponsor + bizOrg.setOrgType("sponsor"); + List> rows = bizOrgService.selectSponsorOrgOptions(bizOrg); + return success(rows); + } + + /** + * 执行方下拉选项: JOIN sys_user MAIN 账号 (parent_user_id IS NULL), 用于 manager 项目分配弹窗 + * GET /business/org/executorOptions?orgName=xxx + * 返回 [{ userId, orgName, userName }, ...] (不走分页) + * 关键: label=orgName (执行单位名称), value=MAIN user_id (直接写 biz_project_assign.exec_user_id) + * 已通过 SQL 限定 parent_user_id IS NULL, 自动排除同一公司下的普通员工子账号 + */ + @GetMapping("/executorOptions") + public AjaxResult executorOptions(BizOrg bizOrg) { + // 强制 orgType=executor + bizOrg.setOrgType("executor"); + List> rows = bizOrgService.selectExecutorOrgOptions(bizOrg); + return success(rows); + } + @GetMapping("/{orgId}") public AjaxResult getInfo(@PathVariable("orgId") Long orgId) { return success(bizOrgService.getById(orgId)); diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizProjectController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizProjectController.java index 8dd0ea8..1037fb5 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizProjectController.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizProjectController.java @@ -20,6 +20,8 @@ import com.ruoyi.business.domain.BizProjectSponsorAssign; import com.ruoyi.business.service.IBizProjectAssignService; import com.ruoyi.business.service.IBizProjectRatingService; import com.ruoyi.business.service.IBizProjectSponsorAssignService; +import com.ruoyi.system.domain.vo.SysUserExtendVo; +import com.ruoyi.business.mapper.BizSysUserQueryMapper; /** * 项目Controller @@ -41,6 +43,8 @@ public class BizProjectController extends BaseController private IBizProjectRatingService bizProjectRatingService; @Autowired private IBizProjectSponsorAssignService bizProjectSponsorAssignService; + @Autowired + private BizSysUserQueryMapper bizSysUserQueryMapper; /** * 我报名的项目 (当前用户在 biz_execution_intent 里有意向的项目) @@ -162,10 +166,10 @@ public class BizProjectController extends BaseController } /** - * 赞助方分配监察员 (写 biz_project_sponsor_assign) + * 支持方分配监察员 (写 biz_project_sponsor_assign) * POST /business/project/sponsorAssign */ - @Log(title = "赞助方分配监察员", businessType = BusinessType.INSERT) + @Log(title = "支持方分配监察员", businessType = BusinessType.INSERT) @PostMapping("/sponsorAssign") public AjaxResult sponsorAssign(@RequestBody BizProjectSponsorAssign body) { @@ -176,11 +180,28 @@ public class BizProjectController extends BaseController } /** - * 赞助方批量分配监察员 (多个项目, 同一个监察员 + 同一份说明) + * 按 sys_user.role_type 查用户列表 (供前端下拉用, 不走 system:user:list 权限, 限定只查合规管理员等业务角色) + * GET /business/project/listByRole?roleType=manager&userName=xxx + * 不传 roleType 时返回空表, 防止误用全表扫描 + * 走业务模块专属 mapper BizSysUserQueryMapper, 避开 system 模块的 @DataScope 切面 + */ + @GetMapping("/listByRole") + public TableDataInfo listByRole(SysUserExtendVo vo) + { + if (vo.getRoleType() == null || vo.getRoleType().isEmpty()) { + return new TableDataInfo(); + } + startPage(); + List list = bizSysUserQueryMapper.selectActiveByRole(vo); + return getDataTable(list); + } + + /** + * 支持方批量分配监察员 (多个项目, 同一个监察员 + 同一份说明) * POST /business/project/sponsorAssignBatch * body: List (每个 item.projectId / monitorUserId / assignDesc / assignPoints) */ - @Log(title = "赞助方批量分配监察员", businessType = BusinessType.INSERT) + @Log(title = "支持方批量分配监察员", businessType = BusinessType.INSERT) @PostMapping("/sponsorAssignBatch") public AjaxResult sponsorAssignBatch(@RequestBody List bodies) { diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizOrg.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizOrg.java index c63e6ad..f7b29aa 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizOrg.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizOrg.java @@ -7,17 +7,20 @@ import com.ruoyi.common.core.domain.BaseEntity; /** * 公司对象 biz_org - * 用途: 赞助方(sponsor) + 执行方(executor) 共用 + * 用途: 支持方(sponsor) + 执行方(executor) 共用 * 重构说明: 原 biz_support_unit + biz_execution_unit 合并, 通过 org_type 区分 */ public class BizOrg extends BaseEntity { private static final long serialVersionUID = 1L; /** org_id */ private Long orgId; + /** 主账号 sys_user.user_id (注册时自动关联, 一用户一类型一公司) */ + @Excel(name = "user_id") + private Long userId; /** org_name */ @Excel(name = "org_name") private String orgName; - /** org_type: sponsor赞助方 / executor执行方 */ + /** org_type: sponsor支持方 / executor执行方 */ @Excel(name = "org_type") private String orgType; /** 企业性质 私营/国营/中外合资/外资/其他 */ @@ -35,7 +38,7 @@ public class BizOrg extends BaseEntity { /** contact_phone */ @Excel(name = "contact_phone") private String contactPhone; - /** intent_count (仅赞助方用) */ + /** intent_count (仅支持方用) */ @Excel(name = "intent_count") private Integer intentCount; /** status */ @@ -50,6 +53,8 @@ public class BizOrg extends BaseEntity { public Long getOrgId() { return orgId; } public void setOrgId(Long orgId) { this.orgId = orgId; } + public Long getUserId() { return userId; } + public void setUserId(Long userId) { this.userId = userId; } public String getOrgName() { return orgName; } public void setOrgName(String orgName) { this.orgName = orgName; } public String getOrgType() { return orgType; } diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizPerson.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizPerson.java index ae0b347..6e4fad1 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizPerson.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizPerson.java @@ -32,9 +32,6 @@ public class BizPerson extends BaseEntity { /** role */ @Excel(name = "role") private String role; - /** 状态 0正常 1禁用 - 跟 sys_user.status 同步, 前端展示请读 sys_user */ - @Deprecated - private String status; /** create_by */ @Excel(name = "create_by") private String createBy; @@ -51,6 +48,9 @@ public class BizPerson extends BaseEntity { private Date updateTime; /** 关联系统用户ID */ private Long userId; + /** 启停状态 '0'/'1' (前端 toggle 用, BizPersonServiceImpl 同步到 sys_user.status) - 非持久化字段 */ + @com.fasterxml.jackson.annotation.JsonProperty("status") + private transient String status; /** 所属单位类型 execution执行/sponsor支持 */ private String unitType; /** 账号类型 (来自 sys_user.account_type, MAIN=主账号 / SUB=子账号) - 仅展示用,不入库 */ @@ -81,8 +81,6 @@ public class BizPerson extends BaseEntity { public void setPosition(String position) { this.position = position; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } - public String getStatus() { return status; } - public void setStatus(String status) { this.status = status; } /** 兼容前端调用, 实际读 sys_user.delFlag */ public String getDelFlag() { return null; } public void setDelFlag(String delFlag) { /* noop - 跟 sys_user 同步 */ } @@ -96,6 +94,8 @@ public class BizPerson extends BaseEntity { public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId = userId; } + public String getStatus() { return status; } + public void setStatus(String status) { this.status = status; } public String getUnitType() { return unitType; } public void setUnitType(String unitType) { this.unitType = unitType; } public String getAccountType() { return accountType; } diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProject.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProject.java index 7f00f4d..7dd247d 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProject.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProject.java @@ -49,11 +49,15 @@ public class BizProject extends BaseEntity { private BigDecimal ratingQ3; /** 评分维度: 合规安全 */ private BigDecimal ratingQ4; - /** 赞助方负责人用户名(冗余) — 原 org_name */ + /** 支持方负责人用户名(冗余) — 原 org_name */ @Excel(name = "sponsor_admin_user_name") private String sponsorAdminUserName; + /** 支持单位名称 (查询参数 + 列表展示列, JOIN biz_org 取 org_name, org_type='sponsor') */ + private String sponsorOrgName; /** 服务机构名称 (查询条件, 仅匹配 org_type='executor' + org_name LIKE) */ private String execOrgName; + /** 服务机构名称列表, 多个用英文逗号连接 (GROUP_CONCAT 派生, 不入库, 仅展示) */ + private String execOrgNames; /** project_form */ @Excel(name = "project_form") private String projectForm; @@ -63,9 +67,17 @@ public class BizProject extends BaseEntity { /** is_settled */ @Excel(name = "is_settled") private String isSettled; - /** 赞助方负责人用户ID (sys_user.user_id, role_type=sponsor) — 原 org_id */ + /** 支持方负责人用户ID (sys_user.user_id, role_type=sponsor) — 原 org_id */ @Excel(name = "sponsor_admin_user_id") private Long sponsorAdminUserId; + /** 项目负责人 user_id (sys_user.user_id, role_type=manager 合规管理员) */ + @Excel(name = "lead_user_id") + private Long leadUserId; + /** 项目负责人用户名 (JOIN sys_user.user_name 派生, 不入库) */ + private String leadUserName; + /** 是否招标项目 Y/N */ + @Excel(name = "is_bid_project") + private String isBidProject; /** create_by */ @Excel(name = "create_by") private String createBy; @@ -110,7 +122,7 @@ public class BizProject extends BaseEntity { /** 公告类型 (邀请函/支持函/通知/日程/公示) */ private String announcementType; - /* ============ 赞助方评分字段 (来自 biz_project_sponsor 中间表, 仅展示用) ============ */ + /* ============ 支持方评分字段 (来自 biz_project_sponsor 中间表, 仅展示用) ============ */ /** 当前 login 用户对该项目的平均分 */ private BigDecimal sponsorRating; private Integer sponsorQ1; @@ -150,8 +162,12 @@ public class BizProject extends BaseEntity { public void setRatingQ4(BigDecimal ratingQ4) { this.ratingQ4 = ratingQ4; } public String getSponsorAdminUserName() { return sponsorAdminUserName; } public void setSponsorAdminUserName(String sponsorAdminUserName) { this.sponsorAdminUserName = sponsorAdminUserName; } + public String getSponsorOrgName() { return sponsorOrgName; } + public void setSponsorOrgName(String sponsorOrgName) { this.sponsorOrgName = sponsorOrgName; } public String getExecOrgName() { return execOrgName; } public void setExecOrgName(String execOrgName) { this.execOrgName = execOrgName; } + public String getExecOrgNames() { return execOrgNames; } + public void setExecOrgNames(String execOrgNames) { this.execOrgNames = execOrgNames; } public String getProjectForm() { return projectForm; } public void setProjectForm(String projectForm) { this.projectForm = projectForm; } public String getIsFinished() { return isFinished; } @@ -160,6 +176,12 @@ public class BizProject extends BaseEntity { public void setIsSettled(String isSettled) { this.isSettled = isSettled; } public Long getSponsorAdminUserId() { return sponsorAdminUserId; } public void setSponsorAdminUserId(Long sponsorAdminUserId) { this.sponsorAdminUserId = sponsorAdminUserId; } + public Long getLeadUserId() { return leadUserId; } + public void setLeadUserId(Long leadUserId) { this.leadUserId = leadUserId; } + public String getLeadUserName() { return leadUserName; } + public void setLeadUserName(String leadUserName) { this.leadUserName = leadUserName; } + public String getIsBidProject() { return isBidProject; } + public void setIsBidProject(String isBidProject) { this.isBidProject = isBidProject; } public String getCreateBy() { return createBy; } public void setCreateBy(String createBy) { this.createBy = createBy; } public Date getCreateTime() { return createTime; } diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectAssign.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectAssign.java index b5c496f..70f7bcf 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectAssign.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectAssign.java @@ -3,27 +3,25 @@ package com.ruoyi.business.domain; import java.math.BigDecimal; import com.ruoyi.common.core.domain.BaseEntity; -/** 项目执行方分配对象 BizProjectAssign */ +/** 项目执行方分配对象 BizProjectAssign + * 注: 不再缓存 execution_unit_name / exec_user_name / exec_nick_name / exec_org, + * 这 4 个字段都是 JOIN 一查就有的快照, 已从 DB DROP。 + * 业务展示统一走 service 层 JOIN biz_org + sys_user。 + */ public class BizProjectAssign extends BaseEntity { private static final long serialVersionUID = 1L; /** assign_id */ private String assignId; /** project_id */ private Long projectId; - /** 执行方用户ID (sys_user.user_id) */ + /** 执行单位ID (FK: biz_org.org_id, NOT NULL) - service 层从 execUserId 反查 biz_org 写入 */ + private Long executionUnitId; + /** 执行方用户ID (sys_user.user_id, executor 主账号) - 业务主键,前端直接传 */ private Long execUserId; - /** 执行方用户名 (denormalized) */ - private String execUserName; - /** 执行方昵称 (denormalized) */ - private String execNickName; - /** 执行方所属机构 (denormalized) */ - private String execOrg; /** 分配场次 */ private Integer sessions; /** 分配金额 */ private BigDecimal amount; - /** 备注 */ - private String remark; /** 状态 0正常 1已撤销 */ private String status; @@ -31,20 +29,14 @@ public class BizProjectAssign extends BaseEntity { public void setAssignId(String assignId) { this.assignId = assignId; } public Long getProjectId() { return projectId; } public void setProjectId(Long projectId) { this.projectId = projectId; } + public Long getExecutionUnitId() { return executionUnitId; } + public void setExecutionUnitId(Long executionUnitId) { this.executionUnitId = executionUnitId; } public Long getExecUserId() { return execUserId; } public void setExecUserId(Long execUserId) { this.execUserId = execUserId; } - public String getExecUserName() { return execUserName; } - public void setExecUserName(String execUserName) { this.execUserName = execUserName; } - public String getExecNickName() { return execNickName; } - public void setExecNickName(String execNickName) { this.execNickName = execNickName; } - public String getExecOrg() { return execOrg; } - public void setExecOrg(String execOrg) { this.execOrg = execOrg; } public Integer getSessions() { return sessions; } public void setSessions(Integer sessions) { this.sessions = sessions; } public BigDecimal getAmount() { return amount; } public void setAmount(BigDecimal amount) { this.amount = amount; } - public String getRemark() { return remark; } - public void setRemark(String remark) { this.remark = remark; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } -} +} \ No newline at end of file diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectSponsorAssign.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectSponsorAssign.java index 6e6863d..c79c978 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectSponsorAssign.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectSponsorAssign.java @@ -4,7 +4,7 @@ import java.util.Date; import com.fasterxml.jackson.annotation.JsonFormat; import com.ruoyi.common.core.domain.BaseEntity; -/** 项目-赞助方-监察员分配记录 (biz_project_sponsor_assign) */ +/** 项目-支持方-监察员分配记录 (biz_project_sponsor_assign) */ public class BizProjectSponsorAssign extends BaseEntity { private static final long serialVersionUID = 1L; private Long id; diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/vo/BizSignupExpertExportVo.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/vo/BizSignupExpertExportVo.java new file mode 100644 index 0000000..ec21053 --- /dev/null +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/vo/BizSignupExpertExportVo.java @@ -0,0 +1,48 @@ +package com.ruoyi.business.domain.vo; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.ruoyi.common.annotation.Excel; + +/** + * 报名专家导出 VO (中文列头) + * + *

数据源: biz_execution_intent (公开门户"立即报名"写入的执行意向表, 即已报名专家). + * 仅用于 Excel 导出, 不参与业务逻辑. + * + * @author guoju + */ +public class BizSignupExpertExportVo { + + @Excel(name = "专家姓名", sort = 1) + private String name; + + @Excel(name = "科室", sort = 2) + private String department; + + @Excel(name = "医院", sort = 3) + private String workUnit; + + @Excel(name = "职称", sort = 4) + private String position; + + @Excel(name = "报名时间", sort = 5, dateFormat = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Excel(name = "手机号", sort = 6) + private String phone; + + public String getName() { return name; } + public void setName(String name) { this.name = name; } + public String getDepartment() { return department; } + public void setDepartment(String department) { this.department = department; } + public String getWorkUnit() { return workUnit; } + public void setWorkUnit(String workUnit) { this.workUnit = workUnit; } + public String getPosition() { return position; } + public void setPosition(String position) { this.position = position; } + public Date getCreateTime() { return createTime; } + public void setCreateTime(Date createTime) { this.createTime = createTime; } + public String getPhone() { return phone; } + public void setPhone(String phone) { this.phone = phone; } +} \ No newline at end of file diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizOrgMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizOrgMapper.java index 3b90ce6..2ba3691 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizOrgMapper.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizOrgMapper.java @@ -1,6 +1,7 @@ package com.ruoyi.business.mapper; import java.util.List; +import java.util.Map; import com.ruoyi.business.domain.BizOrg; public interface BizOrgMapper { @@ -9,4 +10,12 @@ public interface BizOrgMapper { int insert(BizOrg entity); int updateByPrimaryKey(BizOrg entity); int deleteByPrimaryKeys(Long[] orgIds); + /** 支持方下拉选项 (JOIN sys_user.user_name), 用于 manager 项目分配弹窗 */ + List> selectSponsorOrgOptions(BizOrg entity); + /** 执行方下拉选项 (JOIN sys_user MAIN 账号 user_name), 用于 manager 项目分配弹窗 + * 返回 Map: userId / orgName / userName + * 过滤条件: orgType='executor' + sys_user MAIN 账号 (parent_user_id IS NULL) + * 注意: value 必须 MAIN user_id (写入 biz_project_assign.exec_user_id); + * label 必须 org_name, 不用 user_name 以避免把同公司的普通员工带出来 */ + List> selectExecutorOrgOptions(BizOrg entity); } diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectSponsorAssignMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectSponsorAssignMapper.java index f14a075..4b97f60 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectSponsorAssignMapper.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectSponsorAssignMapper.java @@ -6,6 +6,6 @@ import com.ruoyi.business.domain.BizProjectSponsorAssign; public interface BizProjectSponsorAssignMapper { int insertAssign(BizProjectSponsorAssign entity); List selectByProjectId(String projectId); - /** 按 project_id 全删 (赞助方分配: 先删后插策略) */ + /** 按 project_id 全删 (支持方分配: 先删后插策略) */ int deleteByProjectId(String projectId); } \ No newline at end of file diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizSysUserQueryMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizSysUserQueryMapper.java new file mode 100644 index 0000000..e60f34b --- /dev/null +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizSysUserQueryMapper.java @@ -0,0 +1,22 @@ +package com.ruoyi.business.mapper; + +import java.util.List; +import org.apache.ibatis.annotations.Mapper; +import com.ruoyi.system.domain.vo.SysUserExtendVo; + +/** + * 业务模块自用的 sys_user 查询 (不走 system 模块的 mapper, + * 避开 SysUserService.selectUserExtendList 上的 @DataScope 切面, + * 因此不能直接复用 /system/user/list 的权限模型) + * + * 用途: 前端下拉按 role_type 选人 (项目负责人 / 执行方 等) + */ +@Mapper +public interface BizSysUserQueryMapper +{ + /** + * 按 role_type + 可选 userName 模糊查 sys_user (status='0' 正常, del_flag='0' 未删除) + * 无 dataScope 注入, 所有合规业务角色都可查 + */ + List selectActiveByRole(SysUserExtendVo vo); +} \ No newline at end of file diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizOrgService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizOrgService.java index 7bcbb9b..c60773e 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizOrgService.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizOrgService.java @@ -1,6 +1,7 @@ package com.ruoyi.business.service; import java.util.List; +import java.util.Map; import com.ruoyi.business.domain.BizOrg; public interface IBizOrgService { @@ -9,4 +10,9 @@ public interface IBizOrgService { int insert(BizOrg entity); int updateByPrimaryKey(BizOrg entity); int deleteByPrimaryKeys(Long[] orgIds); + /** 支持方下拉选项 (userId/orgName/userName), 用于 manager 项目分配弹窗 */ + List> selectSponsorOrgOptions(BizOrg entity); + /** 执行方下拉选项 (userId/orgName/userName), 用于 manager 项目分配弹窗 + * 只返回 biz_org.org_type='executor' 对应的 MAIN 账号 (parent_user_id IS NULL) */ + List> selectExecutorOrgOptions(BizOrg entity); } diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectSponsorAssignService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectSponsorAssignService.java index 6a6313c..4323e0d 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectSponsorAssignService.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectSponsorAssignService.java @@ -4,7 +4,7 @@ import java.util.List; import com.ruoyi.business.domain.BizProjectSponsorAssign; public interface IBizProjectSponsorAssignService { - /** 赞助方分配 (策略: 按 project_id 先删后插, 一个项目只分配一个 sponsor) */ + /** 支持方分配 (策略: 按 project_id 先删后插, 一个项目只分配一个 sponsor) */ int insertAssign(BizProjectSponsorAssign entity); List listByProjectId(String projectId); int deleteByProjectId(String projectId); diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizOrgServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizOrgServiceImpl.java index 59fcb09..03b6651 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizOrgServiceImpl.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizOrgServiceImpl.java @@ -1,6 +1,7 @@ package com.ruoyi.business.service.impl; import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.business.domain.BizOrg; @@ -34,4 +35,14 @@ public class BizOrgServiceImpl implements IBizOrgService { for (Long id : orgIds) { rows += bizOrgMapper.deleteByPrimaryKeys(new Long[]{id}); } return rows; } + + @Override + public List> selectSponsorOrgOptions(BizOrg entity) { + return bizOrgMapper.selectSponsorOrgOptions(entity); + } + + @Override + public List> selectExecutorOrgOptions(BizOrg entity) { + return bizOrgMapper.selectExecutorOrgOptions(entity); + } } diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizPersonServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizPersonServiceImpl.java index e3ac99e..7711024 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizPersonServiceImpl.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizPersonServiceImpl.java @@ -47,20 +47,25 @@ public class BizPersonServiceImpl implements IBizPersonService throw new ServiceException("登录账号已存在"); } - // 0.5 兜底: 如果前端没传 orgId, 按 (orgName + unitType) 查 biz_org 回填 - // (前端从 org 页面跳来时已带 orgId; 直接访问 new 页面没带 orgId 时走这条路径) - if (entity.getOrgId() == null && entity.getOrgName() != null && !entity.getOrgName().isEmpty() + // 0.5 主账号 → 自己公司的 biz_org 反查 (按 user_id + org_type, 一用户一类型一公司) + // 解决: 注册时建了公司但前端拿不到, 子账号瞎填 orgName 报错的问题 + if (entity.getOrgId() == null && mainUserId != null && entity.getUnitType() != null && !entity.getUnitType().isEmpty()) { BizOrg q = new BizOrg(); - q.setOrgName(entity.getOrgName().trim()); + q.setUserId(mainUserId); q.setOrgType(entity.getUnitType()); List matched = bizOrgMapper.selectList(q); if (matched != null && !matched.isEmpty()) { - entity.setOrgId(matched.get(0).getOrgId()); + BizOrg mine = matched.get(0); + entity.setOrgId(mine.getOrgId()); + // 兜底同步 orgName, 避免 biz_person.org_name 为空 + if (entity.getOrgName() == null || entity.getOrgName().isEmpty()) { + entity.setOrgName(mine.getOrgName()); + } } } if (entity.getOrgId() == null) { - throw new ServiceException("请填写所属公司 (需先在 [支持单位管理/服务机构管理] 录入 orgType=" + entity.getUnitType() + " 的公司)"); + throw new ServiceException("请填写所属公司 (主账号尚未注册公司, 请联系 admin 在 [支持单位管理/服务机构管理] 录入 orgType=" + entity.getUnitType() + " 的公司并关联 user_id)"); } // 1. 创建 sys_user 子账号 diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectAssignServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectAssignServiceImpl.java index b130174..68a62d1 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectAssignServiceImpl.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectAssignServiceImpl.java @@ -1,17 +1,25 @@ package com.ruoyi.business.service.impl; +import java.util.Date; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import com.ruoyi.business.domain.BizOrg; import com.ruoyi.business.domain.BizProjectAssign; +import com.ruoyi.business.mapper.BizOrgMapper; import com.ruoyi.business.mapper.BizProjectAssignMapper; import com.ruoyi.business.service.IBizProjectAssignService; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.id.SnowflakeId; @Service public class BizProjectAssignServiceImpl implements IBizProjectAssignService { @Autowired private BizProjectAssignMapper bizProjectAssignMapper; + @Autowired + private BizOrgMapper bizOrgMapper; @Override public BizProjectAssign getById(String assignId) { return bizProjectAssignMapper.selectByPrimaryKey(assignId); } @@ -22,19 +30,58 @@ public class BizProjectAssignServiceImpl implements IBizProjectAssignService @Override public List selectList(BizProjectAssign entity) { return bizProjectAssignMapper.selectList(entity); } + /** + * 插入项目执行方分配: + * 1. execUserId → biz_org(org_type='executor') 反查 org_id 写入 executionUnitId (NOT NULL, 找不到 throw) + * 2. 自动补 audit 字段 (createBy/createTime/updateBy/updateTime) 从 SecurityUtils + * 3. SnowflakeId 主键 + * 4. status='0' 默认 + */ @Override public int insert(BizProjectAssign entity) { - com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "assignId"); - if (entity.getStatus() == null) entity.setStatus("0"); + // 0. 必须有 execUserId (前端必传) + if (entity.getExecUserId() == null) { + throw new ServiceException("执行方用户ID不能为空"); + } + + // 1. execUserId → biz_org(executor) → executionUnitId + BizOrg q = new BizOrg(); + q.setUserId(entity.getExecUserId()); + q.setOrgType("executor"); + List matched = bizOrgMapper.selectList(q); + if (matched == null || matched.isEmpty()) { + throw new ServiceException("执行方用户 " + entity.getExecUserId() + " 未关联执行单位 (请检查 biz_org.org_type='executor' + user_id 是否绑定)"); + } + BizOrg org = matched.get(0); + entity.setExecutionUnitId(org.getOrgId()); + + // 2. audit 字段 + Date now = new Date(); + String operator = SecurityUtils.getUsername(); + if (entity.getCreateBy() == null || entity.getCreateBy().isEmpty()) entity.setCreateBy(operator); + if (entity.getCreateTime() == null) entity.setCreateTime(now); + entity.setUpdateBy(operator); + entity.setUpdateTime(now); + + // 3. 默认值 + if (entity.getStatus() == null || entity.getStatus().isEmpty()) entity.setStatus("0"); + + // 4. SnowflakeId + SnowflakeId.injectIfEmpty(entity, "assignId"); + return bizProjectAssignMapper.insert(entity); } @Override - public int updateByPrimaryKey(BizProjectAssign entity) { return bizProjectAssignMapper.updateByPrimaryKey(entity); } + public int updateByPrimaryKey(BizProjectAssign entity) { + entity.setUpdateBy(SecurityUtils.getUsername()); + entity.setUpdateTime(new Date()); + return bizProjectAssignMapper.updateByPrimaryKey(entity); + } @Override public int deleteByPrimaryKey(String assignId) { return bizProjectAssignMapper.deleteByPrimaryKey(assignId); } @Override public int deleteByProjectId(Long projectId) { return bizProjectAssignMapper.deleteByProjectId(projectId); } -} +} \ No newline at end of file diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectSponsorAssignServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectSponsorAssignServiceImpl.java index 3985e11..c47456f 100644 --- a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectSponsorAssignServiceImpl.java +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectSponsorAssignServiceImpl.java @@ -14,7 +14,7 @@ public class BizProjectSponsorAssignServiceImpl implements IBizProjectSponsorAss @Override public int insertAssign(BizProjectSponsorAssign entity) { - // 赞助方分配策略: 一个项目只分配一个 sponsor, 先按 project_id 删, 再插 + // 支持方分配策略: 一个项目只分配一个 sponsor, 先按 project_id 删, 再插 mapper.deleteByProjectId(entity.getProjectId()); return mapper.insertAssign(entity); } diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizOrgMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizOrgMapper.xml index c7487fb..1ad8a84 100644 --- a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizOrgMapper.xml +++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizOrgMapper.xml @@ -3,6 +3,7 @@ + @@ -19,7 +20,7 @@ - select org_id, org_name, org_type, business_nature, address, tax_no, status, create_time, + select org_id, user_id, org_name, org_type, business_nature, address, tax_no, status, create_time, contact_name, contact_phone, intent_count, create_by, update_by, update_time from biz_org @@ -33,6 +34,7 @@ + select o.user_id as userId, + o.org_name as orgName, + u.user_name as userName + from biz_org o + join sys_user u on u.user_id = o.user_id + where o.org_type = 'sponsor' + and u.del_flag = '0' + and o.user_id = #{userId} + and o.org_name like concat('%', #{orgName}, '%') + order by o.org_id desc + + + + diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizPersonMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizPersonMapper.xml index be6f752..7d861b6 100644 --- a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizPersonMapper.xml +++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizPersonMapper.xml @@ -11,7 +11,6 @@ - diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectAssignMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectAssignMapper.xml index 2169a51..e68afd0 100644 --- a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectAssignMapper.xml +++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectAssignMapper.xml @@ -2,25 +2,24 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + - select assign_id, project_id, exec_user_id, exec_user_name, exec_nick_name, exec_org, - sessions, amount, remark, status, create_by, create_time, update_by, update_time + select assign_id, project_id, execution_unit_id, exec_user_id, + sessions, amount, remark, status, + create_by, create_time, update_by, update_time from biz_project_assign @@ -39,57 +38,60 @@ and project_id = #{projectId} + and execution_unit_id = #{executionUnitId} and exec_user_id = #{execUserId} and status = #{status} order by assign_id desc + insert into biz_project_assign - assign_id, + assign_id, project_id, + execution_unit_id, exec_user_id, - exec_user_name, - exec_nick_name, - exec_org, sessions, amount, remark, status, create_by, - create_time, + create_time, + update_by, + update_time, - #{assignId}, + #{assignId}, #{projectId}, + #{executionUnitId}, #{execUserId}, - #{execUserName}, - #{execNickName}, - #{execOrg}, #{sessions}, #{amount}, #{remark}, #{status}, #{createBy}, - sysdate(), + #{createTime}, + #{updateBy}, + #{updateTime}, update biz_project_assign + execution_unit_id = #{executionUnitId}, exec_user_id = #{execUserId}, - exec_user_name = #{execUserName}, - exec_nick_name = #{execNickName}, - exec_org = #{execOrg}, sessions = #{sessions}, amount = #{amount}, - remark = #{remark}, + remark = #{remark}, status = #{status}, update_by = #{updateBy}, - update_time = sysdate(), + update_time = #{updateTime}, where assign_id = #{assignId} @@ -101,4 +103,4 @@ delete from biz_project_assign where project_id = #{projectId} - + \ No newline at end of file diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectMapper.xml index 91286a1..ac448b1 100644 --- a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectMapper.xml +++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectMapper.xml @@ -13,16 +13,16 @@ - - - - + + + + + - @@ -36,35 +36,39 @@ - - - - - - select project_id, project_no, project_name, total_sessions, done_sessions, todo_sessions, total_amount, available_amount, paid_labor_amount, paid_meeting_amount, rating_score, rating_q1, rating_q2, rating_q3, rating_q4, sponsor_admin_user_name, project_form, is_finished, is_settled, sponsor_admin_user_id, create_by, create_time, update_by, update_time, manage_fee, start_time, end_time, submit_deadline_days, support_contract_url, execute_contract_url, invitation_url, support_letter_url, publish_url, notice_url, schedule_url, is_published, publish_time, announcement_type - from biz_project + select p.project_id, p.project_no, p.project_name, p.total_sessions, p.done_sessions, p.todo_sessions, p.total_amount, p.available_amount, p.paid_labor_amount, p.paid_meeting_amount, p.rating_score, p.sponsor_admin_user_name, p.project_form, p.is_finished, p.is_settled, p.sponsor_admin_user_id, p.lead_user_id, p.is_bid_project, p.create_by, p.create_time, p.update_by, p.update_time, p.manage_fee, p.start_time, p.end_time, p.submit_deadline_days, p.support_contract_url, p.execute_contract_url, p.invitation_url, p.support_letter_url, p.publish_url, + o.org_name as sponsor_org_name, + lu.user_name as lead_user_name, + (select group_concat(distinct o2.org_name separator ',') + from biz_project_assign bpa + join biz_org o2 on o2.org_id = bpa.execution_unit_id and o2.org_type = 'executor' + where bpa.project_id = p.project_id) as exec_org_names + from biz_project p + left join biz_org o on o.user_id = p.sponsor_admin_user_id and o.org_type = 'sponsor' + left join sys_user lu on lu.user_id = p.lead_user_id - + select p.project_id, p.project_no, p.project_name, p.total_sessions, p.done_sessions, p.todo_sessions, p.total_amount, p.available_amount, p.paid_labor_amount, p.paid_meeting_amount, - p.sponsor_admin_user_name, p.project_form, p.is_finished, p.is_settled, - p.sponsor_admin_user_id, + p.rating_score, p.sponsor_admin_user_name, p.project_form, p.is_finished, p.is_settled, + p.sponsor_admin_user_id, p.lead_user_id, p.is_bid_project, p.create_by, p.create_time, p.update_by, p.update_time, p.manage_fee, p.start_time, p.end_time, p.submit_deadline_days, p.support_contract_url, p.execute_contract_url, p.invitation_url, p.support_letter_url, - p.publish_url, p.notice_url, p.schedule_url, p.is_published, p.publish_time, p.announcement_type, - bps.sponsor_rating as sponsor_rating, - bps.sponsor_q1 as sponsor_q1, - bps.sponsor_q2 as sponsor_q2, - bps.sponsor_q3 as sponsor_q3, - bps.sponsor_q4 as sponsor_q4, - bps.sponsor_remark as sponsor_remark + p.publish_url, + o.org_name as sponsor_org_name, + lu.user_name as lead_user_name, + (select group_concat(distinct o2.org_name separator ',') + from biz_project_assign bpa + join biz_org o2 on o2.org_id = bpa.execution_unit_id and o2.org_type = 'executor' + where bpa.project_id = p.project_id) as exec_org_names from biz_project p - left join biz_project_sponsor bps on bps.project_id = p.project_id and bps.user_id = #{params.loginUid} + left join biz_org o on o.user_id = p.sponsor_admin_user_id and o.org_type = 'sponsor' + left join sys_user lu on lu.user_id = p.lead_user_id @@ -147,15 +150,13 @@ paid_labor_amount, paid_meeting_amount, rating_score, - rating_q1, - rating_q2, - rating_q3, - rating_q4, sponsor_admin_user_name, project_form, is_finished, is_settled, sponsor_admin_user_id, + lead_user_id, + is_bid_project, create_by, create_time, update_by, @@ -169,11 +170,6 @@ invitation_url, support_letter_url, publish_url, - notice_url, - schedule_url, - is_published, - publish_time, - announcement_type, #{projectId}, @@ -187,15 +183,13 @@ #{paidLaborAmount}, #{paidMeetingAmount}, #{ratingScore}, - #{ratingQ1}, - #{ratingQ2}, - #{ratingQ3}, - #{ratingQ4}, #{sponsorAdminUserName}, #{projectForm}, #{isFinished}, #{isSettled}, #{sponsorAdminUserId}, + #{leadUserId}, + #{isBidProject}, #{createBy}, #{createTime}, #{updateBy}, @@ -209,11 +203,6 @@ #{invitationUrl}, #{supportLetterUrl}, #{publishUrl}, - #{noticeUrl}, - #{scheduleUrl}, - #{isPublished}, - #{publishTime}, - #{announcementType}, @@ -228,11 +217,6 @@ invitation_url = #{invitationUrl}, support_letter_url = #{supportLetterUrl}, publish_url = #{publishUrl}, - notice_url = #{noticeUrl}, - schedule_url = #{scheduleUrl}, - is_published = #{isPublished}, - publish_time = #{publishTime}, - announcement_type = #{announcementType}, project_no = #{projectNo}, project_name = #{projectName}, total_sessions = #{totalSessions}, @@ -243,15 +227,13 @@ paid_labor_amount = #{paidLaborAmount}, paid_meeting_amount = #{paidMeetingAmount}, rating_score = #{ratingScore}, - rating_q1 = #{ratingQ1}, - rating_q2 = #{ratingQ2}, - rating_q3 = #{ratingQ3}, - rating_q4 = #{ratingQ4}, sponsor_admin_user_name = #{sponsorAdminUserName}, project_form = #{projectForm}, is_finished = #{isFinished}, is_settled = #{isSettled}, sponsor_admin_user_id = #{sponsorAdminUserId}, + lead_user_id = #{leadUserId}, + is_bid_project = #{isBidProject}, create_by = #{createBy}, create_time = #{createTime}, update_by = #{updateBy}, diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectSponsorAssignMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectSponsorAssignMapper.xml index 7f37a31..73ee784 100644 --- a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectSponsorAssignMapper.xml +++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectSponsorAssignMapper.xml @@ -22,7 +22,7 @@ (#{projectId}, #{sponsorUserId}, #{monitorUserId}, #{assignDesc}, #{assignPoints}, #{createBy}, sysdate()) - + delete from biz_project_sponsor_assign where project_id = #{projectId} diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizSysUserQueryMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizSysUserQueryMapper.xml new file mode 100644 index 0000000..b186566 --- /dev/null +++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizSysUserQueryMapper.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ry-vue3/src/api/business/project.js b/ry-vue3/src/api/business/project.js index 7e2277a..5aa323b 100644 --- a/ry-vue3/src/api/business/project.js +++ b/ry-vue3/src/api/business/project.js @@ -24,7 +24,7 @@ export function sponsorAssignProject(data) { } /** - * 赞助方批量分配 (多个项目同一个监察员 + 同一份说明) + * 支持方批量分配 (多个项目同一个监察员 + 同一份说明) * body: [{projectId, monitorUserId, assignDesc, assignPoints}, ...] */ export function sponsorAssignBatch(data) { diff --git a/ry-vue3/src/api/system.js b/ry-vue3/src/api/system.js index c8c9a37..c645c7e 100644 --- a/ry-vue3/src/api/system.js +++ b/ry-vue3/src/api/system.js @@ -11,12 +11,28 @@ export function listRole(query) { return request({ url: '/system/role/list', method: 'get', params: query }) } -// 按角色查询用户列表 (绕开 sys_user:list 权限) -// 用法: listByRole({ roleType: 'executor', userName: 'exe' }) +// 按 sys_user.role_type 查用户列表 (走 /business/project/listByRole, 不走 system:user:list 权限) +// 用法: listByRole({ roleType: 'manager', userName: 'm' }) export function listByRole(query) { - return request({ url: '/business/executor/list', method: 'get', params: query }) + return request({ url: '/business/project/listByRole', method: 'get', params: query }) } -// 兼容旧名 +// 兼容旧名 (项目分配弹窗已不再使用, 保留避免破坏其它 import) export const listExecutor = (query) => listByRole({ roleType: 'executor', ...query }) export const listSupporters = (query) => listByRole({ roleType: 'sponsor', ...query }) +// 合规管理员 (sys_user.role_type='manager', 选项目负责人用) +export const listManagers = (query) => listByRole({ roleType: 'manager', ...query }) + +// 支持方下拉选项 (JOIN biz_org + sys_user): 返回 [{ userId, orgName, userName }, ...] +// 用于 manager 项目分配弹窗按公司名搜索 + 选公司 +export function listSponsorOrgs(query) { + return request({ url: '/business/org/sponsorOptions', method: 'get', params: query }) +} + +// 执行方下拉选项 (JOIN biz_org + sys_user, 仅 MAIN 账号): 返回 [{ userId, orgName, userName }, ...] +// 用于 manager 项目分配弹窗按公司名搜索 + 选执行单位 +// 关键: 后端 SQL 已限定 parent_user_id IS NULL, 自动排除同公司的普通员工子账号 +// 业务上 label=orgName / value=MAIN user_id, 直接写 biz_project_assign.exec_user_id +export function listExecutorOrgs(query) { + return request({ url: '/business/org/executorOptions', method: 'get', params: query }) +} diff --git a/ry-vue3/src/components/PortalShell.vue b/ry-vue3/src/components/PortalShell.vue new file mode 100644 index 0000000..bd2af29 --- /dev/null +++ b/ry-vue3/src/components/PortalShell.vue @@ -0,0 +1,257 @@ + + + + + \ No newline at end of file diff --git a/ry-vue3/src/layout/AdminLayout.vue b/ry-vue3/src/layout/AdminLayout.vue index 893f619..6425d73 100644 --- a/ry-vue3/src/layout/AdminLayout.vue +++ b/ry-vue3/src/layout/AdminLayout.vue @@ -62,7 +62,7 @@ const router = useRouter() const store = useUserStore() const role = computed(() => route.meta?.role || store.role) -const ROLE_LABEL = { leader: '项目负责人', manager: '合规人员', admin: '后台管理员', doctor: '评审专家', executor: '执行人', sponsor: '赞助方' } +const ROLE_LABEL = { leader: '项目负责人', manager: '合规人员', admin: '后台管理员', doctor: '评审专家', executor: '执行人', sponsor: '支持方' } const roleLabel = computed(() => ROLE_LABEL[role.value] || '工作台') const MENU = { diff --git a/ry-vue3/src/router/index.js b/ry-vue3/src/router/index.js index e666d7d..1a222d3 100644 --- a/ry-vue3/src/router/index.js +++ b/ry-vue3/src/router/index.js @@ -12,7 +12,7 @@ const routes = [ { path: 'invitation/:annId', name: 'invitation', component: () => import('@/views/portal/Invitation.vue'), meta: { title: '邀请函详情' } }, { path: 'register-expert', name: 'register-expert', component: () => import('@/views/auth/RegisterExpert.vue'), meta: { title: '专家注册' } }, { path: 'register-executor', name: 'register-executor', component: () => import('@/views/auth/RegisterExecutor.vue'), meta: { title: '执行单位(供应商)注册' } }, - { path: 'register-sponsor', name: 'register-sponsor', component: () => import('@/views/auth/RegisterSponsor.vue'), meta: { title: '赞助方注册' } }, + { path: 'register-sponsor', name: 'register-sponsor', component: () => import('@/views/auth/RegisterSponsor.vue'), meta: { title: '支持方注册' } }, { path: 'login', name: 'login', component: () => import('@/views/auth/Login.vue'), meta: { title: '登录' } }, { path: 'article/:type', name: 'portal-article', component: () => import('@/views/portal/ArticleView.vue'), meta: { title: '协议' } }, { path: 'special-plan/:id', name: 'portal-special-plan', component: () => import('@/views/portal/SpecialPlanDetail.vue'), meta: { title: '专项计划详情' } } diff --git a/ry-vue3/src/views/admin/Account.vue b/ry-vue3/src/views/admin/Account.vue index 6794376..f01f65b 100644 --- a/ry-vue3/src/views/admin/Account.vue +++ b/ry-vue3/src/views/admin/Account.vue @@ -50,7 +50,7 @@ const store = useUserStore() const tab = ref('profile') const loading = ref(false) const profile = ref({}) -const ROLE_LABEL = { admin: '后台管理员', leader: '项目负责人', manager: '合规人员', doctor: '评审专家', executor: '执行人', sponsor: '赞助方' } +const ROLE_LABEL = { admin: '后台管理员', leader: '项目负责人', manager: '合规人员', doctor: '评审专家', executor: '执行人', sponsor: '支持方' } const roleLabel = computed(() => ROLE_LABEL[store.role] || store.role || '后台管理员') const form = reactive({ nickName: '', phonenumber: '', email: '' }) diff --git a/ry-vue3/src/views/admin/ExecutorPeople.vue b/ry-vue3/src/views/admin/ExecutorPeople.vue index f604159..3f1070e 100644 --- a/ry-vue3/src/views/admin/ExecutorPeople.vue +++ b/ry-vue3/src/views/admin/ExecutorPeople.vue @@ -137,7 +137,10 @@ function reset() { async function onToggleStatus(row) { const disabled = isDisabled(row) - const newStatus = disabled ? '正常' : '禁用' + // sys_user.status 是 CHAR(1), 只能写 '0'/'1' (禁用='1', 启用='0') + // 必须带 userId: BizPersonServiceImpl.updateByPrimaryKey 仅在 userId != null 时 + // 才同步 status 到 sys_user, 否则只更新 biz_person (而 biz_person.status 已删除) + const newStatus = disabled ? '0' : '1' const label = disabled ? '启用' : '禁用' try { await ElMessageBox.confirm( @@ -147,7 +150,7 @@ async function onToggleStatus(row) { ) } catch { return } try { - await bizUpdate('person', { personId: row.personId, status: newStatus }) + await bizUpdate('person', { personId: row.personId, userId: row.userId, status: newStatus }) ElMessage.success('已' + label) load() } catch (e) { ElMessage.error(e?.msg || '操作失败') } diff --git a/ry-vue3/src/views/admin/Orgs.vue b/ry-vue3/src/views/admin/Orgs.vue index 05d0457..a238e3b 100644 --- a/ry-vue3/src/views/admin/Orgs.vue +++ b/ry-vue3/src/views/admin/Orgs.vue @@ -3,7 +3,7 @@ 角色: 🟦 后台 公司管理 (admin/orgs) 重构说明 (2026-08-15): 原 biz_support_unit / biz_execution_unit / biz_service_org 三表合并为 biz_org - 通过 org_type 区分 sponsor(赞助方) / execution(执行方) + 通过 org_type 区分 sponsor(支持方) / execution(执行方) biz_service_org 整体删除 接口: bizList('org', q) / bizUpdate --> @@ -14,7 +14,7 @@ - + @@ -50,7 +50,7 @@ @@ -95,7 +95,7 @@ - 赞助方 + 支持方 执行方 @@ -219,7 +219,7 @@ function onEdit(row) { function onView(row) { // 只读查看用 ElMessageBox 弹窗即可, 这里简单 alert 一下 ElMessageBox.alert( - `类型: ${row.orgType === 'sponsor' ? '赞助方' : '执行方'}\n` + + `类型: ${row.orgType === 'sponsor' ? '支持方' : '执行方'}\n` + `名称: ${row.orgName}\n` + `地址: ${row.address || '-'}\n` + `税号: ${row.taxNo || '-'}\n` + diff --git a/ry-vue3/src/views/admin/Roles.vue b/ry-vue3/src/views/admin/Roles.vue index 94d196e..0b54eaa 100644 --- a/ry-vue3/src/views/admin/Roles.vue +++ b/ry-vue3/src/views/admin/Roles.vue @@ -47,7 +47,7 @@ import { ElMessage } from 'element-plus' const ROLE_LABEL = { admin: '后台管理员', leader: '项目负责人', manager: '合规人员', - doctor: '评审专家', executor: '执行人', sponsor: '赞助方' + doctor: '评审专家', executor: '执行人', sponsor: '支持方' } // 卡片展示的角色 (隐藏 admin / leader) const VISIBLE_ROLES = ['manager', 'doctor', 'executor', 'sponsor'] diff --git a/ry-vue3/src/views/admin/SponsorOrgs.vue b/ry-vue3/src/views/admin/SponsorOrgs.vue index 132388e..f39cf3a 100644 --- a/ry-vue3/src/views/admin/SponsorOrgs.vue +++ b/ry-vue3/src/views/admin/SponsorOrgs.vue @@ -198,7 +198,7 @@ function onPeople(row) { } function onView(row) { ElMessageBox.alert( - `类型: 赞助方\n` + + `类型: 支持方\n` + `名称: ${row.orgName}\n` + `地址: ${row.address || '-'}\n` + `税号: ${row.taxNo || '-'}\n` + diff --git a/ry-vue3/src/views/admin/SponsorPeople.vue b/ry-vue3/src/views/admin/SponsorPeople.vue index 047b448..7a21cbc 100644 --- a/ry-vue3/src/views/admin/SponsorPeople.vue +++ b/ry-vue3/src/views/admin/SponsorPeople.vue @@ -138,7 +138,10 @@ function reset() { async function onToggleStatus(row) { const disabled = isDisabled(row) - const newStatus = disabled ? '正常' : '禁用' + // sys_user.status 是 CHAR(1), 只能写 '0'/'1' (禁用='1', 启用='0') + // 必须带 userId: BizPersonServiceImpl.updateByPrimaryKey 仅在 userId != null 时 + // 才同步 status 到 sys_user, 否则只更新 biz_person (而 biz_person.status 已删除) + const newStatus = disabled ? '0' : '1' const label = disabled ? '启用' : '禁用' try { await ElMessageBox.confirm( @@ -148,7 +151,7 @@ async function onToggleStatus(row) { ) } catch { return } try { - await bizUpdate('person', { personId: row.personId, status: newStatus }) + await bizUpdate('person', { personId: row.personId, userId: row.userId, status: newStatus }) ElMessage.success('已' + label) load() } catch (e) { ElMessage.error(e?.msg || '操作失败') } diff --git a/ry-vue3/src/views/admin/SponsorPersonNew.vue b/ry-vue3/src/views/admin/SponsorPersonNew.vue index 528a0e4..f8fb371 100644 --- a/ry-vue3/src/views/admin/SponsorPersonNew.vue +++ b/ry-vue3/src/views/admin/SponsorPersonNew.vue @@ -30,7 +30,7 @@ - 监察员 (赞助方人员固定) + 监察员 (支持方人员固定) diff --git a/ry-vue3/src/views/admin/Users.vue b/ry-vue3/src/views/admin/Users.vue index c0dc0d8..353d64b 100644 --- a/ry-vue3/src/views/admin/Users.vue +++ b/ry-vue3/src/views/admin/Users.vue @@ -98,7 +98,7 @@ import { ElMessage } from 'element-plus' const ROLE_LABEL = { admin: '后台管理员', leader: '项目负责人', manager: '合规人员', - doctor: '评审专家', executor: '执行人', sponsor: '赞助方' + doctor: '评审专家', executor: '执行人', sponsor: '支持方' } const roleOptions = Object.entries(ROLE_LABEL).map(([value, label]) => ({ value, label })) diff --git a/ry-vue3/src/views/admin/Workbench.vue b/ry-vue3/src/views/admin/Workbench.vue index ccac9f7..9148802 100644 --- a/ry-vue3/src/views/admin/Workbench.vue +++ b/ry-vue3/src/views/admin/Workbench.vue @@ -53,7 +53,7 @@ const roleStats = ref([]) const ROLE_LABEL = { admin: '后台管理员', leader: '项目负责人', manager: '合规人员', - doctor: '评审专家', executor: '执行人', sponsor: '赞助方' + doctor: '评审专家', executor: '执行人', sponsor: '支持方' } async function load() { @@ -125,7 +125,7 @@ onMounted(load) background-clip: text; } -.hint-text { font-size: 12px; color: #ff4d4f; margin: 12px 0 20px; text-align: center; } +.hint-text { font-size: 12px; color: #8c8c8c; margin: 12px 0 20px; text-align: center; } .section { background: #fff; diff --git a/ry-vue3/src/views/auth/Login.vue b/ry-vue3/src/views/auth/Login.vue index 048e6aa..2af0f01 100644 --- a/ry-vue3/src/views/auth/Login.vue +++ b/ry-vue3/src/views/auth/Login.vue @@ -213,7 +213,7 @@ const userTypes = [ { value: 'manager', name: '项目经理', desc: '项目管理、方案审核、过程监督' }, { value: 'doctor', name: '评审专家', desc: '项目评审、评分反馈、查看任务' }, { value: 'executor', name: '执行单位', desc: '会议组织、人员安排、劳务结算' }, - { value: 'sponsor', name: '支持单位 / 赞助方', desc: '支持函管理、人员管理、合作记录' }, + { value: 'sponsor', name: '支持单位', desc: '支持函管理、人员管理、合作记录' }, ] async function loadCaptcha() { diff --git a/ry-vue3/src/views/auth/RegisterExecutor.vue b/ry-vue3/src/views/auth/RegisterExecutor.vue index 1b917aa..78b7aa1 100644 --- a/ry-vue3/src/views/auth/RegisterExecutor.vue +++ b/ry-vue3/src/views/auth/RegisterExecutor.vue @@ -1,7 +1,7 @@