ソースを参照

feat: 把原来的员工改为角色,方便理解

wuwenyi 2 週間 前
コミット
1b408c7003

+ 4 - 0
src/api/system/user.ts

@@ -23,6 +23,10 @@ export function deleteUser(id: number): Promise<void> {
   return request.delete(`/system/user/${id}`)
 }
 
+export function assignUserRoles(id: number, roleIds: number[]): Promise<void> {
+  return request.put(`/system/user/${id}/roles`, { roleIds })
+}
+
 export function bindWeCom(id: number, data: { wecomUserId?: string; wecomRemindEnabled?: number }): Promise<void> {
   return request.put(`/system/user/${id}/wecom`, data)
 }

+ 2 - 2
src/router/index.ts

@@ -81,13 +81,13 @@ const router = createRouter({
           path: 'user',
           name: 'User',
           component: () => import('@/views/system/user/index.vue'),
-          meta: { title: '管理员管理', icon: 'UserFilled' }
+          meta: { title: '用户管理', icon: 'UserFilled' }
         },
         {
           path: 'role',
           name: 'Role',
           component: () => import('@/views/system/role/index.vue'),
-          meta: { title: '员工管理', icon: 'User' }
+          meta: { title: '审批角色', icon: 'User' }
         },
       ]
     },

+ 3 - 3
src/views/flow/designer/index.vue

@@ -49,7 +49,7 @@
               v-model="nodeProps.assigneeValue"
               filterable
               clearable
-              placeholder="请选择员工管理中的成员"
+              placeholder="请选择审批角色中的成员"
               style="width: 100%"
             >
               <el-option
@@ -677,13 +677,13 @@ function validateFlow(graphData: any): string | null {
   if (endNodes.length === 0) return '流程图缺少结束节点'
   if (startNodes.length > 1) return '流程图只能有一个开始节点'
   if (endNodes.length > 1) return '流程图只能有一个结束节点'
-  // 检查审批节点是否选择了员工管理中的成员(角色账号)
+  // 检查审批节点是否选择了审批角色
   for (const node of nodes) {
     if (node.type === 'approval-node' || node.type === 'approval') {
       const props = node.properties || {}
       const assigneeValue = props.assigneeValue || props.approver
       if (!assigneeValue) {
-        return `审批节点 "${node.text || node.name}" 未选择员工管理中的审批成员`
+        return `审批节点 "${node.text || node.name}" 未选择审批角色`
       }
     }
   }

+ 1 - 1
src/views/system/notification-config/index.vue

@@ -49,7 +49,7 @@
           <p><strong>1. 配置来源</strong></p>
           <p>本系统将企业微信配置保存在 <code>sys_notification_config</code> 表中,对接后端可调用 <code>GET /system/notification-config/wecom</code> 读取。</p>
           <p><strong>2. 接收人映射</strong></p>
-          <p>员工的企业微信账号保存在 <code>sys_user.wecom_user_id</code> 字段,可在「员工管理」中为每个员工绑定。</p>
+          <p>企业微信账号可在「用户管理」或「审批角色」中为每个账号绑定。</p>
           <p><strong>3. 事件触发点</strong></p>
           <p>本系统会在以下事件发生时通过日志输出待通知内容,对接方可订阅事件或轮询待发送记录:</p>
           <ul>

+ 20 - 20
src/views/system/role/index.vue

@@ -32,22 +32,22 @@
         </el-card>
       </el-col>
 
-      <!-- 右侧员工列表 -->
+      <!-- 右侧审批角色列表 -->
       <el-col :span="19">
         <el-card>
           <template #header>
             <div class="card-header">
-              <span>员工列表</span>
-              <el-button type="primary" @click="handleAdd">新增员工</el-button>
+              <span>审批角色列表</span>
+              <el-button type="primary" @click="handleAdd">新增角色</el-button>
             </div>
           </template>
 
           <el-form :inline="true" :model="queryParams" class="search-form">
-            <el-form-item label="员工编码">
-              <el-input v-model="queryParams.roleCode" placeholder="请输入员工编码" clearable />
+            <el-form-item label="角色编码">
+              <el-input v-model="queryParams.roleCode" placeholder="请输入角色编码" clearable />
             </el-form-item>
-            <el-form-item label="员工姓名">
-              <el-input v-model="queryParams.roleName" placeholder="请输入员工姓名" clearable />
+            <el-form-item label="角色名称">
+              <el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable />
             </el-form-item>
             <el-form-item>
               <el-button type="primary" @click="handleQuery">查询</el-button>
@@ -57,8 +57,8 @@
 
           <el-table v-loading="loading" :data="tableData" border>
             <el-table-column type="index" label="序号" width="60" />
-            <el-table-column prop="roleCode" label="员工编码" />
-            <el-table-column prop="roleName" label="员工姓名" />
+            <el-table-column prop="roleCode" label="角色编码" />
+            <el-table-column prop="roleName" label="角色名称" />
             <el-table-column prop="username" label="登录账号" />
             <el-table-column prop="phone" label="手机号">
               <template #default="{ row }">
@@ -105,17 +105,17 @@
       </el-col>
     </el-row>
 
-    <!-- 员工弹窗 -->
+    <!-- 角色弹窗 -->
     <el-dialog v-model="dialogVisible" :title="dialogTitle" width="500px">
       <el-form ref="formRef" :model="form" :rules="formRules" label-width="80px">
-        <el-form-item label="员工编码" prop="roleCode">
+        <el-form-item label="角色编码" prop="roleCode">
           <el-input v-model="form.roleCode" :disabled="isEdit" />
         </el-form-item>
-        <el-form-item label="员工姓名" prop="roleName">
+        <el-form-item label="角色名称" prop="roleName">
           <el-input v-model="form.roleName" />
         </el-form-item>
         <el-form-item label="登录账号" prop="username">
-          <el-input v-model="form.username" placeholder="员工登录账号" />
+          <el-input v-model="form.username" placeholder="角色登录账号" />
         </el-form-item>
         <el-form-item label="手机号" prop="phone">
           <el-input v-model="form.phone" placeholder="请输入手机号" />
@@ -159,7 +159,7 @@
           :closable="false"
           style="margin-bottom: 20px;"
         />
-        <el-form-item label="员工姓名">
+        <el-form-item label="角色名称">
           <el-input v-model="wecomForm.roleName" disabled />
         </el-form-item>
         <el-form-item label="企微账号">
@@ -255,7 +255,7 @@ const deptTree = computed(() => {
 
 const deptTreeForSelect = shallowRef<Dept[]>([])
 
-// 员工弹窗
+// 角色弹窗
 const dialogVisible = ref(false)
 const dialogTitle = ref('')
 const isEdit = ref(false)
@@ -273,8 +273,8 @@ const form = reactive<Partial<Role>>({
 })
 
 const formRules: FormRules = {
-  roleCode: [{ required: true, message: '请输入员工编码', trigger: 'blur' }],
-  roleName: [{ required: true, message: '请输入员工姓名', trigger: 'blur' }],
+  roleCode: [{ required: true, message: '请输入角色编码', trigger: 'blur' }],
+  roleName: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
   phone: [{
     pattern: /^1[3-9]\d{9}$/,
     message: '请输入正确的手机号',
@@ -363,7 +363,7 @@ function handleDeptClick(data: Dept) {
 
 function handleAdd() {
   isEdit.value = false
-  dialogTitle.value = '新增员工'
+  dialogTitle.value = '新增角色'
   Object.assign(form, {
     id: undefined,
     roleCode: '',
@@ -380,7 +380,7 @@ function handleAdd() {
 
 function handleEdit(row: Role) {
   isEdit.value = true
-  dialogTitle.value = '编辑员工'
+  dialogTitle.value = '编辑角色'
   Object.assign(form, {
     ...row,
     phone: row.phone || ''
@@ -390,7 +390,7 @@ function handleEdit(row: Role) {
 
 async function handleDelete(row: Role) {
   try {
-    await ElMessageBox.confirm(`确认删除员工 "${row.roleName}" 吗?`, '提示', { type: 'warning' })
+    await ElMessageBox.confirm(`确认删除角色 "${row.roleName}" 吗?`, '提示', { type: 'warning' })
     await deleteRole(row.id)
     ElMessage.success('删除成功')
     loadData()

+ 51 - 4
src/views/system/user/index.vue

@@ -44,9 +44,10 @@
           </template>
         </el-table-column>
         <el-table-column prop="createTime" label="创建时间" />
-        <el-table-column label="操作" width="180">
+        <el-table-column label="操作" width="260">
           <template #default="{ row }">
             <el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
+            <el-button link type="success" @click="handleAssignRole(row)">分配角色</el-button>
             <el-button link type="danger" @click="handleDelete(row)">删除</el-button>
           </template>
         </el-table-column>
@@ -64,6 +65,20 @@
       />
     </el-card>
 
+    <!-- 分配角色弹窗 -->
+    <el-dialog v-model="roleDialogVisible" title="分配角色" width="500px">
+      <el-checkbox-group v-model="selectedRoleIds">
+        <el-checkbox v-for="role in allRoles" :key="role.id" :label="role.id">
+          {{ role.roleName }}({{ role.roleCode }})
+        </el-checkbox>
+      </el-checkbox-group>
+      <el-empty v-if="allRoles.length === 0" description="暂无可分配的角色" :image-size="60" />
+      <template #footer>
+        <el-button @click="roleDialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="submitAssignRole">确认</el-button>
+      </template>
+    </el-dialog>
+
     <!-- 管理员弹窗 -->
     <el-dialog v-model="dialogVisible" :title="dialogTitle" width="500px">
       <el-form ref="formRef" :model="form" :rules="formRules" label-width="80px">
@@ -121,10 +136,11 @@
 import { ref, shallowRef, reactive, onMounted } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import type { FormInstance, FormRules } from 'element-plus'
-import { listUser, addUser, updateUser, deleteUser } from '@/api/system/user'
+import { listUser, addUser, updateUser, deleteUser, assignUserRoles } from '@/api/system/user'
+import { listRole } from '@/api/system/role'
 import { listDept } from '@/api/system/dept'
 import { adminEmployeeTypeLabel } from '@/utils/format'
-import type { User, Dept } from '@/types/system'
+import type { User, Role, Dept } from '@/types/system'
 
 const loading = ref(false)
 const tableData = ref<User[]>([])
@@ -288,8 +304,39 @@ async function submitForm() {
   loadData()
 }
 
+// 分配角色
+const roleDialogVisible = ref(false)
+const allRoles = ref<Role[]>([])
+const selectedRoleIds = ref<number[]>([])
+const assigningUserId = ref<number | null>(null)
+
+async function loadAllRoles() {
+  try {
+    const res = await listRole({ pageNum: 1, pageSize: 200 })
+    allRoles.value = res.list
+  } catch { /* ignore */ }
+}
+
+function handleAssignRole(row: User) {
+  assigningUserId.value = row.id
+  selectedRoleIds.value = row.roleIds ? [...row.roleIds] : []
+  roleDialogVisible.value = true
+}
+
+async function submitAssignRole() {
+  if (assigningUserId.value == null) return
+  try {
+    await assignUserRoles(assigningUserId.value, selectedRoleIds.value)
+    ElMessage.success('角色分配成功')
+    roleDialogVisible.value = false
+    loadData()
+  } catch (e: any) {
+    ElMessage.error(e?.message || '分配失败')
+  }
+}
+
 onMounted(() => {
-  Promise.all([loadDepts(), loadData()])
+  Promise.all([loadDepts(), loadData(), loadAllRoles()])
 })
 </script>