index.vue 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. <template>
  2. <div class="flex direction-column full user-manage">
  3. <div
  4. class="flex items-center p-l-base p-r-base p-t-medium-base fill-blank filter-form"
  5. :class="{ 'is-expand': expand }"
  6. style="padding-bottom: 10px"
  7. >
  8. <base-form
  9. ref="formRef"
  10. class="full-w"
  11. size="small"
  12. :label-width="'60px'"
  13. :disabled="loading"
  14. :model="model"
  15. :transition="false"
  16. :rows="rows"
  17. :items="formItems"
  18. >
  19. <template #form-item-button-group>
  20. <el-button :loading="loading" type="primary" @click="onSearch">查询</el-button>
  21. <span class="m-l-auto">
  22. <el-button link custom-1 @click="toggleExpand">
  23. 更多
  24. <el-icon class="collapse-icon">
  25. <arrow-right />
  26. </el-icon>
  27. </el-button>
  28. </span>
  29. </template>
  30. </base-form>
  31. </div>
  32. <div class="flex-1 p-base">
  33. <el-card table>
  34. <div class="flex items-center m-b-base">
  35. <el-button size="small" type="primary" @click="onAddUser">新增</el-button>
  36. <el-button size="small" type="primary" @click="onBulkAddUser">批量新增</el-button>
  37. <!-- <el-popconfirm
  38. v-if="hasSelected"
  39. :width="'220px'"
  40. hide-icon
  41. title="是否重置选中用户密码?"
  42. @confirm="handleResetPwd"
  43. >
  44. <template #reference>
  45. <el-button size="small" type="primary">重置密码</el-button>
  46. </template>
  47. </el-popconfirm> -->
  48. <el-button size="small" type="primary" @click="checkSelected('reset', 'mult')">重置密码</el-button>
  49. <el-popconfirm
  50. v-if="hasSelected"
  51. :width="'220px'"
  52. hide-icon
  53. title="是否禁用选中用户?"
  54. @confirm="handleDisableUsers"
  55. >
  56. <template #reference>
  57. <el-button size="small" type="primary">禁用</el-button>
  58. </template>
  59. </el-popconfirm>
  60. <el-button v-else size="small" type="primary" @click="checkSelected('disabled')">禁用</el-button>
  61. <el-button size="small" custom-1 @click="onExportUsers">导出</el-button>
  62. <el-upload
  63. ref="upload"
  64. v-model:file-list="fileList"
  65. :limit="1"
  66. :show-file-list="false"
  67. :on-exceed="onExceed"
  68. :auto-upload="false"
  69. >
  70. <el-button size="small" custom-1 class="m-l-base" :loading="importUsersLoading">导入姓名</el-button>
  71. </el-upload>
  72. <!-- <el-link class="m-l-base" type="primary" @click="downTpl">导入姓名模板下载</el-link> -->
  73. </div>
  74. <base-table
  75. ref="tableRef"
  76. border
  77. stripe
  78. size="small"
  79. :columns="columns"
  80. :data="data"
  81. height="-webkit-fill-available"
  82. @selection-change="onSectionChange"
  83. >
  84. <template #column-operation="{ row }">
  85. <el-button type="primary" link @click="onEditUser(row)">修改</el-button>
  86. <el-button type="primary" link @click="onSingleResetUserPwd(row)">重置密码</el-button>
  87. <!-- <el-popconfirm :width="'220px'" hide-icon title="确认重置用户密码?" @confirm="onSingleResetUserPwd(row)">
  88. <template #reference>
  89. <el-button type="primary" link>重置密码</el-button>
  90. </template>
  91. </el-popconfirm> -->
  92. <el-popconfirm
  93. :width="'220px'"
  94. hide-icon
  95. :title="`确认${row.enable ? '禁用' : '启用'}用户?`"
  96. @confirm="onDisableUser(row)"
  97. >
  98. <template #reference>
  99. <el-button type="primary" link>
  100. {{ row.enable ? '禁用' : '启用' }}
  101. </el-button>
  102. </template>
  103. </el-popconfirm>
  104. </template>
  105. </base-table>
  106. <el-pagination v-bind="pagination" v-model:current-page="currentPage" background right></el-pagination>
  107. </el-card>
  108. </div>
  109. <base-dialog :width="380" title="导入/导出" destroy-on-close>
  110. <template #footer>
  111. <confirm-button @confirm="handleResetPwd" @cancel="() => {}"></confirm-button>
  112. </template>
  113. </base-dialog>
  114. <base-dialog
  115. v-model="showResetPwdDialog"
  116. :width="300"
  117. title="重置密码"
  118. class="reset-pwd"
  119. destroy-on-close
  120. @close="newPwd = ''"
  121. >
  122. <el-input v-model="newPwd" type="password" placeholder="请输入新的密码" clearable></el-input>
  123. <template #footer>
  124. <confirm-button
  125. :disabled="!newPwd"
  126. @confirm="handleResetPwd"
  127. @cancel="showResetPwdDialog = false"
  128. ></confirm-button>
  129. </template>
  130. </base-dialog>
  131. </div>
  132. </template>
  133. <script setup lang="ts" name="UserManage">
  134. /** 用户管理 */
  135. import { ref, reactive, watch } from 'vue'
  136. import {
  137. ElButton,
  138. ElPopconfirm,
  139. ElCard,
  140. ElIcon,
  141. ElPagination,
  142. ElMessage,
  143. ElInput,
  144. ElLink,
  145. ElUpload,
  146. } from 'element-plus'
  147. import { ArrowRight } from '@element-plus/icons-vue'
  148. import { useRouter } from 'vue-router'
  149. import BaseDialog from '@/components/element/BaseDialog.vue'
  150. import BaseForm from '@/components/element/BaseForm.vue'
  151. import BaseTable from '@/components/element/BaseTable.vue'
  152. import ConfirmButton from '@/components/common/ConfirmButton.vue'
  153. import useFetch from '@/hooks/useFetch'
  154. import useUserManageFilter from './hooks/useUserManageFilter'
  155. import useUserManageTable from './hooks/useUserManageTable'
  156. import useUploadFile from '@/hooks/useUploadFile'
  157. import useVW from '@/hooks/useVW'
  158. import type { ExtractMultipleApiResponse } from '@/api/api'
  159. const newPwd = ref('')
  160. const { push } = useRouter()
  161. const { fileList, upload, percentage, setPercentage, onExceed } = useUploadFile()
  162. const { fetch: importUsersFile, loading: importUsersLoading } = useFetch('importUsersFile')
  163. const importUsersModel = reactive<any>({
  164. file: void 0,
  165. })
  166. watch(
  167. fileList,
  168. () => {
  169. importUsersModel.file = fileList.value?.[0]?.raw
  170. importUsersFile(importUsersModel).then((res: any) => {
  171. // ElMessage.success('导入用户成功')
  172. if (!res.hasError) {
  173. ElMessage.success('导入用户成功')
  174. } else {
  175. ElMessage.error('导入失败,详见“任务信息报告”')
  176. }
  177. onSearch()
  178. })
  179. },
  180. { deep: true }
  181. )
  182. const { formRef, model, items: formItems, rows, expand, toggleExpand } = useUserManageFilter()
  183. const {
  184. pagination,
  185. currentPage,
  186. loading,
  187. data,
  188. columns,
  189. onSectionChange,
  190. hasSelected,
  191. selectedList,
  192. fetchTable,
  193. tableRef,
  194. } = useUserManageTable(model)
  195. const { fetch: resetPwdFetch } = useFetch('resetUsersPwd')
  196. const { fetch: toggleFetch } = useFetch('toggleEnableUsers')
  197. /** 查询按钮 */
  198. function onSearch() {
  199. fetchTable()
  200. }
  201. /** 新增按钮 */
  202. function onAddUser() {
  203. push({ name: 'EditUser' })
  204. }
  205. /** 批量新增按钮 */
  206. function onBulkAddUser() {
  207. push({ name: 'BulkAddUser' })
  208. }
  209. const showResetPwdDialog = ref(false)
  210. const resetPwdType = ref<any>('')
  211. function checkSelected(type: 'reset' | 'disabled', resetType?: string) {
  212. if (!selectedList.length) {
  213. return ElMessage.warning(`请选择需要${type === 'reset' ? '重置密码' : '禁用'}的用户`)
  214. }
  215. if (type === 'reset') {
  216. showResetPwdDialog.value = true
  217. resetPwdType.value = resetType
  218. }
  219. }
  220. /** 重置密码 */
  221. async function handleResetPwd() {
  222. if (!selectedList.length) {
  223. return void ElMessage.warning(`请选择需要重置密码的用户`)
  224. }
  225. /** valid password */
  226. /** submit */
  227. try {
  228. await resetPwdFetch({ userIds: selectedList.map((d) => d.id), password: newPwd.value })
  229. ElMessage.success(`修改成功`)
  230. if (resetPwdType.value === 'single') {
  231. onSectionChange(selectionSelectedList)
  232. }
  233. showResetPwdDialog.value = false
  234. } catch (error) {
  235. console.error(error)
  236. if (resetPwdType.value === 'single') {
  237. onSectionChange(selectionSelectedList)
  238. }
  239. }
  240. }
  241. /** 禁用用户 */
  242. async function handleDisableUsers() {
  243. if (!selectedList.length) {
  244. return void ElMessage.warning(`请选择需要禁用的用户`)
  245. }
  246. /** submit */
  247. try {
  248. await toggleFetch({ ids: selectedList.map((d) => d.id), enable: false })
  249. ElMessage.success(`禁用成功`)
  250. fetchTable()
  251. } catch (error) {
  252. console.error(error)
  253. }
  254. }
  255. /** 导出按钮 */
  256. function onExportUsers() {
  257. useFetch('exportUser').fetch(model)
  258. }
  259. function onImportUsers() {
  260. alert(1)
  261. }
  262. function downTpl() {
  263. useFetch('importUsersTemplate', 'get').fetch()
  264. }
  265. /** table column 修改用户 */
  266. function onEditUser(row: ExtractMultipleApiResponse<'getUserList'>) {
  267. push({ name: 'EditUser', params: { id: row.id } })
  268. }
  269. let selectionSelectedList = selectedList.slice(0)
  270. /** table column 重置密码 */
  271. function onSingleResetUserPwd(row: ExtractMultipleApiResponse<'getUserList'>) {
  272. selectionSelectedList = selectedList.slice(0)
  273. onSectionChange([row])
  274. // handleResetPwd().finally(() => {
  275. // onSectionChange(selectionSelectedList)
  276. // })
  277. checkSelected('reset', 'single')
  278. }
  279. /** table column 禁用 */
  280. function onDisableUser(row: ExtractMultipleApiResponse<'getUserList'>) {
  281. row.id && toggleFetch({ enable: !row.enable, ids: [row.id] }).then(fetchTable)
  282. }
  283. onSearch()
  284. </script>
  285. <style scoped lang="scss">
  286. .user-manage {
  287. .filter-form {
  288. border-bottom: $OnePixelLine;
  289. }
  290. .collapse-icon {
  291. transition: transform var(--el-transition-duration);
  292. font-weight: 300;
  293. }
  294. .is-expand {
  295. .collapse-icon {
  296. transform: rotate(90deg);
  297. }
  298. }
  299. :deep(.el-form-item--small) {
  300. margin-bottom: 10px;
  301. }
  302. }
  303. </style>