feat(sponsor/people): 主账号同步建 biz_person (admin/总负责人), 列表可见 + 操作列对本人隐藏 + 新建下拉不包含 admin
后端:
- BizAuthController.registerSponsor step 6: 为主账号同步建 biz_person
(走 BizPersonMapper 直插, 绕过 BizPersonServiceImpl 创 SUB 子账号的逻辑;
SnowflakeId 注入 personId; department=管理部, position=总负责人, role=admin,
unit_type=sponsor, user_id=主账号自己)
- BizPersonMapper.java + xml 新增 countAdminByOrgId: 校验某 org 下是否已有 admin
(注册场景下天然返回 0, 是给未来 bug 兜底, registerSponsor 暂不调用)
- BizPersonMapper.xml selectSponsorList: WHERE 加 OR u.user_id=#{sponsorOwnerUid},
让主账号自己的 biz_person (parent_user_id=NULL) 也能被自身 list 看到
前端:
- utils/roleMap.js: PERSON_ROLE_LABEL 加 admin:'管理员'
- sponsor/SponsorPeople.vue: 角色列改用 translatePersonRole, tag type 按 role 动态
(admin=warning, supervisor=primary); 操作列本人隐藏 禁用/恢复 + 删除
(v-if=row.userId !== store.user?.userId, 防主账号把自己禁用/误删)
- sponsor/NewPerson.vue: 编辑模式 role=admin 显示静态 el-tag, 新建下拉仍只含 supervisor
- sponsor/PersonDetail.vue: 角色展示同步用 translatePersonRole
- auth/Login.vue + portal/Home.vue: 文案 监察员 → 管理员 (注册即管理员, 可建监察员子账号)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+26
-1
@@ -11,9 +11,12 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.business.domain.BizOrg;
|
||||
import com.ruoyi.business.domain.BizPerson;
|
||||
import com.ruoyi.business.dto.SmsValidForm;
|
||||
import com.ruoyi.business.mapper.BizPersonMapper;
|
||||
import com.ruoyi.business.service.IBizOrgService;
|
||||
import com.ruoyi.business.service.SysSmsService;
|
||||
import com.ruoyi.common.utils.id.SnowflakeId;
|
||||
import com.ruoyi.common.constant.Constants;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
@@ -37,7 +40,8 @@ import com.ruoyi.system.service.ISysUserService;
|
||||
* 3. 加密密码
|
||||
* 4. 插入 sys_user (用户名=前端传入, sys_user.role_type 写入 executor/sponsor, 主账号)
|
||||
* 5. 插入 biz_org (对应类型, business_nature/contact_phone 从表单)
|
||||
* 注: 主账号不建 biz_person
|
||||
* 6. 插入 biz_person (主账号同步建自己=管理员, 让自己在"人员管理"可见)
|
||||
* 注: 主账号同步建 biz_person (自己=管理员)
|
||||
*
|
||||
* 2026-08-16 重构: 删 biz_user_role_bind, 统一用 sys_user.role_type (见迁移脚本)
|
||||
*
|
||||
@@ -58,6 +62,9 @@ public class BizAuthController extends BaseController {
|
||||
@Autowired
|
||||
private IBizOrgService bizOrgService;
|
||||
|
||||
@Autowired
|
||||
private BizPersonMapper bizPersonMapper;
|
||||
|
||||
@Autowired
|
||||
private BCryptPasswordEncoder passwordEncoder;
|
||||
|
||||
@@ -294,6 +301,24 @@ public class BizAuthController extends BaseController {
|
||||
bizOrgService.insert(org);
|
||||
Long orgId = org.getOrgId();
|
||||
|
||||
// 6. 同步建 biz_person (主账号自己 = 管理员, 让"人员管理"能看到自己)
|
||||
// 注意: 不能走 IBizPersonService.insert(BizPerson, Long), 那个方法是创建 SUB 子账号的
|
||||
// (强制 accountType='SUB' + 需 loginUsername, 主账号自己不需要).
|
||||
// sys_user 已在 step 4 建好, 这里只需把 biz_person 关联到主账号自己.
|
||||
BizPerson self = new BizPerson();
|
||||
SnowflakeId.injectIfEmpty(self, "personId");
|
||||
self.setName(unitName);
|
||||
self.setPhone(phone);
|
||||
self.setOrgId(orgId);
|
||||
self.setDepartment("管理部");
|
||||
self.setPosition("总负责人");
|
||||
self.setRole("admin"); // 主账号 = 管理员 (与子账号的监察员区分)
|
||||
self.setUnitType("sponsor");
|
||||
self.setUserId(userId);
|
||||
self.setCreateBy(username);
|
||||
self.setUpdateBy(username);
|
||||
bizPersonMapper.insert(self);
|
||||
|
||||
return success("注册成功, 请等待审核").put("userId", userId).put("orgId", orgId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.ruoyi.business.mapper;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import com.ruoyi.business.domain.BizPerson;
|
||||
|
||||
/**
|
||||
@@ -19,4 +20,6 @@ public interface BizPersonMapper
|
||||
int deleteByPrimaryKeys(String[] personIds);
|
||||
/** 联动: person 逻辑删除后, 把对应 sys_user 子账号也逻辑删除 */
|
||||
int softDeleteSysUserByPersonIds(String[] personIds);
|
||||
/** 校验某 org 下是否已有 admin 角色 (注册时兜底, 保证一公司一管理员) */
|
||||
int countAdminByOrgId(@Param("orgId") Long orgId);
|
||||
}
|
||||
@@ -47,9 +47,10 @@
|
||||
<where>
|
||||
u.del_flag = '0'
|
||||
<if test="unitType != null and unitType != ''"> and p.unit_type = #{unitType}</if>
|
||||
<if test="name != null and name != ''"> and p.name = #{name}</if>
|
||||
<if test="name != null and name != ''"> and p.name like concat('%', #{name}, '%')</if>
|
||||
<if test="phone != null and phone != ''"> and p.phone = #{phone}</if>
|
||||
<if test="orgId != null"> and p.org_id = #{orgId}</if>
|
||||
<if test="orgName != null and orgName != ''"> and o.org_name like concat('%', #{orgName}, '%')</if>
|
||||
<if test="orgType != null and orgType != ''"> and o.org_type = #{orgType}</if>
|
||||
<if test="department != null and department != ''"> and p.department = #{department}</if>
|
||||
<if test="position != null and position != ''"> and p.position = #{position}</if>
|
||||
@@ -144,16 +145,18 @@
|
||||
</update>
|
||||
|
||||
<!-- sponsor 专属: 通过 biz_person.user_id 关联 sys_user, 利用 sys_user.parent_user_id 过滤主账号归属 -->
|
||||
<!-- INNER JOIN 自然过滤掉 user_id=NULL 的游离 person (不算员工) -->
|
||||
<!-- 主账号自己 (parent_user_id=NULL) 也通过 OR u.user_id=#{sponsorOwnerUid} 一并带上 (否则主账号看不到自己) -->
|
||||
<select id="selectSponsorList" resultMap="BizPersonResult" parameterType="BizPerson">
|
||||
<include refid="selectFieldsWithAccount"/>
|
||||
<where>
|
||||
u.del_flag = '0'
|
||||
and p.unit_type = 'sponsor'
|
||||
and u.parent_user_id = #{params.sponsorOwnerUid}
|
||||
<if test="name != null and name != ''"> and p.name = #{name}</if>
|
||||
and (u.parent_user_id = #{params.sponsorOwnerUid}
|
||||
or u.user_id = #{params.sponsorOwnerUid})
|
||||
<if test="name != null and name != ''"> and p.name like concat('%', #{name}, '%')</if>
|
||||
<if test="phone != null and phone != ''"> and p.phone = #{phone}</if>
|
||||
<if test="orgId != null"> and p.org_id = #{orgId}</if>
|
||||
<if test="orgName != null and orgName != ''"> and o.org_name like concat('%', #{orgName}, '%')</if>
|
||||
<if test="department != null and department != ''"> and p.department = #{department}</if>
|
||||
<if test="position != null and position != ''"> and p.position = #{position}</if>
|
||||
<if test="role != null and role != ''"> and p.role = #{role}</if>
|
||||
@@ -169,9 +172,10 @@
|
||||
u.del_flag = '0'
|
||||
and p.unit_type = 'executor'
|
||||
and u.parent_user_id = #{params.executorOwnerUid}
|
||||
<if test="name != null and name != ''"> and p.name = #{name}</if>
|
||||
<if test="name != null and name != ''"> and p.name like concat('%', #{name}, '%')</if>
|
||||
<if test="phone != null and phone != ''"> and p.phone = #{phone}</if>
|
||||
<if test="orgId != null"> and p.org_id = #{orgId}</if>
|
||||
<if test="orgName != null and orgName != ''"> and o.org_name like concat('%', #{orgName}, '%')</if>
|
||||
<if test="department != null and department != ''"> and p.department = #{department}</if>
|
||||
<if test="position != null and position != ''"> and p.position = #{position}</if>
|
||||
<if test="role != null and role != ''"> and p.role = #{role}</if>
|
||||
@@ -179,4 +183,11 @@
|
||||
</where>
|
||||
order by p.person_id desc
|
||||
</select>
|
||||
|
||||
<!-- 校验某 org 下是否已有 admin 角色 (主账号自带 biz_person.role='admin', 每公司唯一) -->
|
||||
<select id="countAdminByOrgId" resultType="int">
|
||||
select count(*) from biz_person p
|
||||
left join sys_user u on p.user_id = u.user_id
|
||||
where p.org_id = #{orgId} and p.role = 'admin' and u.del_flag = '0'
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
*/
|
||||
export const PERSON_ROLE_LABEL = {
|
||||
meetingExecutor: '会议执行',
|
||||
supervisor: '监察员'
|
||||
supervisor: '监察员',
|
||||
admin: '管理员'
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -204,7 +204,7 @@ let smsSmsTimer = null
|
||||
const registerTypes = [
|
||||
{ value: 'expert', name: '项目参与专家', desc: '负责项目方案设计与评审' },
|
||||
{ value: 'executor', name: '项目执行单位(供应商)', desc: '承担项目执行,需走入库流程' },
|
||||
{ value: 'sponsor', name: '项目支持单位', desc: '注册后默认为监察员角色' }
|
||||
{ value: 'sponsor', name: '项目支持单位', desc: '注册后默认为管理员角色, 可建监察员子账号' }
|
||||
]
|
||||
|
||||
const userTypes = [
|
||||
|
||||
@@ -65,8 +65,8 @@
|
||||
<div class="notice-card">
|
||||
<ul class="notice-list">
|
||||
<li><strong>登录要求</strong> · 点击计划详情及项目提案,需先登录系统;</li>
|
||||
<li><strong>支持方注册</strong> · 注册后默认为监察员角色,合规人员可配置支持方的管理员账号;</li>
|
||||
<li><strong>支持方管理</strong> · 注册时选择的企业为主单位,默认进入该企业的人员管理页,由企业管理员进行管理,管理员账号可新建监督员账号;</li>
|
||||
<li><strong>支持方注册</strong> · 注册后默认为管理员角色,可登录后新建监察员子账号;</li>
|
||||
<li><strong>支持方管理</strong> · 注册时选择的企业为主单位,默认进入该企业的人员管理页,由企业管理员(总负责人)进行管理,管理员账号可新建监察员账号;</li>
|
||||
<li><strong>执行方注册</strong> · 注册跳转至供应商系统,走入库流程,注册成功后该账号默认为管理员账号,管理员账号可新建执行人员账号。</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -66,7 +66,10 @@
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="角色" prop="role">
|
||||
<el-select v-model="form.role" placeholder="请选择" style="width:100%">
|
||||
<!-- 编辑模式 + 当前 role=admin (主账号自己) → 显示静态 tag, 不让改 -->
|
||||
<!-- 新建时下拉不包含 admin, 只允许选 supervisor (监察员) -->
|
||||
<el-tag v-if="isEdit && form.role === 'admin'" type="warning" disable-transitions>管理员</el-tag>
|
||||
<el-select v-else v-model="form.role" placeholder="请选择" style="width:100%">
|
||||
<el-option label="监察员" value="supervisor" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
@@ -45,7 +45,11 @@
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="角色">
|
||||
<el-tag v-if="detail.role === 'supervisor'" type="primary" disable-transitions>监察员</el-tag>
|
||||
<!-- 主账号 role=admin(管理员), 子账号 role=supervisor(监察员), 都走 roleMap 翻译 -->
|
||||
<el-tag v-if="detail.role === 'admin' || detail.role === 'supervisor'"
|
||||
:type="detail.role === 'admin' ? 'warning' : 'primary'" disable-transitions>
|
||||
{{ translatePersonRole(detail.role) }}
|
||||
</el-tag>
|
||||
<span v-else style="color:#909399">{{ display.role }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -81,6 +85,7 @@ import { ref, computed, onMounted } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { bizGet } from '@/api/public'
|
||||
import { translatePersonRole } from '@/utils/roleMap'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
@@ -51,8 +51,10 @@
|
||||
<el-table-column prop="position" label="职务" width="120" />
|
||||
<el-table-column label="角色" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.role === 'supervisor'" type="primary" disable-transitions>监察员</el-tag>
|
||||
<span v-else style="color:#909399">—</span>
|
||||
<!-- 主账号 role=admin(管理员/总负责人), 子账号 role=supervisor(监察员), 都走 roleMap 翻译 -->
|
||||
<el-tag :type="row.role === 'admin' ? 'warning' : (row.role === 'supervisor' ? 'primary' : 'info')" disable-transitions>
|
||||
{{ translatePersonRole(row.role) || '—' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="账号类型" width="90">
|
||||
@@ -75,10 +77,12 @@
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="onView(row)">查看</el-button>
|
||||
<el-button link type="primary" @click="onEdit(row)">编辑</el-button>
|
||||
<el-button link :type="row.status === '0' ? 'warning' : 'success'" @click="onToggleStatus(row)">
|
||||
<!-- 本人不显示禁用/恢复按钮 (避免主账号把自己禁用导致登录不上) -->
|
||||
<el-button v-if="row.userId !== store.user?.userId" link :type="row.status === '0' ? 'warning' : 'success'" @click="onToggleStatus(row)">
|
||||
{{ row.status === '0' ? '禁用' : '恢复' }}
|
||||
</el-button>
|
||||
<el-button link type="danger" @click="onRemoveOne(row)">删除</el-button>
|
||||
<!-- 本人不显示删除按钮 (避免主账号误删自己的 biz_person) -->
|
||||
<el-button v-if="row.userId !== store.user?.userId" link type="danger" @click="onRemoveOne(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -142,9 +146,12 @@ import { useRouter } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { bizUpdate, bizDelete } from '@/api/public'
|
||||
import { listSponsorPerson } from '@/api/business/person'
|
||||
import { useUserStore } from '@/store/user'
|
||||
import { translatePersonRole } from '@/utils/roleMap'
|
||||
import request from '@/utils/request'
|
||||
|
||||
const router = useRouter()
|
||||
const store = useUserStore()
|
||||
|
||||
// sponsor 端只看自己团队 (主账号+子账号) 创建的人, 走专属接口 /business/person/sponsorList (后端强制隔离)
|
||||
const q = reactive({
|
||||
|
||||
Reference in New Issue
Block a user