index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. <script setup lang="ts" name="User">
  2. import apis from "@/api"
  3. import type { VbFormItem } from "@/components/form/models"
  4. import AuthRole from "./_authRole.vue"
  5. import { permissionNames } from "@/core/services/PermissionNames"
  6. import message from "@/core/utils/message"
  7. import { download } from "@/core/services/RequestService"
  8. const deptTreeRef = ref()
  9. const deptOptions = ref<any>()
  10. function loadDept() {
  11. apis.system.userApi.deptTreeSelect().then((res) => {
  12. deptOptions.value = res.data
  13. })
  14. }
  15. const tableRef = ref()
  16. const tableOpts = reactive({
  17. permission: permissionNames.SystemUser,
  18. columns: [
  19. { field: "userId", name: `用户编号`, width: 85 },
  20. { field: "userName", name: `用户名称` },
  21. { field: "nickName", name: `用户昵称` },
  22. { field: "deptName", name: `部门` },
  23. { field: "phonenumber", name: `手机号码` },
  24. { field: "status", name: `状态` },
  25. { field: "createTime", name: `创建时间` },
  26. { field: "actions", name: `操作` },
  27. ],
  28. queryParams: {
  29. userName: undefined,
  30. phonenumber: undefined,
  31. status: undefined,
  32. deptId: undefined,
  33. dateRange: [],
  34. },
  35. searchFormItems: [
  36. {
  37. field: "userName",
  38. label: "用户名称",
  39. placeholder: "请输入用户名称",
  40. required: false,
  41. component: "i",
  42. listeners: {
  43. keyup: (e: KeyboardEvent) => {
  44. if (e.code == "Enter") {
  45. handleQuery()
  46. }
  47. },
  48. },
  49. span: 4,
  50. },
  51. {
  52. field: "phonenumber",
  53. label: "手机号码",
  54. placeholder: "请输入手机号码",
  55. required: false,
  56. component: "I",
  57. listeners: {
  58. keyup: (e: KeyboardEvent) => {
  59. if (e.code == "Enter") {
  60. handleQuery()
  61. }
  62. },
  63. },
  64. span: 4,
  65. },
  66. {
  67. field: "status",
  68. label: "用户状态",
  69. required: false,
  70. component: "Dict",
  71. span: 5,
  72. props: {
  73. placeholder: "请选择用户状态",
  74. dictType: "sys_normal_disable",
  75. },
  76. },
  77. {
  78. field: "dateRange",
  79. label: "创建时间",
  80. placeholder: "请选择创建时间",
  81. required: false,
  82. component: "d",
  83. span: 6,
  84. props: {
  85. placeholder: "请选择创建时间",
  86. valueFormat: "YYYY-MM-DD",
  87. type: "daterange",
  88. rangeSeparator: "-",
  89. startPlaceholder: "开始日期",
  90. endPlaceholder: "结束日期",
  91. },
  92. listeners: {
  93. change: (v: any) => {
  94. queryParams.value.dateRange = v
  95. },
  96. },
  97. },
  98. ],
  99. handleFuns: {
  100. handleCreate,
  101. handleUpdate: () => {
  102. const row = tableRef.value.getSelected()
  103. handleUpdate(row)
  104. },
  105. handleDelete: () => {
  106. const rows = tableRef.value.getSelecteds()
  107. handleDelete(rows)
  108. },
  109. handleImport,
  110. handleExport,
  111. },
  112. })
  113. const { permission, columns, queryParams, searchFormItems, handleFuns } = toRefs(tableOpts)
  114. function handleQuery() {
  115. addDateRange(queryParams.value, queryParams.value.dateRange)
  116. tableRef.value?.search()
  117. }
  118. function resetQuery() {
  119. queryParams.value.dateRange = []
  120. addDateRange(queryParams.value, queryParams.value.dateRange)
  121. queryParams.value.deptId = undefined
  122. deptTreeRef.value.setCurrentKey(null)
  123. }
  124. const userPosts = ref([])
  125. const userRoles = ref([])
  126. const modalRef = ref()
  127. const modalOpts = reactive({
  128. title: "用户",
  129. formItems: [
  130. {
  131. field: "nickName",
  132. label: "用户昵称",
  133. placeholder: "请输入用户昵称",
  134. required: true,
  135. component: "i",
  136. span: 12,
  137. },
  138. {
  139. field: "deptId",
  140. label: "归属部门",
  141. class: "w-100",
  142. required: true,
  143. data: () => deptOptions.value,
  144. component: "vst",
  145. props: {
  146. //dataFun: loadDept,
  147. placeholder: "请选择归属部门",
  148. },
  149. span: 12,
  150. },
  151. {
  152. field: "phonenumber",
  153. label: "手机号码",
  154. placeholder: "请输入手机号码",
  155. required: true,
  156. component: "i",
  157. props: {
  158. maxlength: 11,
  159. },
  160. span: 12,
  161. },
  162. {
  163. field: "email",
  164. label: "邮箱",
  165. placeholder: "请输入邮箱",
  166. required: true,
  167. component: "i",
  168. rules: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
  169. props: {
  170. maxlength: 11,
  171. },
  172. span: 12,
  173. },
  174. {
  175. field: "userName",
  176. label: "用户名称",
  177. placeholder: "请输入用户名称",
  178. required: true,
  179. rules: [{ min: 2, max: 20, message: "用户名称长度必须介于 2 和 20 之间", trigger: "blur" }],
  180. span: 12,
  181. },
  182. {
  183. field: "password",
  184. label: "用户密码",
  185. type: "password",
  186. placeholder: "请输入用户密码",
  187. required: false,
  188. rules: [{ min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" }],
  189. span: 12,
  190. },
  191. {
  192. field: "sex",
  193. label: "用户性别",
  194. class: "w-100",
  195. component: "dict",
  196. props: {
  197. placeholder: "请选择用户性别",
  198. dictType: "sys_user_sex",
  199. },
  200. span: 12,
  201. },
  202. {
  203. field: "status",
  204. label: "用户状态",
  205. class: "w-100",
  206. component: "dict",
  207. props: {
  208. placeholder: "请选择用户状态",
  209. dictType: "sys_normal_disable",
  210. },
  211. span: 12,
  212. },
  213. {
  214. field: "postIds",
  215. label: "用户岗位",
  216. class: "w-100",
  217. component: "vs",
  218. data: () => userPosts.value,
  219. placeholder: "请选择用户岗位",
  220. span: 12,
  221. props: {
  222. //multiple: true,
  223. },
  224. },
  225. {
  226. field: "roleIds",
  227. //id: () => role_id.value,
  228. label: "用户角色",
  229. class: "w-100",
  230. placeholder: "请选择用户角色",
  231. data: () => userRoles.value,
  232. component: "vs",
  233. props: {
  234. //dataFun: loadUserRole,
  235. multiple: true,
  236. },
  237. span: 12,
  238. },
  239. {
  240. field: "remark",
  241. label: "备注",
  242. type: "textarea",
  243. placeholder: "请输入备注内容",
  244. required: false,
  245. component: "i",
  246. span: 24,
  247. },
  248. ],
  249. emptyFormData: {
  250. userId: undefined,
  251. deptId: undefined,
  252. userName: undefined,
  253. nickName: undefined,
  254. password: undefined,
  255. phonenumber: undefined,
  256. email: undefined,
  257. sex: "0",
  258. status: "0",
  259. remark: undefined,
  260. postIds: [],
  261. roleIds: [],
  262. },
  263. })
  264. const { title: modalTitle, emptyFormData, formItems } = toRefs(modalOpts)
  265. const form = ref(emptyFormData)
  266. function reset() {
  267. form.value = emptyFormData.value
  268. }
  269. const initPassword = ref(undefined)
  270. function handleCreate() {
  271. console.log("C")
  272. modalTitle.value = "新增用户"
  273. reset()
  274. apis.system.userApi.getUser().then((res: any) => {
  275. setOptions(res)
  276. form.value.password = initPassword.value
  277. modalRef.value.show()
  278. })
  279. }
  280. function handleUpdate(row: any) {
  281. modalTitle.value = "编辑用户"
  282. //row = row ||
  283. const userId = row.userId
  284. console.log("U", userId, row)
  285. apis.system.userApi.getUser(userId).then((res: any) => {
  286. setOptions(res)
  287. form.value = res.data
  288. form.value.postIds = res.postIds
  289. form.value.roleIds = res.roleIds
  290. form.value.password = undefined
  291. modalRef.value.show()
  292. })
  293. }
  294. function setOptions(data: any) {
  295. userPosts.value = data.posts.map((v: any) => {
  296. return {
  297. label: v.postName,
  298. value: v.postId,
  299. disabled: v.status == 1,
  300. }
  301. })
  302. userRoles.value = data.roles.map((v: any) => {
  303. return {
  304. label: v.roleName,
  305. value: v.roleId,
  306. disabled: v.status == 1,
  307. }
  308. })
  309. }
  310. function submitForm() {
  311. if (form.value.userId != undefined) {
  312. apis.system.userApi.updateUser(form.value).then(() => {
  313. message.msgSuccess("修改成功")
  314. handleQuery()
  315. })
  316. } else {
  317. apis.system.userApi.addUser(form.value).then(() => {
  318. message.msgSuccess("新增成功")
  319. handleQuery()
  320. })
  321. }
  322. }
  323. function handleDelete(rows?: Array<any>) {
  324. rows = rows || tableRef.value.getSelecteds()
  325. if (!rows) {
  326. return
  327. }
  328. const userIds = rows.map((v) => v.userId)
  329. message
  330. .confirm('是否确认删除用户编号为"' + userIds.join(",") + '"的数据项?')
  331. .then(() => {
  332. apis.system.userApi.delUser(userIds).then(() => {
  333. handleQuery()
  334. })
  335. })
  336. .catch(() => {
  337. //
  338. })
  339. }
  340. const uploadModalRef = ref<any>()
  341. const upload = {
  342. // 弹出层标题
  343. title: "导入数据",
  344. // 上传的地址
  345. url: import.meta.env.VITE_APP_BASE_API + apis.system.userApi.importUrl,
  346. accept: ".xlsx, .xls",
  347. templateUrl: apis.system.userApi.importTemplateUrl,
  348. templateName: "USER",
  349. }
  350. function handleImport() {
  351. uploadModalRef.value.show()
  352. }
  353. /** 文件上传成功处理 */
  354. const handleFileSuccess = () => {
  355. handleQuery()
  356. }
  357. function handleExport() {
  358. download(apis.system.userApi.exportUrl, { ...queryParams }, `USER_${new Date().getTime()}.xlsx`)
  359. }
  360. /** 用户状态修改 */
  361. function handleStatusChange(row: any) {
  362. const text = row.status === "0" ? "启用" : "停用"
  363. message
  364. .confirm('确认要"' + text + '""' + row.userName + '"用户吗?')
  365. .then(function () {
  366. return apis.system.userApi.changeUserStatus(row.userId, row.status)
  367. })
  368. .then(() => {
  369. message.msgSuccess(text + "成功")
  370. })
  371. .catch(function () {
  372. row.status = row.status === "0" ? "1" : "0"
  373. })
  374. }
  375. function handleResetPwd(row: any) {
  376. console.log("RP==>", row)
  377. message
  378. .prompt('请输入"' + row.userName + '"的新密码', "提示", {
  379. confirmButtonText: "确定",
  380. cancelButtonText: "取消",
  381. closeOnClickModal: false,
  382. inputPattern: /^.{5,20}$/,
  383. inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
  384. })
  385. .then(({ value }) => {
  386. apis.system.userApi.resetUserPwd(row.userId, value).then(() => {
  387. message.msgSuccess("修改成功,新密码是:" + value)
  388. })
  389. })
  390. .catch(() => {
  391. //
  392. })
  393. }
  394. const authRoleModalRef = ref()
  395. const authRoleRef = ref()
  396. const authRoleUserId = ref()
  397. function handleAuthRole(row: any) {
  398. console.log("AR==>", row)
  399. authRoleUserId.value = row.userId
  400. authRoleModalRef.value.show()
  401. }
  402. function submitAuthRole() {
  403. const roleIds = authRoleRef.value.getSelectedRoleIds()
  404. console.log("ROLEIDS", roleIds)
  405. }
  406. loadDept()
  407. // onMounted(() => {
  408. // //console.log("PROXY", proxy?.$refs)
  409. // })
  410. </script>
  411. <template>
  412. <div class="app-container">
  413. <el-row :gutter="20">
  414. <!--部门数据-->
  415. <el-col :span="4" :xs="24">
  416. <DeptTree v-model="queryParams.deptId" :data="deptOptions" @node-click="handleQuery"></DeptTree>
  417. </el-col>
  418. <!--用户数据-->
  419. <el-col :span="20" :xs="24">
  420. <VbDataTable
  421. ref="tableRef"
  422. :handle-perm="permission"
  423. :handle-funs="handleFuns"
  424. :search-form-items="(searchFormItems as Array<VbFormItem>)"
  425. :header="columns"
  426. :query-params="queryParams"
  427. :url="apis.system.userApi.tableUrl"
  428. :check-multiple="true"
  429. :reset-search-form-fun="resetQuery"
  430. :custom-search-fun="handleQuery"
  431. :show-right-toolbar="true"
  432. :auto-search="false"
  433. >
  434. <template #deptName="{ row }">
  435. {{ row.dept.deptName }}
  436. </template>
  437. <template #status="{ row }">
  438. <el-switch
  439. v-model="row.status"
  440. active-value="0"
  441. inactive-value="1"
  442. @change="handleStatusChange(row)"
  443. ></el-switch>
  444. </template>
  445. <template #actions="{ row }">
  446. <span v-if="row.userId == 1" class="text-muted">-</span>
  447. <template v-else>
  448. <vb-tooltip content="修改" placement="top">
  449. <el-button
  450. link
  451. type="primary"
  452. @click="handleUpdate(row)"
  453. v-hasPermission="permissionNames.SystemUserEdit"
  454. >
  455. <template #icon>
  456. <KTIcon icon-name="notepad-edit" icon-type="duotone" class="fs-3"></KTIcon>
  457. </template>
  458. </el-button>
  459. </vb-tooltip>
  460. <vb-tooltip content="删除" placement="top">
  461. <el-button
  462. link
  463. type="primary"
  464. @click="handleDelete([row])"
  465. v-hasPermission="permissionNames.SystemUserRemove"
  466. >
  467. <template #icon>
  468. <KTIcon icon-name="trash-square" icon-type="duotone" class="fs-3"></KTIcon>
  469. </template>
  470. </el-button>
  471. </vb-tooltip>
  472. <vb-tooltip content="重置密码" placement="top">
  473. <el-button
  474. link
  475. type="primary"
  476. @click="handleResetPwd(row)"
  477. v-hasPermission="permissionNames.SystemUserResetpwd"
  478. >
  479. <template #icon>
  480. <KTIcon icon-name="key-square" icon-type="duotone" class="fs-3"></KTIcon>
  481. </template>
  482. </el-button>
  483. </vb-tooltip>
  484. <vb-tooltip content="分配角色" placement="top">
  485. <el-button
  486. link
  487. type="primary"
  488. @click="handleAuthRole(row)"
  489. v-hasPermission="permissionNames.SystemUserEdit"
  490. >
  491. <template #icon>
  492. <KTIcon icon-name="user-square" icon-type="duotone" class="fs-3"></KTIcon>
  493. </template>
  494. </el-button>
  495. </vb-tooltip>
  496. </template>
  497. </template>
  498. </VbDataTable>
  499. </el-col>
  500. </el-row>
  501. <VbModal
  502. v-model:modal="modalRef"
  503. :title="modalTitle"
  504. :form-items="(formItems as Array<VbFormItem>)"
  505. :form-data="form"
  506. @confirm="submitForm"
  507. append-to-body
  508. ></VbModal>
  509. <ImportModal ref="uploadModalRef" :options="upload" @on-success="handleFileSuccess" append-to-body></ImportModal>
  510. <VbModal v-model:modal="authRoleModalRef" title="分配角色" @confirm="submitAuthRole" append-to-body>
  511. <template #body>
  512. <AuthRole ref="authRoleRef" :user-id="authRoleUserId"></AuthRole>
  513. </template>
  514. </VbModal>
  515. </div>
  516. </template>