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.

1174 lines
38 KiB

2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
  1. <script setup>
  2. import { computed, onMounted, ref } from 'vue'
  3. import { ElMessage, ElMessageBox } from 'element-plus'
  4. import { InfoFilled } from '@element-plus/icons-vue'
  5. import _ from 'lodash'
  6. import request from '@/util/http'
  7. import API from '@/util/http'
  8. // 表格数据
  9. const tableData = ref([])
  10. const total = ref(100)
  11. const handleDialogClose = function () {
  12. closeUserAddVisible()
  13. console.log('hhh');
  14. }
  15. const propsAdduser = {
  16. multiple: true, // 多选
  17. }
  18. // 搜索admin
  19. const admin = ref({
  20. account: '',
  21. market: '',
  22. postiton: ''
  23. })
  24. // 搜索对象
  25. const getObj = ref({
  26. pageNum: 1,
  27. pageSize: 10
  28. })
  29. // 修改状态确认
  30. const ackVisible = ref(false)
  31. const currentStatusRow = ref(null)
  32. const statusLoading = ref({})
  33. const showStatusConfirm = (row, targetStatus) => {
  34. currentStatusRow.value = {
  35. ...row,// 当前行数据
  36. targetStatus// 目标状态
  37. }
  38. ackVisible.value = true
  39. }
  40. // 规则
  41. const addUserRules = {
  42. account: [
  43. { required: true, message: '请输入OA号', trigger: 'blur' },
  44. { pattern: /^\d+$/, message: 'OA号必须为数字', trigger: 'blur' },
  45. { max: 20, message: '长度不能超过20位', trigger: 'blur' }
  46. ],
  47. name: [
  48. { required: true, message: '请输入用户名', trigger: 'blur' },
  49. { max: 20, message: '长度不能超过20位', trigger: 'blur' }
  50. ],
  51. market: [
  52. { required: true, message: '请选择所属地区', trigger: 'change' }
  53. ],
  54. permission: [
  55. { required: true, message: '请选择角色名称', trigger: 'change' }
  56. ],
  57. postiton: [
  58. { required: true, message: '请输入职位', trigger: 'blur' },
  59. { max: 20, message: '长度不能超过20位', trigger: 'blur' }
  60. ],
  61. machineIds: [
  62. {
  63. required: true,
  64. message: '请至少输入一个机器码',
  65. trigger: 'change',
  66. validator: (rule, value, callback) => {
  67. // 检查是否有非空的机器码
  68. const hasValid = value.some(item => item.trim() !== '');
  69. if (!hasValid) {
  70. callback(new Error('请至少输入一个机器码'));
  71. } else {
  72. callback();
  73. }
  74. }
  75. }
  76. ]
  77. };
  78. // 新增用户权限弹窗
  79. const userAddVisible = ref(false)
  80. // 编辑用户权限弹窗
  81. const userEditVisible = ref(false)
  82. //选地区
  83. const market = ref([])
  84. // 选部门
  85. const postiton = ref([])
  86. // 新增用户对象
  87. const userAddObj = ref({})
  88. // 新增用户权限对象,机器码要实现存储多个,addMachineIdInput方法实现
  89. const addAdmin = ref({
  90. account: '',
  91. name: '',
  92. market: [],
  93. permission: '',
  94. postiton: '',
  95. machineIds: [''], // 动态添加的机器码输入框
  96. machineId: '',
  97. remark: ''
  98. })
  99. //这是获取用户信息的接口
  100. const adminData = ref({})
  101. // todo 之后优化掉
  102. const getAdminData = async function () {
  103. try {
  104. const result = await API({ url: '/admin/userinfo', data: {} })
  105. adminData.value = result
  106. // console.log('请求成功', result)
  107. console.log('管理员用户信息', adminData.value)
  108. } catch (error) {
  109. console.log('请求失败', error)
  110. }
  111. }
  112. // 编辑用户权限对象
  113. const permissionEditObj = ref({
  114. checkedKeys: [],
  115. machineIds: [''],
  116. machineId: '',
  117. password: '',
  118. postiton: ''
  119. })
  120. const addMachineIdInput = function () {
  121. if (addAdmin.value.machineIds.length >= 2) {
  122. ElMessage.warning('设备数量已达上限')
  123. return
  124. }
  125. addAdmin.value.machineIds.push('')
  126. }
  127. const UseraddMachineIdInput = function () {
  128. if (permissionEditObj.value.machineIds.length >= 2) {
  129. ElMessage.warning('设备数量已达上限')
  130. return
  131. }
  132. permissionEditObj.value.machineIds.push('')
  133. }
  134. // 删除权限对象
  135. const delObj = ref({})
  136. const getPermission = async function (val) {
  137. try {
  138. if (typeof val === 'number') {
  139. getObj.value.pageNum = val
  140. }
  141. console.log('搜索参数', getObj.value, admin.value)
  142. // if (admin.value.market === '总部' || admin.value.market === '研发部') {
  143. // admin.value.market = '';
  144. // }
  145. if (admin.value.account) {
  146. // 纯数字
  147. const numberRegex = /^\d{1,20}$/;
  148. // 检查是否不是数字
  149. if (!numberRegex.test(admin.value.account)) {
  150. ElMessage.error('请检查OA号格式')
  151. // 上面提示过了
  152. return
  153. }
  154. }
  155. const result = await request({
  156. url: '/permission/getPermission',
  157. data: {
  158. ...getObj.value,
  159. permission: {
  160. ...admin.value
  161. }
  162. }
  163. })
  164. tableData.value = result.data.list
  165. console.log('tableData', tableData.value)
  166. total.value = result.data.total
  167. } catch (error) {
  168. console.log('请求失败', error)
  169. }
  170. }
  171. const trimJwCode = () => {
  172. if (admin.value.account) {
  173. admin.value.account = admin.value.account.replace(/\s/g, '');
  174. }
  175. }
  176. const search = function () {
  177. trimJwCode();
  178. getObj.value.pageNum = 1
  179. getPermission()
  180. }
  181. // 重置
  182. const reset = function () {
  183. admin.value = {}
  184. getPermission()
  185. }
  186. const RoleArea = ref([])
  187. const getRoleArea = async function () {
  188. try {
  189. const result = await request({
  190. url: '/general/allRoleMarket',
  191. data: {}
  192. })
  193. RoleArea.value = result.data
  194. } catch (error) {
  195. console.log('请求失败', error)
  196. }
  197. }
  198. // 获取地区树
  199. const marketsTree = ref([])
  200. const getArea = async function () {
  201. try {
  202. // 发送POST请求
  203. const result = await API({
  204. url: '/market/selectMarket',
  205. });
  206. // 将响应结果存储到响应式数据中
  207. console.log('请求成功', result)
  208. // 递归转换树形结构为级联选择器需要的格式(跳过第一级节点)
  209. const transformTree = (nodes) => {
  210. // 直接处理第一级节点的子节点
  211. const allChildren = nodes.flatMap(node => node.children || []);
  212. return allChildren.map(child => {
  213. const grandchildren = child.children && child.children.length
  214. ? transformTree([child]) // 递归处理子节点
  215. : null;
  216. return {
  217. value: child.name,
  218. label: child.name,
  219. children: grandchildren
  220. };
  221. });
  222. };
  223. // 存储地区信息
  224. marketsTree.value = transformTree(result.data)
  225. console.log('转换后的地区树==============', marketsTree.value)
  226. } catch (error) {
  227. console.log('请求失败', error)
  228. }
  229. }
  230. // 获取部门
  231. const getStore = async function () {
  232. try {
  233. const result = await request({
  234. url: '/permission/getposition',
  235. data: {}
  236. })
  237. postiton.value = result.data
  238. } catch (error) {
  239. console.log('请求失败', error)
  240. }
  241. }
  242. // 打开新增用户权限弹窗
  243. const openUserAddVisible = function () {
  244. userAddVisible.value = true
  245. }
  246. // 关闭新增用户权限弹窗,并刷新表单
  247. const closeUserAddVisible = function () {
  248. userAddVisible.value = false;
  249. // 清除表单验证状态
  250. Ref.value.resetFields();
  251. }
  252. // 新增用户权限初始化
  253. const userAddInit = function () {
  254. userAddObj.value = {}
  255. openUserAddVisible()
  256. }
  257. //新增用户
  258. const permissionAdd = async function () {
  259. try {
  260. await new Promise((resolve, reject) => {
  261. Ref.value.validate((valid) => {
  262. if (valid) {
  263. resolve(); // 验证通过,继续执行后续代码
  264. } else {
  265. reject(new Error('请检查并完善表单信息')); // 验证失败,抛出错误
  266. }
  267. });
  268. });
  269. addAdmin.value.adminFlag = 1
  270. addAdmin.value.status1 = 1
  271. if (addAdmin.value.postiton === '管理员') {
  272. addAdmin.value.postiton === 1
  273. }
  274. const params = {
  275. "account": addAdmin.value.account,//OA号
  276. "adminName": addAdmin.value.name,//姓名
  277. "market": addAdmin.value.market,//地区
  278. "roleId": addAdmin.value.permission,//权限ID
  279. "postiton": addAdmin.value.postiton,//职位
  280. "machineId": addAdmin.value.machineIds[0],//机器码
  281. "remark": addAdmin.value.remark//备注
  282. }
  283. console.log('提交前addAdmin market', addAdmin.value.market)
  284. const result = await request({
  285. url: '/permission/addPermission',
  286. data: params
  287. })
  288. console.log(addAdmin.value)
  289. if (result.code === 200) {
  290. ElMessage.success('添加成功')
  291. } else {
  292. ElMessage.error(result.msg)
  293. }
  294. addAdmin.value = {}
  295. getPermission()
  296. closeUserAddVisible()
  297. } catch (error) {
  298. console.log('新增用户权限失败', error)
  299. ElMessage.error('新增用户权限失败')
  300. }
  301. }
  302. // 表单验证ref
  303. const Ref = ref(null)
  304. // 权限类别
  305. const permissionList = ref([])
  306. const getRoles = async function () {
  307. try {
  308. const res = await API({ url: '/role/selectAll' })
  309. permissionList.value = res.data.map(item => ({
  310. label: item.roleName,
  311. value: item.id
  312. }))
  313. console.log('权限列表:', permissionList.value)
  314. } catch (error) {
  315. console.error('获取权限列表失败:', error)
  316. }
  317. }
  318. // 打开编辑用户权限弹窗
  319. const openUserEditVisible = function () {
  320. userEditVisible.value = true
  321. }
  322. // 关闭编辑用户权限弹窗
  323. const closeUserEditVisible = function () {
  324. userEditVisible.value = false
  325. data.value = []
  326. }
  327. // 编辑用户权限初始化
  328. const permissionEditInit = async function (row) {
  329. console.log('row', row)
  330. permissionEditObj.value = {}
  331. permissionEditObj.value.id = row.id
  332. permissionEditObj.value.account = row.account
  333. permissionEditObj.value.adminName = row.name
  334. permissionEditObj.value.remark = row.remark
  335. permissionEditObj.value.market = row.market
  336. permissionEditObj.value.password = ''
  337. // 将字符串形式的 market 转换为数组
  338. if (typeof row.market === 'string' && row.market) {
  339. permissionEditObj.value.market = row.market.split(',');
  340. } else {
  341. // 处理空值或非字符串情况
  342. permissionEditObj.value.market = [];
  343. }
  344. permissionEditObj.value.postiton = row.postiton || ''
  345. if (permissionEditObj.value.postiton === ' ') {
  346. permissionEditObj.value.postiton = ''
  347. }
  348. permissionEditObj.value.roleId = row.roleId
  349. const result = await request({
  350. url: '/role/selectFather',
  351. data: {
  352. id: row.roleId
  353. }
  354. })
  355. console.log('初始查上级权限', result)
  356. permissionEditObj.value.parentId = result.data?.fatherId
  357. permissionEditObj.value.parentName = result.data?.fatherName
  358. console.log('get前', permissionEditObj.value.roleId);
  359. permissionEditObj.value.roleName = row.roleName
  360. if (permissionEditObj.value.roleId === 0) {
  361. permissionEditObj.value.roleId = ''
  362. }
  363. getUserLists(row.roleId)
  364. let machineIdsRef = await request({
  365. url: '/permission/getPermission',
  366. data: {
  367. "pageNum": 1,//页码数
  368. "pageSize": 1,//页条数
  369. "permission": {
  370. account: row.account,//OA号
  371. }
  372. }
  373. })
  374. if (machineIdsRef.data.list[0].machineIds == null || machineIdsRef.data.list[0].machineIds.length === 0) {
  375. permissionEditObj.value.machineIds = ['']
  376. } else {
  377. permissionEditObj.value.machineIds = machineIdsRef.data.list[0].machineIds
  378. }
  379. permissionEditObj.value.machineId = permissionEditObj.value.machineIds[0]
  380. //permissionEditObj.value.permission = row.permission
  381. console.log('编辑用户权限', permissionEditObj.value)
  382. console.log('11111111111111', permissionEditObj.value.machineId)
  383. openUserEditVisible()
  384. }
  385. const collectIds = (tree) => {
  386. let ids = [];
  387. tree.forEach((node) => {
  388. ids.push(node.id);
  389. if (node.children && node.children.length > 0) {
  390. ids = ids.concat(collectIds(node.children));
  391. }
  392. });
  393. return ids;
  394. };
  395. // 定义上级角色提示变量
  396. const parentRoleTip = ref('');
  397. //给data数据加上disabled属性,控制是否禁用
  398. function processTreeData(data) {
  399. return data.map(item => ({
  400. ...item,
  401. disabled: item.id != null || item.menuName.includes("敏感权限"), //控制权限显示的条件
  402. children: item.children ? processTreeData(item.children) : []
  403. }));
  404. }
  405. //根据上级角色控制权限列表,选择角色调整上级角色
  406. const getUserLists = async function (selectedRoleId) {
  407. try {
  408. console.log('permissionEditObj.value.roleId:', permissionEditObj.value.roleId)
  409. console.log('selectedRoleId', selectedRoleId);
  410. permissionEditObj.value.parentId = null;
  411. permissionEditObj.value.parentName = '';
  412. permissionEditObj.value.checkedKeys = [];
  413. parentRoleTip.value = '';
  414. const parentRes = await request({
  415. url: '/role/selectFather',
  416. data: { id: selectedRoleId } // 用选中的角色ID请求
  417. });
  418. const parentId = parentRes.data.fatherId;
  419. const parentName = parentRes.data.parentName;
  420. permissionEditObj.value.parentId = parentId;
  421. permissionEditObj.value.parentName = parentName;
  422. if (parentId == null) {
  423. // 无上级角色:显示提示
  424. parentRoleTip.value = '该角色无上级角色';
  425. }
  426. let roleId = permissionEditObj.value.roleId
  427. // if (permissionEditObj.value.parentId === null || permissionEditObj.value.parentId === undefined) {
  428. // roleId = 2
  429. // }
  430. const res = await API({
  431. url: '/menu/tree',
  432. data: { id: roleId }
  433. })
  434. data.value = processTreeData(res.data)
  435. permissionEditObj.value.checkedKeys = collectIds(res.data) || [];
  436. console.log('看看data', data.value)
  437. console.log('看checkedKeys', permissionEditObj.value.checkedKeys)
  438. console.log('parentID:', permissionEditObj.value.parentId, 'roleId:', roleId)
  439. console.log('permissionEditObj.value.roleId:', permissionEditObj.value.roleId)
  440. } catch (error) {
  441. console.log('请求失败', error)
  442. }
  443. }
  444. //编辑用户表单校验
  445. const editAdminRules = {
  446. market: [
  447. { required: true, message: '请选择所属地区', trigger: 'change' }
  448. ],
  449. postiton: [
  450. { required: true, message: '请输入职位', trigger: ['blur', 'change'] },
  451. { max: 20, message: '长度不能超过20位', trigger: ['blur', 'change'] }
  452. ],
  453. machineIds: [
  454. {
  455. required: true,
  456. message: '请至少输入一个机器码',
  457. trigger: 'change',
  458. validator: (rule, value, callback) => {
  459. // 检查是否有非空的机器码
  460. const hasValid = value.some(item => item.trim() !== '');
  461. if (!hasValid) {
  462. callback(new Error('请至少输入一个机器码'));
  463. } else {
  464. callback();
  465. }
  466. }
  467. }
  468. ]
  469. };
  470. // 编辑用户权限提交
  471. const permissionEdit = async function () {
  472. let { adminName: userName, roleName: oldRole, roleId: newRoleId } = permissionEditObj.value;
  473. if (oldRole == null) {
  474. oldRole = '暂未分配角色'
  475. }
  476. const newRole = permissionList.value.find(item => item.value === newRoleId)?.label || '未知角色';
  477. try {
  478. await new Promise((resolve, reject) => {
  479. Ref.value.validate((valid) => {
  480. if (valid) {
  481. resolve(); // 验证通过,继续执行后续代码
  482. } else {
  483. reject(new Error('请检查并完善表单信息')); // 验证失败,抛出错误
  484. }
  485. });
  486. });
  487. await ElMessageBox.confirm(
  488. `确认修改权限角色?<br>您正在将【${userName}】的权限角色从【${oldRole}】修改为【${newRole}】<br>变更后,该用户的可操作权限将同步更新为新角色配置,涉及数据访问、功能操作等权限变化,请谨慎确认。`,
  489. '警告',
  490. {
  491. confirmButtonText: '确认',
  492. cancelButtonText: '取消',
  493. type: "warning",
  494. lockScroll: false,
  495. dangerouslyUseHTMLString: true //允许解析 HTML 标签
  496. }
  497. )
  498. const result = await request({
  499. url: '/permission/updateAdmin',
  500. data: {
  501. account: permissionEditObj.value.account,//OA号
  502. adminName: permissionEditObj.value.adminName,//姓名
  503. market: permissionEditObj.value.market,//地区
  504. postiton: permissionEditObj.value.postiton,//职位
  505. roleId: permissionEditObj.value.roleId,//角色id
  506. machineId: permissionEditObj.value.machineIds[0],//机器码
  507. machineIds: permissionEditObj.value.machineIds[1],//机器码
  508. password: permissionEditObj.value.password,//
  509. remark: permissionEditObj.value.remark//备注
  510. }
  511. });
  512. console.log('编辑最后提交数据', permissionEditObj.value);
  513. if (result.code === 200) {
  514. await ElMessageBox.alert(
  515. `用户${userName}的权限角色已更改为【${newRole}`,
  516. '成功',
  517. {
  518. confirmButtonText: '确定',
  519. type: 'success' // 设置为 success 类型
  520. }
  521. );
  522. getPermission();
  523. closeUserEditVisible();
  524. } else {
  525. ElMessage.error(result.msg)
  526. }
  527. } catch (error) {
  528. console.log('编辑用户权限失败', error)
  529. ElMessage.error('编辑用户权限失败')
  530. }
  531. }
  532. // 删除初始化
  533. const del = function (row) {
  534. delObj.value = {}
  535. console.log(row, '删除初始化')
  536. delObj.value.account = row.account
  537. delObj.value.id = row.id
  538. }
  539. // 删除权限
  540. const delConfirm = async function () {
  541. try {
  542. const result = await request({
  543. url: '/permission/deleteAdmin',
  544. data: delObj.value
  545. })
  546. console.log('看看删除对象', delObj.value)
  547. console.log('请求成功1', result)
  548. ElMessage.success('删除权限成功')
  549. delObj.value = {}
  550. getPermission()
  551. } catch (error) {
  552. console.log('删除权限失败', error)
  553. ElMessage.error('删除权限失败')
  554. }
  555. }
  556. // 禁用启用用户权限
  557. const editStatus = async function (row) {
  558. const { id, account, targetStatus, ...restRow } = currentStatusRow.value
  559. try {
  560. statusLoading.value[id] = true
  561. console.log(row)
  562. permissionEditObj.value = {}
  563. permissionEditObj.value.id = id
  564. permissionEditObj.value.account = account
  565. permissionEditObj.value.adminStatus = targetStatus
  566. console.log('修改用户权限状态', permissionEditObj.value)
  567. const result = await request({
  568. url: '/permission/upadatePermission',
  569. data: permissionEditObj.value
  570. })
  571. console.log('请求成功2', result)
  572. if (result.code === 200) {
  573. ElMessage.success(
  574. permissionEditObj.value.adminStatus === 1 ? '启用成功' : '禁用成功'
  575. )
  576. statusLoading.value[id] = false
  577. }
  578. permissionEditObj.value = {}
  579. getPermission()
  580. } catch (error) {
  581. console.log('修改用户权限失败', error)
  582. }
  583. }
  584. const handlePageSizeChange = function (val) {
  585. getObj.value.pageSize = val
  586. getPermission()
  587. }
  588. const handleCurrentChange = function (val) {
  589. getObj.value.pageNum = val
  590. getPermission()
  591. }
  592. const data = ref([])
  593. // todo 处理地区选择变化
  594. /*const handleMarketChange = (values) => {
  595. console.log('values的类型:', typeof values);
  596. console.log('values的值:', values);
  597. //判断是否选择了总部
  598. const hasHeadquarters = values.includes('总部');
  599. if (hasHeadquarters) {
  600. // 如果选择了总部,只保留总部
  601. addAdmin.value.market = ['总部'];
  602. }
  603. console.log('看看现在的地区', addAdmin.value.market);
  604. };*/
  605. // 存储地区选择变化
  606. const selectedMarketPath = ref("")
  607. // 这个不转id
  608. const handleMarketChange = (value) => {
  609. if (value && value.length > 0) {
  610. admin.value.market = value[value.length - 1]
  611. } else {
  612. admin.value.market = ''
  613. }
  614. }
  615. // 修改地区选择处理函数
  616. const handleMarketChangeAddUser = (value) => {
  617. if (Array.isArray(value) && value.length > 0) {
  618. // 提取所有选中项的最后一级
  619. const selectedMarkets = value
  620. .map(path => Array.isArray(path) && path.length > 0 ? path[path.length - 1] : null)
  621. .filter(Boolean);
  622. // 检查是否包含总部
  623. const hasHeadquarters = selectedMarkets.includes('总部');
  624. if (hasHeadquarters) {
  625. // 如果包含总部,只保留总部
  626. addAdmin.value.market = ['总部'];
  627. } else {
  628. // 不包含总部,保留所有选择
  629. addAdmin.value.market = selectedMarkets;
  630. }
  631. } else {
  632. // 未选择任何地区
  633. addAdmin.value.market = [];
  634. }
  635. };
  636. // 修改地区选择处理函数
  637. const handleMarketChangeEditUser = (value) => {
  638. if (Array.isArray(value) && value.length > 0) {
  639. // 提取所有选中项的最后一级
  640. const selectedMarkets = value
  641. .map(path => Array.isArray(path) && path.length > 0 ? path[path.length - 1] : null)
  642. .filter(Boolean);
  643. // 检查是否包含总部
  644. const hasHeadquarters = selectedMarkets.includes('总部');
  645. if (hasHeadquarters) {
  646. // 如果包含总部,只保留总部
  647. permissionEditObj.value.market = ['总部'];
  648. } else {
  649. // 不包含总部,保留所有选择
  650. permissionEditObj.value.market = selectedMarkets;
  651. }
  652. } else {
  653. // 未选择任何地区
  654. permissionEditObj.value.market = [];
  655. }
  656. };
  657. const addUserProps = {
  658. multiple: true,
  659. }
  660. /*// 计算属性控制级联选择器的选项禁用状态
  661. const addUserProps = computed(() => {
  662. // 判断是否已选择总部
  663. const hasHeadquarters = addAdmin.value.market.includes('总部');
  664. return {
  665. multiple: true, // 保留多选功能
  666. // 选项禁用逻辑:如果已选择总部,则禁用非总部的选项
  667. disabled: (data) => {
  668. return hasHeadquarters && data.label !== '总部';
  669. }
  670. };
  671. });*/
  672. const editUserProps = {
  673. multiple: true,
  674. }
  675. /*// 计算属性控制级联选择器的选项禁用状态
  676. const editUserProps = computed(() => {
  677. // 判断是否已选择总部
  678. const hasHeadquarters = permissionEditObj.value.market.includes('总部');
  679. return {
  680. multiple: true, // 保留多选功能
  681. // 选项禁用逻辑:如果已选择总部,则禁用非总部的选项
  682. disabled: (data) => {
  683. return hasHeadquarters && data.label !== '总部';
  684. }
  685. };
  686. });*/
  687. const selectParentNodes = (treeData, nodeId, checkedKeys) => {
  688. if (!Array.isArray(treeData)) return false;
  689. for (const item of treeData) {
  690. // 先检查子节点
  691. if (item.children && item.children.length > 0) {
  692. const foundInChildren = selectParentNodes(item.children, nodeId, checkedKeys);
  693. if (foundInChildren) {
  694. // 找到子节点后添加当前节点(父节点)
  695. checkedKeys.add(item.id);
  696. return true;
  697. }
  698. }
  699. // 检查当前节点是否为目标节点
  700. if (item.id === nodeId) {
  701. return true;
  702. }
  703. }
  704. return false;
  705. };
  706. // 重置密码弹窗状态
  707. const resetConfirmVisible = ref(false)
  708. // 当前选中的行数据
  709. const currentRow = ref(null)
  710. // 重置密码
  711. const resetPassword = function (row) {
  712. // 显示确认弹窗
  713. currentRow.value = row
  714. resetConfirmVisible.value = true
  715. }
  716. // 确认重置密码
  717. const confirmResetPassword = async function () {
  718. console.log('adminData', adminData.value)
  719. // 处理markets数据
  720. if (typeof adminData.value.markets === 'string' && adminData.value.markets) {
  721. adminData.value.markets = adminData.value.markets.split(',');
  722. } else if (Array.isArray(adminData.value.markets)) {
  723. // 不处理
  724. } else {
  725. adminData.value.markets = [];
  726. }
  727. console.log('重置密码markets2', adminData.value.markets)
  728. // 权限检查
  729. if (adminData.value.markets.includes(currentRow.value.market) || adminData.value.markets[0] === '总部' || adminData.value.markets[0] === '研发部') {
  730. console.log('符合条件,可以操作', adminData.value.markets.includes(currentRow.value.market) || adminData.value.markets[0] === '总部' || adminData.value.markets[0] === '研发部');
  731. const params = {
  732. account: currentRow.value.account,
  733. }
  734. console.log(params);
  735. // 发送请求
  736. try {
  737. const result = await request({
  738. url: '/admin/reset',
  739. method: 'post',
  740. data: params // 直接传递params对象
  741. });
  742. if (result.code === 200) { // 使用严格相等运算符
  743. ElMessage.success('重置密码成功');
  744. resetConfirmVisible.value = false; // 关闭弹窗
  745. await getPermission()
  746. } else {
  747. ElMessage.error(result.message || '重置密码失败');
  748. }
  749. } catch (error) {
  750. ElMessage.error('重置密码失败');
  751. console.error('请求错误:', error);
  752. }
  753. } else {
  754. // console.log("为什么不能重置",adminData.value.markets)
  755. ElMessage.error('您没有修改' + currentRow.value.market + '地区的用户密码的权限');
  756. resetConfirmVisible.value = false; // 关闭弹窗
  757. }
  758. }
  759. // 取消重置密码
  760. const cancelResetPassword = function () {
  761. resetConfirmVisible.value = false
  762. const collectIds2 = (tree) => {
  763. let ids = [];
  764. tree.forEach((node) => {
  765. // 如果当前节点没有 children 或 children 为空,说明是叶子节点
  766. if (!node.children || node.children.length === 0) {
  767. ids.push(node.id);
  768. } else {
  769. // 如果有 children,递归收集子节点的叶子节点
  770. ids = ids.concat(collectIds2(node.children));
  771. }
  772. });
  773. return ids;
  774. };
  775. }
  776. // 为提交时查找父节点的辅助函数
  777. const selectParentNodesForSubmit = (treeData, nodeId, checkedKeys) => {
  778. if (!Array.isArray(treeData)) return false;
  779. for (const item of treeData) {
  780. // 先检查子节点
  781. if (item.children && item.children.length > 0) {
  782. const foundInChildren = selectParentNodesForSubmit(item.children, nodeId, checkedKeys);
  783. if (foundInChildren) {
  784. // 找到子节点后添加当前节点(父节点)
  785. checkedKeys.add(item.id);
  786. return true;
  787. }
  788. }
  789. // 检查当前节点是否为目标节点
  790. if (item.id === nodeId) {
  791. return true;
  792. }
  793. }
  794. return false;
  795. };
  796. const throttledPermissionEdit = _.throttle(permissionEdit, 5000, {
  797. trailing: false
  798. })
  799. // 使用 _.throttle 并设置 trailing 为 false 实现严格节流,只执行一次
  800. const throttledPermissionAdd = _.throttle(permissionAdd, 5000, {
  801. trailing: false
  802. })
  803. // 挂载
  804. onMounted(async function () {
  805. await getAdminData()
  806. await getPermission()
  807. await getArea()
  808. await getStore()
  809. await getRoles()
  810. await getRoleArea()
  811. })
  812. </script>
  813. <template>
  814. <div>
  815. <el-card style="margin-bottom: 1vh;">
  816. <div class="head-card">
  817. <div class="head-card-element">
  818. <el-text class="mx-1" size="large">OA号</el-text>
  819. <el-input v-model="admin.account" style="width: 240px" placeholder="请输入OA号" clearable />
  820. </div>
  821. <div class="head-card-element" style="margin-left: 50px">
  822. <el-text class="mx-1" size="large">所属地区</el-text>
  823. <el-cascader v-model="admin.market" :options="marketsTree" placeholder="请选择所属地区" clearable style="width:180px"
  824. @change="handleMarketChange" />
  825. </div>
  826. <div class="head-card-element" style="margin-left: 50px">
  827. <el-text class="mx-1" size="large">职位名称</el-text>
  828. <el-select v-model="admin.postiton" placeholder="请选择职位名称" style="width: 240px" clearable>
  829. <el-option v-for="item in postiton" :key="item" :label="item" :value="item" />
  830. </el-select>
  831. </div>
  832. <div class="head-card-btn">
  833. <el-button type="success" @click="reset()">重置</el-button>
  834. <el-button type="primary" @click="search()">查询</el-button>
  835. </div>
  836. </div>
  837. </el-card>
  838. <el-card>
  839. <!-- 展示表单 -->
  840. <div class="add-item">
  841. <el-button style="color: #048efb; border: 1px solid #048efb" @click="userAddInit()">新增用户</el-button>
  842. </div>
  843. <div>
  844. <el-table :data="tableData" style="width: 82vw;height:60vh" show-overflow-tooltip>
  845. <el-table-column type="index" label="序号" width="100px" fixed="left">
  846. <template #default="scope">
  847. <span>{{
  848. scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
  849. }}</span>
  850. </template>
  851. </el-table-column>
  852. <el-table-column prop="account" label="OA号" />
  853. <el-table-column prop="name" label="姓名" />
  854. <el-table-column prop="market" label="所属地区" />
  855. <el-table-column prop="postiton" label="职位" />
  856. <el-table-column prop="roleName" label="部门权限">
  857. </el-table-column>
  858. <el-table-column prop="remark" label="备注" />
  859. <el-table-column prop="operation" label="操作" width="280px">
  860. <template #default="scope">
  861. <el-button type="warning" text @click="resetPassword(scope.row)">
  862. 重置密码
  863. </el-button>
  864. <el-button type="primary" text @click="permissionEditInit(scope.row)"
  865. :disabled="scope.row.adminStatus === 0 || scope.row.account === adminData.account">
  866. 修改权限
  867. </el-button>
  868. <el-popconfirm title="确定将此用户删除吗?" @confirm="delConfirm">
  869. <template #reference>
  870. <el-button type="danger" text @click="del(scope.row)"
  871. :disabled="scope.row.adminStatus === 0 || scope.row.account === adminData.account">
  872. 删除
  873. </el-button>
  874. </template>
  875. <template #actions="{ confirm, cancel }">
  876. <el-button size="small" @click="cancel">取消</el-button>
  877. <el-button type="primary" size="small" @click="confirm">
  878. 确定
  879. </el-button>
  880. </template>
  881. </el-popconfirm>
  882. </template>
  883. </el-table-column>
  884. <el-table-column prop="adminStatus" label="状态">
  885. <template #default="scope">
  886. <el-switch :model-value="scope.row.adminStatus" :active-value="1" :inactive-value="0" size="large"
  887. :disabled="scope.row.account === adminData.account || statusLoading[scope.row.id]"
  888. @change="(targetStatus) => showStatusConfirm(scope.row, targetStatus)" style="
  889. --el-switch-on-color: #13ce66;
  890. --el-switch-off-color: #ff4949;
  891. " active-text="启用" inactive-text="禁用" inline-prompt />
  892. </template>
  893. </el-table-column>
  894. </el-table>
  895. <div class="pagination" style="margin-top: 1vh;">
  896. <el-pagination background :page-size="getObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]"
  897. layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handlePageSizeChange"
  898. @current-change="handleCurrentChange"></el-pagination>
  899. </div>
  900. </div>
  901. </el-card>
  902. </div>
  903. <!-- 新增用户权限 -->
  904. <el-dialog v-model="userAddVisible" title="新增用户权限" width="800px" :close-on-click-modal="false"
  905. @close="handleDialogClose">
  906. <template #footer>
  907. <el-form ref="Ref" :rules="addUserRules" :model="addAdmin" label-width="auto"
  908. style="max-width: 600px; align-items: center">
  909. <el-form-item prop="account" label="OA号:" required clearable>
  910. <el-input v-model="addAdmin.account" placeholder="请输入OA号" style="width: 220px" />
  911. </el-form-item>
  912. <el-form-item prop="name" label="用户名:" required clearable>
  913. <el-input v-model="addAdmin.name" placeholder="请输入用户名" style="width: 220px" />
  914. </el-form-item>
  915. <el-form-item prop="market" label="所属地区:" required clearable>
  916. <el-cascader v-model="addAdmin.market" :options="marketsTree" placeholder="请选择所属地区" clearable collapse-tags
  917. collapse-tags-tooltip style="width:220px" @change="handleMarketChangeAddUser" :max-collapse-tags="2"
  918. :props="addUserProps" />
  919. </el-form-item>
  920. <el-form-item prop="permission" label="角色名称:" required>
  921. <el-select v-model="addAdmin.permission" placeholder="请选择角色名称" style="width: 220px" clearable>
  922. <el-option v-for="item in permissionList" :key="item.value" :label="item.label"
  923. :value="item.value"></el-option>
  924. </el-select>
  925. </el-form-item>
  926. <el-form-item prop="postiton" label="职位:" required>
  927. <el-input v-model="addAdmin.postiton" placeholder="请输入职位" style="width: 220px" clearable />
  928. </el-form-item>
  929. <el-form-item prop="machineIds" label="机器码:" required>
  930. <div style="display: flex; align-items: center; flex-wrap: wrap; gap: 10px;">
  931. <!-- 动态添加的机器码输入框 -->
  932. <div v-for="(item, index) in addAdmin.machineIds" :key="index">
  933. <el-input v-model="addAdmin.machineIds[index]" placeholder="请输入机器码"
  934. style="width: 220px; margin-right: 10px;" />
  935. </div>
  936. <el-button type="primary" @click="addMachineIdInput">添加</el-button>
  937. </div>
  938. </el-form-item>
  939. <el-form-item prop="remark" label="备注">
  940. <el-input v-model="addAdmin.remark" style="width: 300px" :rows="2" maxlength="100" show-word-limit
  941. type="textarea" />
  942. </el-form-item>
  943. </el-form>
  944. <div>
  945. <el-button @click="closeUserAddVisible()">取消</el-button>
  946. <el-button type="primary" @click="throttledPermissionAdd()">
  947. 提交
  948. </el-button>
  949. </div>
  950. </template>
  951. </el-dialog>
  952. <!-- 这是编辑用户权限弹窗 -->
  953. <el-dialog v-model="userEditVisible" title="编辑用户权限" width="800px" :close-on-click-modal="false">
  954. <el-form ref="Ref" :rules="editAdminRules" :model="permissionEditObj" label-width="auto"
  955. style="max-width: 600px; align-items: center">
  956. <el-form-item prop="account" label="用户账号:" clearable>
  957. <el-input v-model="permissionEditObj.account" placeholder="请输入OA号" style="width: 220px" disabled />
  958. </el-form-item>
  959. <el-form-item prop="name" label="用户名称:">
  960. <el-input v-model="permissionEditObj.adminName" placeholder="请输入用户名" style="width: 220px" disabled />
  961. </el-form-item>
  962. <el-form-item prop="market" label="所属地区:" clearable>
  963. <el-cascader v-model="permissionEditObj.market" :options="marketsTree" placeholder="请选择所属地区" clearable
  964. collapse-tags collapse-tags-tooltip style="width:220px" @change="handleMarketChangeEditUser"
  965. :max-collapse-tags="2" :props="editUserProps" />
  966. </el-form-item>
  967. <el-form-item prop="postiton" label="职位:">
  968. <el-input v-model="permissionEditObj.postiton" placeholder="请输入职位" style="width: 220px" clearable />
  969. </el-form-item>
  970. <el-form-item prop="roleName" label="角色名称:">
  971. <el-select v-model="permissionEditObj.roleId" placeholder="请选择角色" style="width: 220px" @change="getUserLists">
  972. <el-option v-for="item in permissionList" :key="item.value" :label="item.label"
  973. :value="item.value"></el-option>
  974. </el-select>
  975. </el-form-item>
  976. <el-form-item prop="parentName" label="上级角色:">
  977. <el-select v-model="permissionEditObj.parentId" placeholder="无上级角色" :disabled="!!parentRoleTip"
  978. style="width: 220px">
  979. <el-option v-if="parentRoleTip" :key="0" :label="parentRoleTip" :value="null" disabled />
  980. <el-option v-else v-for="item in permissionList" :key="item.value" :label="item.label" disabled
  981. :value="item.value"></el-option>
  982. </el-select>
  983. </el-form-item>
  984. <el-form-item prop="permissionSelect" label="权限列表:">
  985. <el-tree v-if="data.length > 0" :data="data" :disabled="true" show-checkbox node-key="id"
  986. :props="{ label: 'menuName', children: 'children' }" :default-checked-keys="permissionEditObj.checkedKeys">
  987. </el-tree>
  988. <div v-else style="display: flex; align-items: center; gap: 8px;">
  989. <span style="color: #999;">暂无数据</span>
  990. </div>
  991. </el-form-item>
  992. <el-form-item prop="machineIds" label="机器码:">
  993. <div style="display: flex; align-items: center; flex-wrap: wrap; gap: 10px;">
  994. <!-- 动态添加的机器码输入框 -->
  995. <div v-for="(item, index) in permissionEditObj.machineIds" :key="index">
  996. <el-input v-model="permissionEditObj.machineIds[index]" placeholder=""
  997. style="width: 220px; margin-right: 10px;" />
  998. </div>
  999. <el-button type="primary" @click="UseraddMachineIdInput">添加</el-button>
  1000. </div>
  1001. </el-form-item>
  1002. </el-form>
  1003. <div>
  1004. </div>
  1005. <template #footer>
  1006. <div>
  1007. <el-button @click="closeUserEditVisible()">取消</el-button>
  1008. <el-button type="primary" @click="throttledPermissionEdit">
  1009. 提交
  1010. </el-button>
  1011. </div>
  1012. </template>
  1013. </el-dialog>
  1014. <!-- 重置密码确认弹窗 -->
  1015. <el-dialog v-model="resetConfirmVisible" width="500px" :close-on-click-modal="false"
  1016. :before-close="cancelResetPassword">
  1017. <el-row>
  1018. <el-col :span="4" style="margin-top: 20px">
  1019. <el-icon class="dialog-icon" color="#10AEFF" size="50">
  1020. <InfoFilled />
  1021. </el-icon>
  1022. </el-col>
  1023. <el-col :span="20">
  1024. <h3>提示</h3>
  1025. <p class="dialog-title">确认重置该账号密码</p>
  1026. <p class="dialog-desc">重置后密码为: 123456请通知用户及时修改</p>
  1027. </el-col>
  1028. </el-row>
  1029. <template #footer>
  1030. <div style="display: flex; justify-content: center; gap: 30px">
  1031. <el-button @click="cancelResetPassword">取消</el-button>
  1032. <el-button type="primary" @click="confirmResetPassword">确定</el-button>
  1033. </div>
  1034. </template>
  1035. </el-dialog>
  1036. <el-dialog v-model="ackVisible" :title="currentStatusRow?.adminStatus === 1 ? '确认禁用' : '确认启用'" width="300px"
  1037. :close-on-click-modal="false"
  1038. @close="() => { if (currentStatusRow) currentStatusRow.adminStatus = currentStatusRow.adminStatus === 1 ? 0 : 1 }">
  1039. <div class="status-confirm-content">
  1040. 确定要{{ currentStatusRow?.adminStatus === 1 ? '禁用' : '启用' }}该用户吗
  1041. <br>
  1042. </div>
  1043. <template #footer>
  1044. <div style="display: flex;">
  1045. <el-button @click="() => {
  1046. currentStatusRow.adminStatus = currentStatusRow.adminStatus === 1 ? 0 : 1
  1047. ackVisible = false
  1048. }">
  1049. 取消
  1050. </el-button>
  1051. <el-button type="primary" @click="() => {
  1052. editStatus(currentStatusRow)
  1053. ackVisible = false
  1054. }">
  1055. 确认
  1056. </el-button>
  1057. </div>
  1058. </template>
  1059. </el-dialog>
  1060. </template>
  1061. <style scoped>
  1062. .pagination {
  1063. display: flex;
  1064. }
  1065. .head-card {
  1066. display: flex;
  1067. }
  1068. .head-card-element {
  1069. margin-right: 20px;
  1070. }
  1071. .head-card-btn {
  1072. margin-left: auto;
  1073. }
  1074. </style>