user.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. <template>
  2. <div>
  3. <warning-bar title="注:右上角头像下拉可切换角色" />
  4. <div class="gva-table-box">
  5. <div class="gva-btn-list">
  6. <el-button
  7. type="primary"
  8. icon="plus"
  9. @click="addUser"
  10. >新增用户</el-button>
  11. </div>
  12. <el-table
  13. :data="tableData"
  14. row-key="ID"
  15. style="width: 100%"
  16. >
  17. <el-table-column
  18. align="left"
  19. label="头像"
  20. min-width="75"
  21. >
  22. <template #default="scope">
  23. <CustomPic
  24. style="margin-top:8px"
  25. :pic-src="scope.row.headerImg"
  26. />
  27. </template>
  28. </el-table-column>
  29. <el-table-column
  30. align="left"
  31. label="ID"
  32. min-width="50"
  33. prop="ID"
  34. />
  35. <el-table-column
  36. align="left"
  37. label="用户名"
  38. min-width="150"
  39. prop="userName"
  40. />
  41. <el-table-column
  42. align="left"
  43. label="昵称"
  44. min-width="120"
  45. prop="nickName"
  46. />
  47. <el-table-column
  48. align="left"
  49. label="手机号"
  50. min-width="120"
  51. prop="phone"
  52. />
  53. <el-table-column
  54. align="left"
  55. label="邮箱"
  56. min-width="180"
  57. prop="email"
  58. />
  59. <el-table-column
  60. align="left"
  61. label="用户角色"
  62. min-width="200"
  63. >
  64. <template #default="scope">
  65. <el-cascader
  66. v-model="scope.row.authorityId"
  67. :options="authOptions"
  68. :show-all-levels="false"
  69. collapse-tags
  70. :props="{ checkStrictly: true,label:'authorityName',value:'authorityId',disabled:'disabled',emitPath:false}"
  71. :clearable="false"
  72. @visible-change="(flag)=>{changeAuthority(scope.row,flag,0)}"
  73. />
  74. </template>
  75. </el-table-column>
  76. <el-table-column
  77. align="left"
  78. label="项目分配"
  79. min-width="260"
  80. prop="project"
  81. >
  82. <template #default="scope">
  83. <el-select
  84. v-model="scope.row.projectIds"
  85. multiple
  86. filterable
  87. collapse-tags
  88. placeholder="分配项目"
  89. style="width: 240px"
  90. @change="changeProjectId(scope.row.ID,scope.row.projectIds)"
  91. >
  92. <el-option
  93. v-for="item in projects"
  94. :key="item.ID"
  95. :label="item.projectName"
  96. :value="item.ID"
  97. />
  98. </el-select>
  99. </template>
  100. </el-table-column>
  101. <el-table-column
  102. align="left"
  103. label="启用"
  104. min-width="80"
  105. >
  106. <template #default="scope">
  107. <el-switch
  108. v-model="scope.row.enable"
  109. inline-prompt
  110. :active-value="1"
  111. :inactive-value="2"
  112. @change="()=>{switchEnable(scope.row)}"
  113. />
  114. </template>
  115. </el-table-column>
  116. <el-table-column
  117. label="操作"
  118. min-width="250"
  119. fixed="right"
  120. >
  121. <template #default="scope">
  122. <el-button
  123. type="primary"
  124. link
  125. icon="delete"
  126. @click="deleteUserFunc(scope.row)"
  127. >删除</el-button>
  128. <el-button
  129. type="primary"
  130. link
  131. icon="edit"
  132. @click="openEdit(scope.row)"
  133. >编辑</el-button>
  134. <el-button
  135. type="primary"
  136. link
  137. icon="magic-stick"
  138. @click="resetPasswordFunc(scope.row)"
  139. >重置密码</el-button>
  140. </template>
  141. </el-table-column>
  142. </el-table>
  143. <div class="gva-pagination">
  144. <el-pagination
  145. :current-page="page"
  146. :page-size="pageSize"
  147. :page-sizes="[10, 30, 50, 100]"
  148. :total="total"
  149. layout="total, sizes, prev, pager, next, jumper"
  150. @current-change="handleCurrentChange"
  151. @size-change="handleSizeChange"
  152. />
  153. </div>
  154. </div>
  155. <el-drawer
  156. v-model="addUserDialog"
  157. size="60%"
  158. :show-close="false"
  159. :close-on-press-escape="false"
  160. :close-on-click-modal="false"
  161. >
  162. <template #header>
  163. <div class="flex justify-between items-center">
  164. <span class="text-lg">用户</span>
  165. <div>
  166. <el-button @click="closeAddUserDialog">取 消</el-button>
  167. <el-button
  168. type="primary"
  169. @click="enterAddUserDialog"
  170. >确 定</el-button>
  171. </div>
  172. </div>
  173. </template>
  174. <el-form
  175. ref="userForm"
  176. :rules="rules"
  177. :model="userInfo"
  178. label-width="80px"
  179. >
  180. <el-form-item
  181. v-if="dialogFlag === 'add'"
  182. label="用户名"
  183. prop="userName"
  184. >
  185. <el-input v-model="userInfo.userName" />
  186. </el-form-item>
  187. <el-form-item
  188. v-if="dialogFlag === 'add'"
  189. label="密码"
  190. prop="password"
  191. >
  192. <el-input v-model="userInfo.password" />
  193. </el-form-item>
  194. <el-form-item
  195. label="昵称"
  196. prop="nickName"
  197. >
  198. <el-input v-model="userInfo.nickName" />
  199. </el-form-item>
  200. <el-form-item
  201. label="手机号"
  202. prop="phone"
  203. >
  204. <el-input v-model="userInfo.phone" />
  205. </el-form-item>
  206. <el-form-item
  207. label="邮箱"
  208. prop="email"
  209. >
  210. <el-input v-model="userInfo.email" />
  211. </el-form-item>
  212. <el-form-item
  213. label="用户角色"
  214. prop="authorityId"
  215. >
  216. <el-cascader
  217. v-model="userInfo.authorityId"
  218. style="width:100%"
  219. :options="authOptions"
  220. :show-all-levels="false"
  221. :props="{ checkStrictly: true,label:'authorityName',value:'authorityId',disabled:'disabled',emitPath:false}"
  222. :clearable="false"
  223. />
  224. </el-form-item>
  225. <el-form-item
  226. label="启用"
  227. prop="disabled"
  228. >
  229. <el-switch
  230. v-model="userInfo.enable"
  231. inline-prompt
  232. :active-value="1"
  233. :inactive-value="2"
  234. />
  235. </el-form-item>
  236. <el-form-item
  237. label="头像"
  238. label-width="80px"
  239. >
  240. <SelectImage
  241. v-model="userInfo.headerImg"
  242. />
  243. </el-form-item>
  244. </el-form>
  245. </el-drawer>
  246. </div>
  247. </template>
  248. <script setup>
  249. import {
  250. getUserList,
  251. setUserAuthorities,
  252. register,
  253. deleteUser
  254. } from '@/api/user'
  255. import { getAuthorityList } from '@/api/authority'
  256. import CustomPic from '@/components/customPic/index.vue'
  257. import WarningBar from '@/components/warningBar/warningBar.vue'
  258. import { setUserInfo, resetPassword, getProjectList, changeProjects } from '@/api/user.js'
  259. import { nextTick, ref } from 'vue'
  260. import { ElMessage, ElMessageBox } from 'element-plus'
  261. import SelectImage from '@/components/selectImage/selectImage.vue'
  262. defineOptions({
  263. name: 'User',
  264. })
  265. const path = ref(import.meta.env.VITE_BASE_API + '/')
  266. // 初始化相关
  267. const setAuthorityOptions = (AuthorityData, optionsData) => {
  268. AuthorityData &&
  269. AuthorityData.forEach(item => {
  270. if (item.children && item.children.length) {
  271. const option = {
  272. authorityId: item.authorityId,
  273. authorityName: item.authorityName,
  274. children: []
  275. }
  276. setAuthorityOptions(item.children, option.children)
  277. optionsData.push(option)
  278. } else {
  279. const option = {
  280. authorityId: item.authorityId,
  281. authorityName: item.authorityName
  282. }
  283. optionsData.push(option)
  284. }
  285. })
  286. }
  287. const page = ref(1)
  288. const total = ref(0)
  289. const pageSize = ref(10)
  290. const tableData = ref([])
  291. // 分页
  292. const handleSizeChange = (val) => {
  293. pageSize.value = val
  294. getTableData()
  295. }
  296. const handleCurrentChange = (val) => {
  297. page.value = val
  298. getTableData()
  299. }
  300. // 查询
  301. const getTableData = async() => {
  302. const table = await getUserList({ page: page.value, pageSize: pageSize.value })
  303. if (table.code === 0) {
  304. tableData.value = table.data.list
  305. total.value = table.data.total
  306. page.value = table.data.page
  307. pageSize.value = table.data.pageSize
  308. }
  309. tableData.value && tableData.value.forEach((user) => {
  310. user.projectIds = user.projects && user.projects.map(i => {
  311. return i.ID
  312. })
  313. })
  314. }
  315. const projects = ref()
  316. const changeProjectId = async(userId, arr) => {
  317. var res = await changeProjects({ Id: userId, ProIds: arr })
  318. if (res.code === 0) {
  319. ElMessage({
  320. type: 'success',
  321. message: res.msg,
  322. })
  323. } else {
  324. ElMessage({
  325. type: 'error',
  326. message: res.msg,
  327. })
  328. }
  329. }
  330. const initPage = async() => {
  331. getTableData()
  332. const res = await getAuthorityList({ page: 1, pageSize: 999 })
  333. setOptions(res.data.list)
  334. const response = await getProjectList()
  335. projects.value = response.data
  336. }
  337. initPage()
  338. const resetPasswordFunc = (row) => {
  339. ElMessageBox.confirm(
  340. '是否将此用户密码重置为123456?',
  341. '警告',
  342. {
  343. confirmButtonText: '确定',
  344. cancelButtonText: '取消',
  345. type: 'warning',
  346. }
  347. ).then(async() => {
  348. const res = await resetPassword({
  349. ID: row.ID,
  350. })
  351. if (res.code === 0) {
  352. ElMessage({
  353. type: 'success',
  354. message: res.msg,
  355. })
  356. } else {
  357. ElMessage({
  358. type: 'error',
  359. message: res.msg,
  360. })
  361. }
  362. })
  363. }
  364. const authOptions = ref([])
  365. const setOptions = (authData) => {
  366. authOptions.value = []
  367. setAuthorityOptions(authData, authOptions.value)
  368. }
  369. const deleteUserFunc = async(row) => {
  370. ElMessageBox.confirm('确定要删除吗?', '提示', {
  371. confirmButtonText: '确定',
  372. cancelButtonText: '取消',
  373. type: 'warning'
  374. }).then(async() => {
  375. const res = await deleteUser({ id: row.ID })
  376. if (res.code === 0) {
  377. ElMessage.success('删除成功')
  378. await getTableData()
  379. }
  380. })
  381. }
  382. // 弹窗相关
  383. const userInfo = ref({
  384. username: '',
  385. password: '',
  386. nickName: '',
  387. headerImg: '',
  388. authorityId: '',
  389. enable: 1,
  390. })
  391. const rules = ref({
  392. userName: [
  393. { required: true, message: '请输入用户名', trigger: 'blur' },
  394. { min: 5, message: '最低5位字符', trigger: 'blur' }
  395. ],
  396. password: [
  397. { required: true, message: '请输入用户密码', trigger: 'blur' },
  398. { min: 6, message: '最低6位字符', trigger: 'blur' }
  399. ],
  400. nickName: [
  401. { required: true, message: '请输入用户昵称', trigger: 'blur' }
  402. ],
  403. phone: [
  404. { pattern: /^1([38][0-9]|4[014-9]|[59][0-35-9]|6[2567]|7[0-8])\d{8}$/, message: '请输入合法手机号', trigger: 'blur' },
  405. ],
  406. email: [
  407. { pattern: /^([0-9A-Za-z\-_.]+)@([0-9a-z]+\.[a-z]{2,3}(\.[a-z]{2})?)$/g, message: '请输入正确的邮箱', trigger: 'blur' },
  408. ],
  409. authorityId: [
  410. { required: true, message: '请选择用户角色', trigger: 'blur' }
  411. ]
  412. })
  413. const userForm = ref(null)
  414. const enterAddUserDialog = async() => {
  415. userForm.value.validate(async valid => {
  416. if (valid) {
  417. const req = {
  418. ...userInfo.value
  419. }
  420. if (dialogFlag.value === 'add') {
  421. const res = await register(req)
  422. if (res.code === 0) {
  423. ElMessage({ type: 'success', message: '创建成功' })
  424. await getTableData()
  425. closeAddUserDialog()
  426. }
  427. }
  428. if (dialogFlag.value === 'edit') {
  429. const res = await setUserInfo(req)
  430. if (res.code === 0) {
  431. ElMessage({ type: 'success', message: '编辑成功' })
  432. await getTableData()
  433. closeAddUserDialog()
  434. }
  435. }
  436. }
  437. })
  438. }
  439. const addUserDialog = ref(false)
  440. const closeAddUserDialog = () => {
  441. userForm.value.resetFields()
  442. userInfo.value.headerImg = ''
  443. userInfo.value.authorityIds = []
  444. addUserDialog.value = false
  445. }
  446. const dialogFlag = ref('add')
  447. const addUser = () => {
  448. dialogFlag.value = 'add'
  449. addUserDialog.value = true
  450. }
  451. const tempAuth = {}
  452. const changeAuthority = async(row, flag, removeAuth) => {
  453. await nextTick()
  454. const res = await setUserAuthorities({
  455. ID: row.ID,
  456. authorityId: row.authorityId
  457. })
  458. if (res.code === 0) {
  459. ElMessage({ type: 'success', message: '角色设置成功' })
  460. } else {
  461. if (!removeAuth) {
  462. row.authorityIds = [...tempAuth[row.ID]]
  463. delete tempAuth[row.ID]
  464. } else {
  465. row.authorityIds = [removeAuth, ...row.authorityIds]
  466. }
  467. }
  468. }
  469. const openEdit = (row) => {
  470. dialogFlag.value = 'edit'
  471. userInfo.value = JSON.parse(JSON.stringify(row))
  472. addUserDialog.value = true
  473. }
  474. const switchEnable = async(row) => {
  475. userInfo.value = JSON.parse(JSON.stringify(row))
  476. await nextTick()
  477. const req = {
  478. ...userInfo.value
  479. }
  480. const res = await setUserInfo(req)
  481. if (res.code === 0) {
  482. ElMessage({ type: 'success', message: `${req.enable === 2 ? '禁用' : '启用'}成功` })
  483. await getTableData()
  484. userInfo.value.headerImg = ''
  485. userInfo.value.authorityIds = []
  486. }
  487. }
  488. </script>
  489. <style lang="scss">
  490. .header-img-box {
  491. @apply w-52 h-52 border border-solid border-gray-300 rounded-xl flex justify-center items-center cursor-pointer;
  492. }
  493. </style>