A8000
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

499 lines
12 KiB

8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
  1. <template>
  2. <div class="user-management">
  3. <div class="user-table" :key="refreshKey">
  4. <el-table
  5. :data="tableData"
  6. header-cell-class-name="table-header"
  7. row-class-name="table-row"
  8. >
  9. <el-table-column type="selection" width="80" />
  10. <el-table-column label="用户" property="account" min-width="200" />
  11. <el-table-column label="权限" property="usrRole" min-width="200" />
  12. </el-table>
  13. <div class="table-footer">
  14. <el-button type="primary" @click="addUser">新增</el-button>
  15. <el-button type="primary" @click="modifyPin">PIN</el-button>
  16. <el-button type="danger" @click="deleteSelectedUsers">删除</el-button>
  17. </div>
  18. </div>
  19. <!-- 弹窗组件 -->
  20. <DelWarn
  21. v-if="delShowModal"
  22. :visible="delShowModal"
  23. icon="/src/assets/Warn.svg"
  24. title="删除用户"
  25. :message="deleteUserMessage"
  26. description="您正在删除用户,请谨慎操作"
  27. confirm-text="确认删除"
  28. cancel-text="取消删除"
  29. @confirm="handleConfirmDelete"
  30. @cancel="handleCancelDelete"
  31. />
  32. <DelMessage
  33. v-if="delMessageShowModal"
  34. v-model:visible="delMessageShowModal"
  35. icon="/src/assets/OK.svg"
  36. message="已成功删除用户"
  37. :username="selectedUsers[0]?.account"
  38. @confirm="handleConfirmMsgDelete"
  39. />
  40. <DelWarn
  41. v-if="updatePinModal"
  42. :visible="updatePinModal"
  43. icon="/src/assets/update-pin-icon.svg"
  44. title="PIN码更新"
  45. :message="updatePinMessage"
  46. description="您正在更改PIN码,请谨慎操作"
  47. confirm-text="确认更新"
  48. cancel-text="取消更新"
  49. @confirm="handleConfirmUpdatePin"
  50. @cancel="handleCancelUpdatePin"
  51. />
  52. <EnterPinModal
  53. v-if="enterPinModal"
  54. :visible="enterPinModal"
  55. :loading="updatePinLoading"
  56. @confirm="updatePinConfirm"
  57. @cancel="closeEnterPinModal"
  58. />
  59. <DelMessage
  60. v-if="updatePinMsgModal"
  61. :visible="updatePinMsgModal"
  62. icon="/src/assets/OK.svg"
  63. message="PIN码更新成功"
  64. :username="selectedUsers[0].account"
  65. @confirm="handleConfirmMsg"
  66. />
  67. <!-- 添加用户相关弹窗 -->
  68. <template v-if="currentStep === 'username'">
  69. <AddUserModal
  70. :visible="insertUserShowModal"
  71. :already-exist="isExist"
  72. placeholder="请输入用户名"
  73. :tips="tips"
  74. @confirm="handleConfirmInsert"
  75. @cancel="handleCancelInsert"
  76. @resetAlreadyExist="resetAlreadyExist"
  77. />
  78. </template>
  79. <template v-else-if="currentStep === 'pin'">
  80. <EnterPinModal
  81. :visible="isPinModalVisible"
  82. :loading="registerLoading"
  83. @confirm="handlePinConfirm"
  84. @cancel="closeModal"
  85. />
  86. </template>
  87. <DelMessage
  88. v-if="confirmInsert"
  89. :visible="confirmInsert"
  90. icon="/src/assets/OK.svg"
  91. message="已成功添加新用户"
  92. :username="newUser.account"
  93. @confirm="handleConfirmMsg"
  94. />
  95. </div>
  96. </template>
  97. <script setup lang="ts">
  98. import type { User } from '../../../types/Index'
  99. import { DelWarn, DelMessage, AddUserModal, EnterPinModal } from '../components'
  100. import { ref, onMounted, computed } from 'vue'
  101. import {
  102. getUserList,
  103. deleteUser,
  104. userRegister,
  105. changeUserPassword,
  106. } from '../../../services/Index/index'
  107. const tableData = ref<User[]>([
  108. {
  109. id: 1,
  110. account: '管理员',
  111. password: '0000',
  112. usrRole: 'Admin',
  113. isBuiltInUser: true,
  114. },
  115. {
  116. id: 2,
  117. account: '操作员01',
  118. password: '0000',
  119. usrRole: 'Usr',
  120. isBuiltInUser: false,
  121. },
  122. ])
  123. // 创建 `newUser` 对象存储用户名和 PIN 码
  124. const newUser = ref({
  125. account: '',
  126. password: '',
  127. usrRole: 'Usr',
  128. })
  129. //创建临时用户对象,用于存储用户名和PIN码
  130. const tempUser = ref({
  131. id: 0,
  132. password: '',
  133. })
  134. const registerLoading = ref(false)
  135. const updatePinLoading = ref(false)
  136. const placeholder = ref('请输入用户名')
  137. const currentStep = ref('username') // 当前步骤,初始为用户名输入页面
  138. //控制删除提醒teleport
  139. const delShowModal = ref(false)
  140. const delMessageShowModal = ref(false)
  141. const updatePinModal = ref(false)
  142. const updatePinMsgModal = ref(false)
  143. const insertUserShowModal = ref(false)
  144. const isPinModalVisible = ref(true)
  145. const confirmInsert = ref(false)
  146. const isChecked = ref(false)
  147. const enterPinModal = ref(false)
  148. //用户是否存在
  149. const isExist = ref(false)
  150. //提醒
  151. const tips = ref('')
  152. // 模拟用户数据
  153. const selectedUsers = ref<User[]>([])
  154. const refreshKey = ref(0)
  155. // 获取用户列表
  156. const fetchUserList = async () => {
  157. const response = await getUserList()
  158. console.log('获取用户列表', response)
  159. if (response && response.success) {
  160. tableData.value = response.data
  161. } else {
  162. console.log('获取用户列表失败')
  163. }
  164. }
  165. // 处理选择变化
  166. const handleSelectionChange = (val: User[]) => {
  167. selectedUsers.value = val
  168. console.log('选中的用户', val)
  169. // 只有当有选中用户时才更新 tempUser
  170. if (val && val.length > 0) {
  171. tempUser.value.id = val[0].id
  172. tempUser.value.password = val[0].password
  173. } else {
  174. // 当没有选中用户时,重置 tempUser
  175. tempUser.value.id = 0
  176. tempUser.value.password = ''
  177. }
  178. }
  179. // 新增用户
  180. const addUser = async () => {
  181. insertUserShowModal.value = true
  182. }
  183. // 修改用户权限 (模拟 PIN 码修改功能)
  184. const modifyPin = async () => {
  185. if (selectedUsers.value.length === 0) {
  186. //通知用户没有选择用户,不使用控制台打印
  187. isChecked.value = true
  188. return
  189. }
  190. updatePinModal.value = true
  191. }
  192. // 删除用户
  193. const deleteSelectedUsers = () => {
  194. if (selectedUsers.value.length === 0) {
  195. //通知用户没有选择用户,不使用控制台打印
  196. isChecked.value = true
  197. return
  198. }
  199. delShowModal.value = true
  200. }
  201. // 在组件挂载时调用获取用户列表
  202. onMounted(() => {
  203. fetchUserList()
  204. })
  205. const handleConfirmDelete = async () => {
  206. try {
  207. const ids = selectedUsers.value.map((user) => user.id)
  208. for (const id of ids) {
  209. const response = await deleteUser({ id })
  210. if (!response || !response.success) {
  211. console.log('删除用户失败')
  212. return
  213. }
  214. }
  215. delShowModal.value = false
  216. // 在显示成功消息之前先保存要显示的用户名
  217. // const deletedUsername = selectedUsers.value[0]?.account
  218. // 清空选中的用户
  219. selectedUsers.value = []
  220. delMessageShowModal.value = true
  221. } catch (error) {
  222. console.error('删除用户时发生错误:', error)
  223. }
  224. }
  225. const handleCancelDelete = () => {
  226. delShowModal.value = false
  227. }
  228. const handleConfirmMsg = () => {
  229. confirmInsert.value = false
  230. isChecked.value = false
  231. updatePinMsgModal.value = false
  232. fetchUserList()
  233. }
  234. const handleConfirmMsgDelete = () => {
  235. delMessageShowModal.value = false
  236. fetchUserList()
  237. }
  238. //更新PIN
  239. //定义请求
  240. const handleUpdatePin = async () => {
  241. if (selectedUsers.value.length !== 1) {
  242. console.log('请选择一个用户来修改PIN码')
  243. return
  244. }
  245. const user = tempUser.value
  246. const response = await changeUserPassword({
  247. id: user.id,
  248. password: user.password,
  249. })
  250. if (response && response.success) {
  251. } else {
  252. console.log('修改用户权限失败')
  253. }
  254. }
  255. //确认更新pin,打开输入框
  256. const handleConfirmUpdatePin = () => {
  257. updatePinModal.value = false
  258. enterPinModal.value = true
  259. }
  260. //输入pin,确认,发送请求
  261. const updatePinConfirm = (val: string) => {
  262. enterPinModal.value = false
  263. updatePinLoading.value = true
  264. tempUser.value.password = val
  265. handleUpdatePin().then(() => {
  266. updatePinLoading.value = false
  267. updatePinMsgModal.value = true
  268. })
  269. }
  270. //取消
  271. const closeEnterPinModal = () => {
  272. enterPinModal.value = false
  273. }
  274. //取消
  275. const handleCancelUpdatePin = () => {
  276. updatePinModal.value = false
  277. }
  278. //添加用户
  279. const handleConfirmInsert = (val: string) => {
  280. const user = tableData.value.find((item) => item.account == val)
  281. if (val == '') {
  282. isExist.value = true
  283. tips.value = '用户名不能为空'
  284. placeholder.value = '请输入用户名'
  285. } else if (user) {
  286. isExist.value = true
  287. tips.value = '用户已存在,请重新输入'
  288. placeholder.value = val
  289. } else {
  290. newUser.value.account = val // 存储用户名
  291. currentStep.value = 'pin'
  292. }
  293. }
  294. const handleCancelInsert = () => {
  295. insertUserShowModal.value = false
  296. }
  297. // 重置 `alreadyExist` 状态
  298. const resetAlreadyExist = () => {
  299. isExist.value = false
  300. placeholder.value = '请输入用户名'
  301. }
  302. const handlePinConfirm = (pin: string) => {
  303. // 处理 PIN 码确认逻辑
  304. registerLoading.value = true
  305. newUser.value.password = pin
  306. handleAddUser().then(() => {
  307. confirmInsert.value = true
  308. registerLoading.value = false
  309. isPinModalVisible.value = false
  310. })
  311. }
  312. const closeModal = () => {
  313. isPinModalVisible.value = false
  314. }
  315. //添加用户的api
  316. const handleAddUser = async () => {
  317. const res = await userRegister(newUser.value)
  318. if (res && res.success) {
  319. fetchUserList()
  320. }
  321. }
  322. // 选中用户的 `account` 信息,用于显示在 `Warning` 组件中
  323. const selectedUserAccount = computed(() => {
  324. return selectedUsers.value.length > 0 ? selectedUsers.value[0].account : ''
  325. })
  326. // 动态生成的 message 内容
  327. const updatePinMessage = computed(
  328. () => `是否更新PIN码 <strong>${selectedUserAccount.value}</strong> 用户`,
  329. )
  330. const deleteUserMessage = computed(
  331. () => `是否删除 <strong>${selectedUserAccount.value}</strong> 用户`,
  332. )
  333. </script>
  334. <style scoped lang="less">
  335. .user-management {
  336. width: 100%;
  337. height: 90vh;
  338. padding: 20px;
  339. box-sizing: border-box;
  340. background-color: #f5f7fa;
  341. display: flex;
  342. flex-direction: column;
  343. .user-table {
  344. flex: 1;
  345. background-color: #fff;
  346. border-radius: 12px;
  347. padding: 24px;
  348. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
  349. display: flex;
  350. flex-direction: column;
  351. transition: all 0.3s ease;
  352. &:hover {
  353. box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.08);
  354. }
  355. :deep(.el-table) {
  356. flex: 1;
  357. border: none;
  358. border-radius: 8px;
  359. overflow: hidden;
  360. &::before {
  361. display: none;
  362. }
  363. .el-table__header {
  364. th {
  365. background-color: #f5f7fa;
  366. border: none;
  367. height: 60px;
  368. font-size: 24px;
  369. font-weight: 500;
  370. color: #303133;
  371. &.is-leaf {
  372. border: none;
  373. }
  374. }
  375. }
  376. .el-table__body {
  377. td {
  378. border: none;
  379. height: 60px;
  380. font-size: 24px;
  381. color: #606266;
  382. transition: background-color 0.3s;
  383. }
  384. tr {
  385. border: none;
  386. transition: all 0.3s;
  387. &:hover > td {
  388. background-color: #f5f7fa;
  389. }
  390. &.selected-row > td {
  391. background-color: #ecf5ff;
  392. }
  393. }
  394. }
  395. // 放大多选框
  396. .el-checkbox {
  397. transform: scale(1.5);
  398. .el-checkbox__inner {
  399. border-color: #dcdfe6;
  400. transition: all 0.3s;
  401. &:hover {
  402. border-color: #409eff;
  403. }
  404. }
  405. }
  406. }
  407. .table-footer {
  408. margin-top: 24px;
  409. display: flex;
  410. justify-content: center;
  411. gap: 20px;
  412. .el-button {
  413. min-width: 160px;
  414. height: 56px;
  415. border-radius: 8px;
  416. font-size: 24px;
  417. font-weight: 500;
  418. transition: all 0.3s;
  419. display: flex;
  420. align-items: center;
  421. justify-content: center;
  422. &:hover {
  423. transform: translateY(-2px);
  424. box-shadow: 0 4px 12px rgba(64, 158, 255, 0.2);
  425. }
  426. &.el-button--primary {
  427. background-color: #409eff;
  428. border-color: #409eff;
  429. &:hover {
  430. background-color: #66b1ff;
  431. border-color: #66b1ff;
  432. }
  433. }
  434. &.el-button--danger {
  435. &:hover {
  436. box-shadow: 0 4px 12px rgba(245, 108, 108, 0.2);
  437. }
  438. }
  439. }
  440. }
  441. }
  442. }
  443. // 添加响应式设计
  444. @media screen and (max-width: 768px) {
  445. .user-management {
  446. padding: 10px;
  447. .user-table {
  448. padding: 16px;
  449. .table-footer {
  450. flex-direction: column;
  451. align-items: stretch;
  452. gap: 12px;
  453. .el-button {
  454. width: 100%;
  455. }
  456. }
  457. }
  458. }
  459. }
  460. </style>