Browse Source

feature: 系统管理->用户管理

autumnal_wind@yeah.net 1 month ago
parent
commit
0dde686162

+ 1 - 1
src/api/system/right/user/types.ts

@@ -68,7 +68,7 @@ export interface UserForm {
68 68
   category?: string;
69 69
   status: string;
70 70
   remark?: string;
71
-  postIds: string[];
71
+  postIds?: string[];
72 72
   roleIds: string[];
73 73
 }
74 74
 

+ 183 - 19
src/views/system/right/user/UserDetailForm.vue

@@ -1,12 +1,126 @@
1 1
 <template>
2 2
   <div class="e-dialog">
3
+    <el-dialog v-model="dialog.visible" :title="dialog.title" :draggable="dialog.draggable" width="35%" align-center>
4
+      <el-form ref="formRef" v-loading="formLoading" :model="formData" :rules="formRules" label-width="auto" class="mt-3">
5
+        <el-row>
6
+          <el-col :span="12">
7
+            <el-form-item label="用户名" prop="userName" >
8
+              <el-input v-model="formData.userName" placeholder="请输入用户名/登录账号" disabled="disabled"/>
9
+            </el-form-item>
10
+          </el-col>
11
+          <el-col :span="12">
12
+            <el-form-item label="登录密码" prop="loginPwd">
13
+              <el-input v-model="formData.loginPwd" placeholder="请输入登录密码" type="password" maxlength="20" show-password disabled="disabled"/>
14
+            </el-form-item>
15
+          </el-col>
16
+        </el-row>
17
+        <el-row>
18
+          <el-col :span="12">
19
+            <el-form-item label="学/工号" prop="userNumb">
20
+              <el-input v-model="formData.userNumb" placeholder="请输入学/工号" disabled="disabled" />
21
+            </el-form-item>
22
+          </el-col>
23
+          <el-col :span="12">
24
+            <el-form-item label="用户姓名" prop="realName">
25
+              <el-input v-model="formData.realName" placeholder="请输入用户姓名" />
26
+            </el-form-item>
27
+          </el-col>
28
+        </el-row>
29
+        <el-row>
30
+          <el-col :span="12">
31
+            <el-form-item label="归属部门" prop="deptId">
32
+              <el-tree-select
33
+                v-model="formData.deptId"
34
+                :data="deptOptions"
35
+                :props="{ value: 'id', label: 'label', children: 'children' }"
36
+                value-key="id"
37
+                placeholder="请选择归属部门"
38
+                check-strictly
39
+                @change="handleDeptChange"
40
+              />
41
+            </el-form-item>
42
+          </el-col>
43
+          <el-col :span="12">
44
+            <el-form-item label="工作岗位" prop="postId">
45
+              <el-select v-model="formData.postId" placeholder="请选择">
46
+                <el-option
47
+                  v-for="item in postOptions"
48
+                  :key="item.postId"
49
+                  :label="item.postName"
50
+                  :value="item.postId"
51
+                  :disabled="item.status == '1'"
52
+                ></el-option>
53
+              </el-select>
54
+            </el-form-item>
55
+          </el-col>
56
+        </el-row>
57
+        <el-row>
58
+          <el-col :span="12">
59
+            <el-form-item label="用户身份" prop="category">
60
+              <el-select v-model="formData.category" placeholder="请选择用户身份">
61
+                <el-option v-for="dict in CATEGORY" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
62
+              </el-select>
63
+            </el-form-item>
64
+          </el-col>
65
+          <el-col :span="12">
66
+            <el-form-item label="手机号码" prop="phone">
67
+              <el-input v-model="formData.phone" placeholder="请输入手机号码" />
68
+            </el-form-item>
69
+          </el-col>
70
+        </el-row>
71
+        <el-row>
72
+          <el-col :span="12">
73
+            <el-form-item label="用户性别" prop="sex">
74
+              <el-select v-model="formData.sex" placeholder="请选择性别">
75
+                <el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
76
+              </el-select>
77
+            </el-form-item>
78
+          </el-col>
79
+          <el-col :span="12">
80
+            <el-form-item label="用户邮箱" prop="email">
81
+              <el-input v-model="formData.email" placeholder="请输入用户邮箱" />
82
+            </el-form-item>
83
+          </el-col>
84
+        </el-row>
85
+        <el-row>
86
+          <el-col :span="24">
87
+            <el-form-item label="角色" prop="roleIds">
88
+              <el-select v-model="formData.roleIds" filterable multiple placeholder="请选择">
89
+                <el-option
90
+                  v-for="item in roleOptions"
91
+                  :key="item.roleId"
92
+                  :label="item.roleName"
93
+                  :value="item.roleId"
94
+                  :disabled="item.status == '1'"
95
+                ></el-option>
96
+              </el-select>
97
+            </el-form-item>
98
+          </el-col>
99
+        </el-row>
100
+        <el-row>
101
+          <el-col :span="24">
102
+            <el-form-item label="备注" prop="remark">
103
+              <el-input v-model="formData.remark" type="textarea" placeholder="请输入内容"></el-input>
104
+            </el-form-item>
105
+          </el-col>
106
+        </el-row>
107
+      </el-form>
108
+      <template #footer>
109
+        <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
110
+        <el-button @click="dialog.visible = false">取 消</el-button>
111
+      </template>
112
+    </el-dialog>
3 113
   </div>
4 114
 </template>
5
-
6 115
 <script setup name="UserDetailForm" lang="ts">
7 116
 /**  模块导入 */
8 117
 import { UserForm } from '@/api/system/right/user/types';
9 118
 import api from '@/api/system/right/user';
119
+import { useI18n } from 'vue-i18n';
120
+import { DeptVO } from '@/api/system/dept/types';
121
+import { PostVO } from '@/api/system/params/post/types';
122
+import { RoleVO } from '@/api/system/role/types';
123
+import { treeselect } from '@/api/system/dept';
10 124
 
11 125
 /** 当前组件属性 */
12 126
 defineOptions({ name: 'RecompenseForm' });
@@ -14,6 +128,7 @@ defineOptions({ name: 'RecompenseForm' });
14 128
 const { t } = useI18n();
15 129
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
16 130
 // 当前页面引用的数据字典
131
+const { sys_yes_no, sys_user_sex, CATEGORY } = toRefs<any>(proxy?.useDict('sys_yes_no', 'sys_user_sex', 'CATEGORY'));
17 132
 // 对话框
18 133
 const dialog = reactive<DialogOption>({
19 134
   visible: false,
@@ -26,6 +141,16 @@ const formLoading = ref(false);
26 141
 const formType = ref('');
27 142
 // 操作类型
28 143
 const command = ref('');
144
+// 输入项是否禁用
145
+const disabled = ref(false);
146
+// 部门下拉数据
147
+const deptOptions = ref<DeptVO[]>([]);
148
+// 默认初始密码
149
+const initPassword = ref<string>('');
150
+// 岗位下拉数据
151
+const postOptions = ref<PostVO[]>([]);
152
+// 角色下拉数据
153
+const roleOptions = ref<RoleVO[]>([]);
29 154
 // 表单引用
30 155
 const formRef = ref<ElFormInstance>();
31 156
 // 表单数据
@@ -44,21 +169,19 @@ const formData = ref<UserForm>({
44 169
   sex: undefined,
45 170
   status: '0',
46 171
   remark: '',
47
-  postIds: [],
48 172
   roleIds: []
49 173
 });
174
+// 表单提交校验规则
50 175
 const formRules = reactive({
51
-  deptId: [{ required: true, message: '部门名称间不能为空', trigger: 'blur' }],
52
-  postId: [{ required: true, message: '岗位名称不能为空', trigger: 'blur' }],
53 176
   userName: [{ required: true, message: '登录账号不能为空', trigger: 'blur' }],
54
-  realName: [{ required: true, message: '用户姓名不能为空', trigger: 'blur' }],
55
-  userNumb: [{ required: true, message: '学/工号不能为空', trigger: 'blur' }],
56 177
   loginPwd: [{ required: true, message: '登录密码不能为空', trigger: 'blur' }],
57
-  category: [{ required: true, message: '用户身份不能为空', trigger: 'blur' }]
58
-  // operatorMoney: [
59
-  //   { required: true, message: '补款金额不能为空', trigger: 'blur' },
60
-  //   { pattern: /^\d+(\.\d{1,2})?$/, message: '补款金额只能为两位小数的数字', trigger: 'blur' }
61
-  // ]
178
+  userNumb: [{ required: true, message: '学/工号不能为空', trigger: 'blur' }],
179
+  realName: [{ required: true, message: '用户姓名不能为空', trigger: 'blur' }],
180
+  deptId: [{ required: true, message: '归属部门不能为空', trigger: 'blur' }],
181
+  postId: [{ required: true, message: '工作岗位不能为空', trigger: 'blur' }],
182
+  category: [{ required: true, message: '用户身份不能为空', trigger: 'blur' }],
183
+  phone: [{ required: true, message: '电话号码不能为空', trigger: 'blur' }],
184
+  roleIds: [{ required: true, message: '用户角色不能为空', trigger: 'blur' }]
62 185
 });
63 186
 /** 当前组件方法 */
64 187
 const open = async (cmd: string, id?: string | number) => {
@@ -67,15 +190,48 @@ const open = async (cmd: string, id?: string | number) => {
67 190
   formType.value = cmd;
68 191
   command.value = cmd;
69 192
   resetForm();
193
+  await initTreeData();
70 194
   // 修改时,设置数据
71
-  if (id) {
72
-    formLoading.value = true;
73
-    try {
74
-      const res = await api.getUser(id);
75
-      Object.assign(formData.value, res.data);
76
-    } finally {
77
-      formLoading.value = false;
195
+  formLoading.value = true;
196
+  try {
197
+    let res;
198
+    if (id) {
199
+      disabled.value = true;
200
+      res = await api.getUser(id);
201
+      Object.assign(formData.value, res.data.user);
202
+      formData.value.postIds = res.data.postIds;
203
+      formData.value.roleIds = res.data.roleIds;
204
+      formData.value.loginPwd = '';
205
+    } else {
206
+      res = await api.getUser();
207
+      formData.value.loginPwd = initPassword.value.toString();
78 208
     }
209
+    postOptions.value = res.data.posts;
210
+    roleOptions.value = res.data.roles;
211
+  } finally {
212
+    formLoading.value = false;
213
+  }
214
+  // if (id) {
215
+  //   formLoading.value = true;
216
+  //   try {
217
+  //     const res = await api.getUser(id);
218
+  //     Object.assign(formData.value, res.data);
219
+  //   } finally {
220
+  //     formLoading.value = false;
221
+  //   }
222
+  // }
223
+};
224
+// 查询部门下拉树结构
225
+const getTreeSelect = async () => {
226
+  const res = await api.deptTreeSelect();
227
+  deptOptions.value = res.data;
228
+};
229
+// 初始化部门数据
230
+const initTreeData = async () => {
231
+  // 判断部门的数据是否存在,存在不获取,不存在则获取
232
+  if (deptOptions.value === undefined) {
233
+    const { data } = await treeselect();
234
+    deptOptions.value = data;
79 235
   }
80 236
 };
81 237
 // 重置表单
@@ -101,12 +257,20 @@ const resetForm = () => {
101 257
   formRef.value?.resetFields();
102 258
 };
103 259
 // 传回给父组件的属性与方法
104
-defineExpose({});
260
+defineExpose({ open });
105 261
 
106 262
 // 触发父组件的事件
107 263
 const emits = defineEmits([]);
108 264
 
109 265
 // 初始化
266
+onMounted(() => {
267
+  // 初始化部门数据
268
+  getTreeSelect();
269
+  // 初始化默认密码
270
+  proxy?.getConfigKey('sys.user.initPassword').then((response) => {
271
+    initPassword.value = response.data;
272
+  });
273
+});
110 274
 </script>
111 275
 
112 276
 <style scoped lang="scss">

+ 55 - 53
src/views/system/right/user/index.vue

@@ -20,15 +20,19 @@
20 20
         </el-card>
21 21
       </el-col>
22 22
       <el-col :lg="20" :xs="24">
23
-        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
23
+        <transition :enter-active-class="proxy?.animate.searchAnimate.enter"
24
+                    :leave-active-class="proxy?.animate.searchAnimate.leave">
24 25
           <div v-show="showSearch" class="mb-[5px]">
25 26
             <el-card shadow="hover">
26
-              <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="auto" class="-mb-25px -mt-5px">
27
+              <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="auto"
28
+                       class="-mb-25px -mt-5px">
27 29
                 <el-form-item label="用户姓名" prop="realName">
28
-                  <el-input v-model="queryParams.realName" placeholder="请输入用户姓名" clearable @keyup.enter="handleQuery" />
30
+                  <el-input v-model="queryParams.realName" placeholder="请输入用户姓名" clearable
31
+                            @keyup.enter="handleQuery" />
29 32
                 </el-form-item>
30 33
                 <el-form-item label="手机号码" prop="phone">
31
-                  <el-input v-model="queryParams.phone" placeholder="请输入手机号码" clearable @keyup.enter="handleQuery" />
34
+                  <el-input v-model="queryParams.phone" placeholder="请输入手机号码" clearable
35
+                            @keyup.enter="handleQuery" />
32 36
                 </el-form-item>
33 37
                 <el-form-item>
34 38
                   <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
@@ -42,15 +46,19 @@
42 46
           <template #header>
43 47
             <el-row :gutter="10">
44 48
               <el-col :span="1.5">
45
-                <el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
49
+                <el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus"
50
+                           @click="handleOpenDetail('add')">新增
51
+                </el-button>
46 52
               </el-col>
47 53
               <el-col :span="1.5">
48
-                <el-button v-has-permi="['system:user:add']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
54
+                <el-button v-has-permi="['system:user:add']" type="success" plain :disabled="single" icon="Edit"
55
+                           @click="handleOpenDetail('edit')">
49 56
                   修改
50 57
                 </el-button>
51 58
               </el-col>
52 59
               <el-col :span="1.5">
53
-                <el-button v-has-permi="['system:user:delete']" type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()">
60
+                <el-button v-has-permi="['system:user:delete']" type="danger" plain :disabled="multiple" icon="Delete"
61
+                           @click="handleDelete()">
54 62
                   删除
55 63
                 </el-button>
56 64
               </el-col>
@@ -58,8 +66,11 @@
58 66
                 <el-dropdown class="mt-[1px]">
59 67
                   <el-button plain type="info">
60 68
                     更多
61
-                    <el-icon class="el-icon--right"><arrow-down /></el-icon
62
-                  ></el-button>
69
+                    <el-icon class="el-icon--right">
70
+                      <arrow-down />
71
+                    </el-icon
72
+                    >
73
+                  </el-button>
63 74
                   <template #dropdown>
64 75
                     <el-dropdown-menu>
65 76
                       <el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item>
@@ -69,19 +80,26 @@
69 80
                   </template>
70 81
                 </el-dropdown>
71 82
               </el-col>
72
-              <right-toolbar v-model:showSearch="showSearch" :columns="columns" :search="true" @query-table="getList"></right-toolbar>
83
+              <right-toolbar v-model:showSearch="showSearch" :columns="columns" :search="true"
84
+                             @query-table="getList"></right-toolbar>
73 85
             </el-row>
74 86
           </template>
75
-          <el-table v-loading="loading" :data="userList" height="calc(100vh - 22rem)" @selection-change="handleSelectionChange">
87
+          <el-table v-loading="loading" :data="userList" height="calc(100vh - 22rem)"
88
+                    @selection-change="handleSelectionChange">
76 89
             <el-table-column type="selection" width="50" align="center" />
77 90
             <el-table-column v-if="columns[0].visible" key="userId" label="用户编号" align="center" prop="userId" />
78
-            <el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
79
-            <el-table-column v-if="columns[2].visible" key="nickName" label="用户昵称" align="center" prop="nickName" :show-overflow-tooltip="true" />
80
-            <el-table-column v-if="columns[3].visible" key="deptName" label="部门" align="center" prop="deptName" :show-overflow-tooltip="true" />
81
-            <el-table-column v-if="columns[4].visible" key="phonenumber" label="手机号码" align="center" prop="phonenumber" width="120" />
91
+            <el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName"
92
+                             :show-overflow-tooltip="true" />
93
+            <el-table-column v-if="columns[2].visible" key="nickName" label="用户昵称" align="center" prop="nickName"
94
+                             :show-overflow-tooltip="true" />
95
+            <el-table-column v-if="columns[3].visible" key="deptName" label="部门" align="center" prop="deptName"
96
+                             :show-overflow-tooltip="true" />
97
+            <el-table-column v-if="columns[4].visible" key="phonenumber" label="手机号码" align="center"
98
+                             prop="phonenumber" width="120" />
82 99
             <el-table-column v-if="columns[5].visible" key="status" label="状态" align="center">
83 100
               <template #default="scope">
84
-                <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
101
+                <el-switch v-model="scope.row.status" active-value="0" inactive-value="1"
102
+                           @change="handleStatusChange(scope.row)"></el-switch>
85 103
               </template>
86 104
             </el-table-column>
87 105
 
@@ -94,18 +112,22 @@
94 112
             <el-table-column label="操作" fixed="right" width="180" class-name="small-padding fixed-width">
95 113
               <template #default="scope">
96 114
                 <el-tooltip v-if="scope.row.userId !== 1" content="修改" placement="top">
97
-                  <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
115
+                  <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit"
116
+                             @click="handleUpdate(scope.row)"></el-button>
98 117
                 </el-tooltip>
99 118
                 <el-tooltip v-if="scope.row.userId !== 1" content="删除" placement="top">
100
-                  <el-button v-hasPermi="['system:user:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
119
+                  <el-button v-hasPermi="['system:user:remove']" link type="primary" icon="Delete"
120
+                             @click="handleDelete(scope.row)"></el-button>
101 121
                 </el-tooltip>
102 122
 
103 123
                 <el-tooltip v-if="scope.row.userId !== 1" content="重置密码" placement="top">
104
-                  <el-button v-hasPermi="['system:user:resetPwd']" link type="primary" icon="Key" @click="handleResetPwd(scope.row)"></el-button>
124
+                  <el-button v-hasPermi="['system:user:resetPwd']" link type="primary" icon="Key"
125
+                             @click="handleResetPwd(scope.row)"></el-button>
105 126
                 </el-tooltip>
106 127
 
107 128
                 <el-tooltip v-if="scope.row.userId !== 1" content="分配角色" placement="top">
108
-                  <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)"></el-button>
129
+                  <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="CircleCheck"
130
+                             @click="handleAuthRole(scope.row)"></el-button>
109 131
                 </el-tooltip>
110 132
               </template>
111 133
             </el-table-column>
@@ -120,7 +142,7 @@
120 142
         </el-card>
121 143
       </el-col>
122 144
     </el-row>
123
-    <!-- 添加或修改用户配置对话框 -->
145
+    <!-- 添加或修改用户对话框 -->
124 146
     <user-detail-form ref="userDetailFormRef" apped-to-body @success="getList" />
125 147
     <!-- 用户导入对话框 -->
126 148
     <el-dialog v-model="upload.open" :title="upload.title" width="400px" append-to-body>
@@ -142,9 +164,14 @@
142 164
         <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
143 165
         <template #tip>
144 166
           <div class="text-center el-upload__tip">
145
-            <div class="el-upload__tip"><el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据</div>
167
+            <div class="el-upload__tip">
168
+              <el-checkbox v-model="upload.updateSupport" />
169
+              是否更新已经存在的用户数据
170
+            </div>
146 171
             <span>仅允许导入xls、xlsx格式文件。</span>
147
-            <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
172
+            <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline"
173
+                     @click="importTemplate">下载模板
174
+            </el-link>
148 175
           </div>
149 176
         </template>
150 177
       </el-upload>
@@ -428,7 +455,7 @@ const handleFileSuccess = (response: any, file: UploadFile) => {
428 455
   upload.open = false;
429 456
   upload.isUploading = false;
430 457
   uploadRef.value?.handleRemove(file);
431
-  ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + '</div>', '导入结果', {
458
+  ElMessageBox.alert('<div style=\'overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;\'>' + response.msg + '</div>', '导入结果', {
432 459
     dangerouslyUseHTMLString: true
433 460
   });
434 461
   getList();
@@ -462,37 +489,12 @@ const cancel = () => {
462 489
 /** 增加/修改按钮操作 */
463 490
 const userDetailFormRef = ref();
464 491
 const handleOpenDetail = async (cmd: string, row?: UserVO) => {
465
-  const userId = row?.userId || ids.value[0];
466
-  const realNames = row?.realName || names.value;
492
+  let userId = undefined;
493
+  if (cmd === 'edit') {
494
+    userId = row?.userId || ids.value[0];
495
+  }
467 496
   userDetailFormRef?.value.open(cmd, userId);
468 497
 };
469
-/** 新增按钮操作 */
470
-// const handleAdd = async () => {
471
-//   reset();
472
-//   const { data } = await api.getUser();
473
-//   dialog.visible = true;
474
-//   dialog.title = '新增用户';
475
-//   await initTreeData();
476
-//   postOptions.value = data.posts;
477
-//   roleOptions.value = data.roles;
478
-//   form.value.password = initPassword.value.toString();
479
-// };
480
-
481
-/** 修改按钮操作 */
482
-// const handleUpdate = async (row?: UserForm) => {
483
-//   reset();
484
-//   const userId = row?.userId || ids.value[0];
485
-//   const { data } = await api.getUser(userId);
486
-//   dialog.visible = true;
487
-//   dialog.title = '修改用户';
488
-//   await initTreeData();
489
-//   Object.assign(form.value, data.user);
490
-//   postOptions.value = data.posts;
491
-//   roleOptions.value = data.roles;
492
-//   form.value.postIds = data.postIds;
493
-//   form.value.roleIds = data.roleIds;
494
-//   form.value.password = '';
495
-// };
496 498
 
497 499
 /** 提交按钮 */
498 500
 const submitForm = () => {