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.

892 lines
30 KiB

6 months ago
6 months ago
6 months ago
4 months ago
5 months ago
6 months ago
6 months ago
4 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
4 months ago
6 months ago
6 months ago
4 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
4 months ago
5 months ago
4 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
  1. <script setup>
  2. import { nextTick, onMounted, reactive, ref } from 'vue'
  3. import { ElMessage } from 'element-plus'
  4. import _ from 'lodash'
  5. import request from '@/util/http'
  6. import API from '@/util/http'
  7. import { useAdminStore } from "@/store/index.js"
  8. import { storeToRefs } from "pinia"
  9. const adminStore = useAdminStore();
  10. const { adminData, menuTree } = storeToRefs(adminStore);
  11. import { permissionMapping, findMenuById } from "@/utils/menuTreePermission.js"
  12. import { tr } from 'element-plus/es/locales.mjs'
  13. import { useI18n } from 'vue-i18n'
  14. // 表单验证ref
  15. const Ref = ref(null)
  16. const { t } = useI18n()
  17. const roleData = ref([])
  18. const tableRef = ref(null)
  19. const scrollTableTop = () => {
  20. tableRef.value?.setScrollTop?.(0)
  21. }
  22. const roleTotal = ref(100)
  23. const treeRef = ref(null)
  24. const admin = ref({
  25. account: '',
  26. market: '',
  27. postiton: ''
  28. })
  29. const role = ref({
  30. name: ''
  31. })
  32. const getRoleObj = ref({
  33. pageNum: 1,
  34. pageSize: 10
  35. })
  36. const permissionAddVisible = ref(false)
  37. // 新增角色表单数据
  38. const addRole = ref({
  39. roleName: '',
  40. parentId: null,
  41. checkedKeys: [],
  42. market: '',
  43. // 新增角色选择的频道名称
  44. channel: ''
  45. })
  46. const addRoleMarket = ref([])
  47. // 频道列表
  48. const channelList = ref([t('common.all')])
  49. // 新增弹窗是否需要展示“频道名称”下拉
  50. const addHasChannel = ref(false)
  51. // 编辑弹窗是否需要展示“频道名称”下拉
  52. const editHasChannel = ref(false)
  53. const getRoleList = async function (val) {
  54. if (!findMenuById(menuTree.value, permissionMapping.view_role_information)) {
  55. // 无此权限
  56. ElMessage.error(t('elmessage.noPermissionText'))
  57. return
  58. }
  59. try {
  60. if (typeof val === 'number') {
  61. getRoleObj.value.pageNum = val
  62. }
  63. console.log('搜索参数', getRoleObj.value, role.value)
  64. const result = await request({
  65. url: '/role/selectBy',
  66. data: {
  67. ...getRoleObj.value,
  68. roleVo: {
  69. roleName: role.value.name
  70. }
  71. }
  72. })
  73. roleData.value = result.data.list || []
  74. await nextTick()
  75. scrollTableTop()
  76. console.log('roleData', roleData.value)
  77. roleTotal.value = result.data.total
  78. } catch (error) {
  79. console.log('请求失败', error)
  80. }
  81. }
  82. // 试试D老师的方法
  83. const formatPermissions = (tree) => {
  84. if (!tree || tree.length === 0) return '';
  85. return tree.map(menu => {
  86. const mainMenu = menu.menuName;
  87. const subMenus = menu.children?.map(child => child.menuName) || [];
  88. // 如果有子菜单,显示前2个子菜单名称
  89. if (subMenus.length > 0) {
  90. const maxSub = Math.min(2, subMenus.length);
  91. const subText = subMenus.slice(0, maxSub).join('、');
  92. const moreText = subMenus.length > maxSub ? '...' : '';
  93. return `${mainMenu}+${subText}${moreText}`;
  94. }
  95. // 没有子菜单时只显示主菜单
  96. return mainMenu;
  97. }).join('+');
  98. };
  99. const trimJwCode = () => {
  100. if (admin.value.account) {
  101. admin.value.account = admin.value.account.replace(/\s/g, '');
  102. }
  103. }
  104. const searchRole = function () {
  105. trimJwCode();
  106. getRoleObj.value.pageNum = 1
  107. getRoleList()
  108. }
  109. // 重置
  110. const reset = function () {
  111. admin.value = {}
  112. role.value.name = ''
  113. // 重置页码
  114. getRoleObj.value.pageNum = 1
  115. getRoleList()
  116. }
  117. const RoleArea = ref([])
  118. const getRoleArea = async function () {
  119. try {
  120. const result = await request({
  121. url: '/general/allRoleMarket',
  122. data: {}
  123. })
  124. RoleArea.value = result.data
  125. } catch (error) {
  126. console.log('请求失败', error)
  127. }
  128. }
  129. // 新增角色弹窗
  130. const openPermissionAddVisible = function () {
  131. permissionAddVisible.value = true
  132. // 打开新增弹窗时,重置“频道相关”的显示与选中状态,避免受上一次操作影响
  133. addHasChannel.value = false
  134. addRole.value.channel = ''
  135. getRoles()
  136. getLists()
  137. }
  138. const closePermissionAddVisible = function () {
  139. permissionAddVisible.value = false
  140. // 关闭时也重置一次,确保下次打开是干净状态
  141. addHasChannel.value = false
  142. addRole.value.channel = ''
  143. Ref.value.resetFields();
  144. getRoleList()
  145. }
  146. // 新增角色初始化
  147. const permissionAddInit = function () {
  148. openPermissionAddVisible()
  149. }
  150. const handleDialogClose = function () {
  151. closePermissionAddVisible()
  152. console.log('hhh');
  153. }
  154. // 权限类别
  155. const permissionList = ref([])
  156. const getRoles = async function () {
  157. try {
  158. const res = await API({ url: '/role/selectAll' })
  159. permissionList.value = res.data.map(item => ({
  160. label: item.roleName,
  161. value: item.id
  162. }))
  163. console.log('权限列表:', permissionList.value)
  164. } catch (error) {
  165. console.error('获取权限列表失败:', error)
  166. }
  167. }
  168. const collectIds = (tree) => {
  169. let ids = [];
  170. tree.forEach((node) => {
  171. ids.push(node.id);
  172. if (node.children && node.children.length > 0) {
  173. ids = ids.concat(collectIds(node.children));
  174. }
  175. });
  176. return ids;
  177. }
  178. //给data数据加上disabled属性,控制是否禁用
  179. function processTreeData(data) {
  180. return data.map(item => ({
  181. ...item,
  182. disabled: item.id != null || item.menuName.includes("敏感权限"), //控制权限显示的条件
  183. children: item.children ? processTreeData(item.children) : []
  184. }));
  185. }
  186. const handleAddRole = async function () {
  187. if (!findMenuById(menuTree.value, permissionMapping.add_role_information)) {
  188. ElMessage.error(t('elmessage.noPermissionText'))
  189. return
  190. }
  191. try {
  192. await new Promise((resolve, reject) => {
  193. Ref.value.validate((valid) => {
  194. if (valid) {
  195. resolve(); // 验证通过,继续执行后续代码
  196. } else {
  197. reject(new Error(t('elmessage.checkFormInfo'))); // 验证失败,抛出错误
  198. }
  199. });
  200. });
  201. addRole.value.roleName = addRole.value.roleName.replace(/\s+/g, '');
  202. console.log('去除角色名空格:', addRole.value.roleName);
  203. // 确保提交时包含所有选中的权限ID(包括父节点)
  204. const finalCheckedKeys = addRole.value.checkedKeys || [];
  205. const res = await API({
  206. url: '/role/add',
  207. data: {
  208. "roleName": addRole.value.roleName,
  209. "menuIds": finalCheckedKeys,
  210. "fatherId": addRole.value.parentId,
  211. "market": addRole.value.market,
  212. channel: addRole.value.channel
  213. }
  214. })
  215. if (res.code === 200) {
  216. ElMessage.success(t('elmessage.roleAddSuccess', { roleName: addRole.value.roleName }))
  217. console.log('成功了,看看addRole', addRole.value)
  218. console.log('提交的权限ID列表:', finalCheckedKeys)
  219. closePermissionAddVisible()
  220. } else {
  221. ElMessage.error(res.msg)
  222. }
  223. } catch (error) {
  224. console.log('请求失败', error)
  225. console.log('失败,看看addRole', addRole.value)
  226. }
  227. }
  228. const handleRolePageSizeChange = (val) => {
  229. getRoleObj.value.pageSize = val
  230. getRoleList() // 调用角色管理的查询
  231. }
  232. // 角色管理分页 - 当前页变化
  233. const handleRoleCurrentChange = (val) => {
  234. getRoleObj.value.pageNum = val
  235. getRoleList() // 调用角色管理的查询
  236. }
  237. const data = ref([])
  238. const getLists = async function () {
  239. try {
  240. console.log('addRole.value.roleId', addRole.value.roleId);
  241. let roleId = addRole.value.parentId
  242. if (addRole.value.parentId === null || addRole.value.parentId === undefined) {
  243. roleId = 2
  244. }
  245. const res = await API({
  246. url: '/menu/tree',
  247. data: { id: roleId }
  248. })
  249. data.value = res.data
  250. data.value = filterPermission(data.value)
  251. console.log('看看data', data.value)
  252. console.log('parentID:', addRole.value.parentId, 'roleId:', roleId)
  253. if (addRole.value.parentId && addRole.value.parentId !== 2) {
  254. const result = await API({
  255. url: '/general/roleMarket',
  256. data: { id: addRole.value.parentId }
  257. })
  258. if (result.code === 200) {
  259. if (typeof result.data === 'string' && result.data) {
  260. addRoleMarket.value = result.data.split(',')
  261. addRole.value.market = ''
  262. } else if (Array.isArray(result.data)) {
  263. addRoleMarket.value = result.data
  264. addRole.value.market = ''
  265. } else {
  266. addRoleMarket.value = []
  267. addRole.value.market = ''
  268. }
  269. } else {
  270. ElMessage.error(t('elmessage.noParentRoleMarket'))
  271. console.log('该上级角色无归属地区')
  272. }
  273. console.log('addRoleMarket.value', addRoleMarket.value)
  274. } else {
  275. addRoleMarket.value = RoleArea.value
  276. console.log('elseRoleArea', RoleArea);
  277. }
  278. } catch (error) {
  279. console.log('请求失败', error)
  280. }
  281. }
  282. //获取频道列表
  283. const getChannelList = async () => {
  284. try {
  285. const res = await API({
  286. url: '/role/getChannel',
  287. })
  288. console.log('res', res);
  289. if (res.code == 200) {
  290. channelList.value = [...channelList.value, ...res.data]
  291. } else {
  292. console.log('获取频道列表', res.msg);
  293. }
  294. } catch (err) {
  295. console.log('获取频道列表出错', err);
  296. }
  297. }
  298. //金豆过滤
  299. const goldenBeanMenuIds = new Set([
  300. permissionMapping.gold_bean_audit,
  301. permissionMapping.gold_bean_recharge,
  302. permissionMapping.gold_bean_consumption,
  303. permissionMapping.gold_bean_customer_details
  304. ])
  305. // 15,43,44,45,46,47,// 金豆审核
  306. // 18,52,53,54,// 金豆充值
  307. // 20,57,58,59,60,// 金豆消耗
  308. // 23// 金豆客户账户明细
  309. const filterGoldenBeanMenus = (tree) => {
  310. return tree
  311. .filter(item => {
  312. // 排除金豆相关的顶层菜单
  313. if (goldenBeanMenuIds.has(item.id)) {
  314. return false
  315. }
  316. // 递归处理子菜单
  317. if (item.children && item.children.length > 0) {
  318. item.children = filterGoldenBeanMenus(item.children)
  319. }
  320. return true
  321. })
  322. }
  323. // 过滤权限模块(????????)俺不会
  324. const filterPermission = (tree) => {
  325. return tree.filter(item => {
  326. if (item.id === permissionMapping.permission_management) {
  327. return false
  328. } else if (item.children && item.children.length > 0) {
  329. item.children = filterPermission(item.children)
  330. }
  331. return true
  332. })
  333. }
  334. // 处理编辑角色权限时的勾选事件(编辑弹窗专用)
  335. const handleEditRolePermissionCheck = (checkedNodes, checkedInfo) => {
  336. const { checkedKeys, checkedNodes: allCheckedNodes } = checkedInfo
  337. // 判断是否有选中的节点
  338. if (allCheckedNodes.length === 0) {
  339. permissionEditRoleObj.value.checkedKeys = []
  340. // 没有任何权限时,不显示频道下拉
  341. editHasChannel.value = false
  342. return
  343. }
  344. // 由于设置了 check-strictly="false",Element Plus 会自动处理父子节点联动
  345. // 我们只需要使用 checkedKeys,它已经包含了所有必要的节点ID
  346. permissionEditRoleObj.value.checkedKeys = checkedKeys
  347. console.log('编辑角色选中的权限ID:', checkedKeys)
  348. console.log('选中的节点数量:', allCheckedNodes.length)
  349. if (checkedKeys.includes(124) || checkedKeys.includes(125) || checkedKeys.includes(126) || checkedKeys.includes(127)) {
  350. // 编辑时勾选了频道管理相关菜单 -> 显示频道下拉
  351. editHasChannel.value = true
  352. } else {
  353. editHasChannel.value = false
  354. }
  355. };
  356. // 新增弹窗权限树勾选事件(新增弹窗专用)
  357. const handleCheckChange = async (checkedNodes, checkedInfo) => {
  358. const { checkedKeys, checkedNodes: allCheckedNodes } = checkedInfo
  359. // 判断是否有选中的节点
  360. if (allCheckedNodes.length === 0) {
  361. addRole.value.checkedKeys = []
  362. // 新增时没有任何权限时,不显示频道下拉
  363. addHasChannel.value = false
  364. return
  365. }
  366. // 创建一个Set存储所有需要选中的ID(包括父级)
  367. const allKeys = new Set(checkedKeys)
  368. // 遍历所有选中的节点,为每个节点添加其父级
  369. allCheckedNodes.forEach(node => {
  370. // 为每个选中的节点单独查找父级
  371. selectParentNodes(data.value, node.id, allKeys)
  372. });
  373. // 将Set转换为数组并更新
  374. addRole.value.checkedKeys = Array.from(allKeys)
  375. console.log('新增角色包含所有父级的选中项:', addRole.value.checkedKeys)
  376. if (addRole.value.checkedKeys.includes(124)) {
  377. // 新增时勾选了频道管理菜单 -> 显示频道下拉
  378. addHasChannel.value = true
  379. console.log('勾选了频道');
  380. } else {
  381. addHasChannel.value = false
  382. }
  383. }
  384. const selectParentNodes = (treeData, nodeId, checkedKeys) => {
  385. if (!Array.isArray(treeData)) return false
  386. for (const item of treeData) {
  387. // 先检查子节点
  388. if (item.children && item.children.length > 0) {
  389. const foundInChildren = selectParentNodes(item.children, nodeId, checkedKeys);
  390. if (foundInChildren) {
  391. // 找到子节点后添加当前节点(父节点)
  392. checkedKeys.add(item.id);
  393. return true
  394. }
  395. }
  396. // 检查当前节点是否为目标节点
  397. if (item.id === nodeId) {
  398. return true
  399. }
  400. }
  401. return false
  402. };
  403. //点击角色权限菜单树点击展示逻辑
  404. const menuTreeVisible = ref(false)
  405. const currentRoleMenuTree = ref([])
  406. const currentRoleName = ref('')
  407. const Rolecheckedkeys = ref([])
  408. const showMenuTree = (treeData, roleName) => {
  409. currentRoleMenuTree.value = processTreeData(treeData) || [];
  410. console.log('currentRoleMenuTree.value', currentRoleMenuTree.value)
  411. Rolecheckedkeys.value = collectIds(treeData)
  412. console.log('Rolecheckedkeys', Rolecheckedkeys.value)
  413. currentRoleName.value = roleName || t('common_add.permissionDetails')
  414. menuTreeVisible.value = true;
  415. }
  416. // 编辑角色对象
  417. const permissionEditRoleObj = ref({
  418. id: null,
  419. roleName: '',
  420. market: '',
  421. parentId: null,
  422. parentName: '',
  423. checkedKeys: [],
  424. channel: ''
  425. })
  426. // 编辑角色弹窗
  427. const permissionEditRoleVisible = ref(false)
  428. // 编辑弹窗关闭时,顺便把“编辑态是否显示频道下拉”的标记重置
  429. const closePermissionEditRoleVisible = () => {
  430. permissionEditRoleVisible.value = false
  431. editHasChannel.value = false
  432. }
  433. const collectIds2 = (tree) => {
  434. let ids = []
  435. tree.forEach((node) => {
  436. // 如果当前节点没有 children 或 children 为空,说明是叶子节点
  437. if (!node.children || node.children.length === 0) {
  438. ids.push(node.id)
  439. } else {
  440. // 如果有 children,递归收集子节点的叶子节点
  441. ids = ids.concat(collectIds2(node.children))
  442. }
  443. })
  444. return ids
  445. }
  446. const collectIdsAll = (tree) => {
  447. let ids = []
  448. tree.forEach((node) => {
  449. ids.push(node.id)
  450. // 如果当前节点没有 children 或 children 为空,说明是叶子节点
  451. if (node.children || node.children.length === 0) {
  452. ids = ids.concat(collectIdsAll(node.children))
  453. }
  454. })
  455. return ids
  456. }
  457. // 编辑角色初始化
  458. const permissionEditRoleInit = async function (row) {
  459. console.log('row', row)
  460. console.log('row.tree', row.tree)
  461. let EditIds = collectIdsAll(row.tree)
  462. console.log(EditIds);
  463. permissionEditRoleObj.value = {}
  464. permissionEditRoleObj.value.id = row.id
  465. permissionEditRoleObj.value.roleName = row.roleName
  466. permissionEditRoleObj.value.market = row.market
  467. permissionEditRoleObj.value.parentId = row.fatherId
  468. permissionEditRoleObj.value.parentName = row.fatherName
  469. permissionEditRoleObj.value.channel = row.channel
  470. console.log('permissionEditRoleObj.value', permissionEditRoleObj.value);
  471. if (EditIds.includes(124)) {
  472. // 编辑初始化时,根据已有权限决定是否展示频道下拉
  473. editHasChannel.value = true
  474. } else {
  475. editHasChannel.value = false
  476. }
  477. try {
  478. let roleId = permissionEditRoleObj.value.parentId;
  479. // 如果没有上级角色,设置为管理员的id
  480. if (permissionEditRoleObj.value.parentId === null || permissionEditRoleObj.value.parentId === undefined) {
  481. roleId = 2;
  482. }
  483. // 调用 /tree 接口,使用上级角色 ID 获取权限列表
  484. const res = await API({
  485. url: '/menu/tree',
  486. data: { id: roleId }
  487. });
  488. data.value = res.data;
  489. data.value = filterPermission(data.value)
  490. //data.value = filterGoldenBeanMenus(data.value);
  491. // 收集当前行权限树的叶子节点id(只收集实际选中的叶子节点)
  492. if (row.tree && row.tree.length > 0) {
  493. const leafIds = collectIds2(row.tree);
  494. permissionEditRoleObj.value.checkedKeys = leafIds;
  495. console.log('编辑角色初始化时的权限列表', permissionEditRoleObj.value.checkedKeys);
  496. } else {
  497. permissionEditRoleObj.value.checkedKeys = [];
  498. }
  499. } catch (error) {
  500. console.log('根据上级角色获取权限列表失败', error);
  501. data.value = [];
  502. permissionEditRoleObj.value.checkedKeys = [];
  503. }
  504. console.log('编辑角色', permissionEditRoleObj.value);
  505. permissionEditRoleVisible.value = true;
  506. // 等待DOM更新后手动设置树的选中状态
  507. await nextTick();
  508. if (treeRef.value && permissionEditRoleObj.value.checkedKeys.length > 0) {
  509. treeRef.value.setCheckedKeys(permissionEditRoleObj.value.checkedKeys);
  510. console.log('手动设置树的选中状态:', permissionEditRoleObj.value.checkedKeys);
  511. }
  512. };
  513. // 编辑角色提交
  514. const permissionEditRole = async function () {
  515. if (!findMenuById(menuTree.value, permissionMapping.edit_role_information)) {
  516. ElMessage.error(t('elmessage.noPermission'))
  517. return
  518. }
  519. try {
  520. await new Promise((resolve, reject) => {
  521. Ref.value.validate((valid) => {
  522. if (valid) {
  523. resolve();
  524. } else {
  525. reject(new Error(t('elmessage.checkFormInfo')));
  526. }
  527. });
  528. });
  529. // 确保提交时包含所有选中的权限ID(包括父节点)
  530. let finalCheckedKeys = permissionEditRoleObj.value.checkedKeys || [];
  531. // 为所有选中的节点添加其父节点ID
  532. const allKeys = new Set(finalCheckedKeys);
  533. finalCheckedKeys.forEach(nodeId => {
  534. selectParentNodesForSubmit(data.value, nodeId, allKeys);
  535. });
  536. finalCheckedKeys = Array.from(allKeys);
  537. const res = await API({
  538. url: '/menu/update',
  539. data: {
  540. ...permissionEditRoleObj.value,
  541. menuIds: finalCheckedKeys
  542. }
  543. });
  544. if (res.code === 200) {
  545. console.log('编辑角色成功', permissionEditRoleObj.value);
  546. console.log('提交的权限ID列表:', finalCheckedKeys);
  547. permissionEditRoleVisible.value = false;
  548. getRoleList();
  549. ElMessage.success(t('elmessage.editSuccess'));
  550. } else if (res.code === 0) {
  551. console.log('角色名重复', permissionEditRoleObj.value);
  552. ElMessage.error(t('elmessage.roleNameDuplicate'));
  553. } else {
  554. console.log('编辑角色失败', res);
  555. ElMessage.error(t('elmessage.editFailed'));
  556. }
  557. } catch (error) {
  558. console.log('编辑角色失败', error);
  559. console.log('失败,看看permissionEditRoleObj', permissionEditRoleObj.value);
  560. }
  561. };
  562. // 为提交时查找父节点的辅助函数
  563. const selectParentNodesForSubmit = (treeData, nodeId, checkedKeys) => {
  564. if (!Array.isArray(treeData)) return false;
  565. for (const item of treeData) {
  566. // 先检查子节点
  567. if (item.children && item.children.length > 0) {
  568. const foundInChildren = selectParentNodesForSubmit(item.children, nodeId, checkedKeys);
  569. if (foundInChildren) {
  570. // 找到子节点后添加当前节点(父节点)
  571. checkedKeys.add(item.id);
  572. return true;
  573. }
  574. }
  575. // 检查当前节点是否为目标节点
  576. if (item.id === nodeId) {
  577. return true;
  578. }
  579. }
  580. return false;
  581. };
  582. const Rolerules = reactive({
  583. roleName: [
  584. { required: true, message: t('elmessage.inputRoleName'), trigger: 'blur' },
  585. { min: 2, max: 20, message: t('elmessage.roleNameLengthLimit'), trigger: 'blur' }
  586. ],
  587. market: [
  588. { required: true, message: t('elmessage.selectMarket'), trigger: 'change' }
  589. ],
  590. checkedKeys: [
  591. {
  592. required: true,
  593. message: t('elmessage.selectPermissionList'),
  594. trigger: 'change', // 选框变化或提交时触发,可根据实际调整
  595. validator: (rule, value, callback) => {
  596. if (value && value.length > 0) {
  597. callback(); // 有选中项,校验通过
  598. } else {
  599. callback(new Error(t('elmessage.selectPermissionList'))); // 未选中,抛出错误提示
  600. }
  601. }
  602. }
  603. ]
  604. });
  605. const throttledHandleAddRole = _.throttle(handleAddRole, 5000, {
  606. trailing: false
  607. })
  608. const canLook = findMenuById(menuTree.value, permissionMapping.view_role_information)
  609. const canAdd = findMenuById(menuTree.value, permissionMapping.add_role_information)
  610. const canEdit = findMenuById(menuTree.value, permissionMapping.edit_role_information)
  611. // 挂载
  612. onMounted(async function () {
  613. await getRoleList()
  614. await getRoleArea()
  615. await getChannelList()
  616. })
  617. </script>
  618. <template>
  619. <div>
  620. <el-card class="card1" style="margin-bottom: 1vh;">
  621. <div style="display: flex;">
  622. <el-text size="large">{{ t('common.roleName') }}</el-text>
  623. <el-input v-model="role.name" style="width: 240px" :placeholder="t('common.roleNamePlaceholder')" clearable />
  624. <div style="margin-left: auto;">
  625. <el-button type="primary" @click="searchRole()" :disabled="!canLook" v-if="canLook">{{ t('common.search') }}</el-button>
  626. <el-button type="success" @click="reset()">{{ t('common.reset') }}</el-button>
  627. </div>
  628. </div>
  629. </el-card>
  630. <el-card class="card2">
  631. <div class="add-item">
  632. <el-button style="color: #048efb; border: 1px solid #048efb" @click="permissionAddInit()" :disabled="!canAdd"
  633. v-if="canAdd">{{ t('common.addRole') }}
  634. </el-button>
  635. </div>
  636. <div>
  637. <el-table ref="tableRef" :data="roleData" style="width: 82vw;height:71.3vh" show-overflow-tooltip
  638. :row-style="{ height: '56px' }">
  639. <el-table-column type="index" :label="t('common_list.id')" width="100px" fixed="left">
  640. <template #default="scope">
  641. <span>{{
  642. scope.$index + 1 + (getRoleObj.pageNum - 1) * getRoleObj.pageSize
  643. }}</span>
  644. </template>
  645. </el-table-column>
  646. <el-table-column prop="roleName" :label="t('common_list.roleName')" />
  647. <el-table-column prop="fatherName" :label="t('common_list.parentRole')">
  648. <template #default="scope">
  649. {{ scope.row.fatherName || '-' }}
  650. </template>
  651. </el-table-column>
  652. <el-table-column :label="t('common_list.permissionScope')" show-overflow-tooltip>
  653. <template #default="scope">
  654. <div class="permission-cell" @click="showMenuTree(scope.row.tree, scope.row.roleName)">
  655. {{ formatPermissions(scope.row.tree) }}
  656. </div>
  657. </template>
  658. </el-table-column>
  659. <el-table-column prop="operation" :label="t('common_list.operation')" width="200px">
  660. <template #default="scope">
  661. <el-button type="warning" text @click="permissionEditRoleInit(scope.row)"
  662. :disabled="(scope.row.id === 2) || (scope.row.id === 1) || !canEdit" v-if="canEdit">
  663. {{ t('common.edit') }}
  664. </el-button>
  665. </template>
  666. </el-table-column>
  667. </el-table>
  668. </div>
  669. <div style="margin-top: 20px;display: flex;">
  670. <el-pagination background :current-page="getRoleObj.pageNum" :page-size="getRoleObj.pageSize"
  671. :page-sizes="[5, 10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper" :total="roleTotal"
  672. @size-change="handleRolePageSizeChange" @current-change="handleRoleCurrentChange"></el-pagination>
  673. </div>
  674. </el-card>
  675. </div>
  676. <!-- 角色菜单树展示 -->
  677. <el-dialog v-model="menuTreeVisible" :title="`${t('common_add.permissionDetails')}:${currentRoleName}`" width="600px">
  678. <el-tree :data="currentRoleMenuTree" node-key="id" :props="{ label: 'menuName', children: 'children' }"
  679. show-checkbox check-strictly :expand-on-click-node="false"
  680. :default-expanded-keys="currentRoleMenuTree.map(item => item.id)" :default-checked-keys="Rolecheckedkeys" />
  681. <template #footer>
  682. <el-button @click="menuTreeVisible = false" type="primary">{{ t('common.close') }}</el-button>
  683. </template>
  684. </el-dialog>
  685. <!-- 新增角色 -->
  686. <el-dialog v-model="permissionAddVisible" :title="t('common_add.addRole')" width="800px" :close-on-click-modal="false"
  687. @close="handleDialogClose">
  688. <template #footer>
  689. <el-form ref="Ref" :rules="Rolerules" :model="addRole" label-width="auto"
  690. style="max-width: 600px; align-items: center">
  691. <el-form-item prop="roleName" :label="t('common_add.roleName') + ':'" required>
  692. <el-input v-model="addRole.roleName" :placeholder="t('common_add.roleNamePlaceholder')" style="width: 220px" />
  693. </el-form-item>
  694. <el-form-item prop="parentName" :label="t('common_add.parentRole') + ':'">
  695. <el-select v-model="addRole.parentId" :placeholder="t('common_add.parentRole')" style="width: 220px" @change="getLists" clearable>
  696. <el-option v-for="item in permissionList" :key="item.value" :label="item.label"
  697. :value="item.value"></el-option>
  698. </el-select>
  699. </el-form-item>
  700. <el-form-item prop="market" :label="t('common.market') + ':'" required>
  701. <el-select v-model="addRole.market" :placeholder="t('common.marketPlaceholder')" style="width: 220px" clearable>
  702. <el-option v-for="item in addRoleMarket" :key="item" :label="item" :value="item" />
  703. </el-select>
  704. <text>{{ t('permission.roleRegionNote') || '' }}</text>
  705. </el-form-item>
  706. <el-form-item prop="checkedKeys" :label="t('common_add.permissionList') + ':'" required>
  707. <el-tree v-if="data.length > 0" :data="data" show-checkbox node-key="id"
  708. :props="{ label: 'menuName', children: 'children' }" :checked-keys="addRole.checkedKeys"
  709. :check-strictly="false" @check="handleCheckChange">
  710. <template #default="{ node }">
  711. <span>{{ node.label }}</span>
  712. </template>
  713. </el-tree>
  714. <div v-else style="display: flex; align-items: center; gap: 8px;">
  715. <span style="color: #999;">{{ t('common.noData') }}</span>
  716. </div>
  717. </el-form-item>
  718. <el-form-item v-show="addHasChannel" :label="t('common_add.channelName') + ':'" required>
  719. <el-select v-model="addRole.channel" :placeholder="t('common_add.channelPlaceholder')" style="width: 220px" filterable clearable>
  720. <el-option v-for="item in channelList" :key="item" :label="item" :value="item" />
  721. </el-select>
  722. </el-form-item>
  723. </el-form>
  724. <div>
  725. <el-button @click="closePermissionAddVisible()">{{ t('common.cancel') }}</el-button>
  726. <el-button type="primary" @click="throttledHandleAddRole">
  727. {{ t('common.submit') }}
  728. </el-button>
  729. </div>
  730. </template>
  731. </el-dialog>
  732. <!-- 編輯角色彈窗 -->
  733. <el-dialog v-model="permissionEditRoleVisible" :title="t('common_add.editRole')" width="800px" :close-on-click-modal="false">
  734. <template #footer>
  735. <el-form ref="Ref" :rules="Rolerules" :model="permissionEditRoleObj" label-width="auto"
  736. style="max-width: 600px; align-items: center">
  737. <el-form-item prop="roleName" :label="t('common_add.roleName') + ':'" required>
  738. <el-input v-model="permissionEditRoleObj.roleName" :placeholder="t('common_add.roleNamePlaceholder')" style="width: 220px" />
  739. </el-form-item>
  740. <el-form-item prop="parentName" :label="t('common_add.parentRole') + ':'">
  741. <el-input v-model="permissionEditRoleObj.parentName" :placeholder="t('common_add.noParentRole')" disabled style="width: 220px">
  742. <el-option v-for="item in permissionList" :key="item.value" :label="item.label"
  743. :value="item.value"></el-option>
  744. </el-input>
  745. </el-form-item>
  746. <el-form-item prop="market" :label="t('common.market')" required>
  747. <el-input v-model="permissionEditRoleObj.market" :placeholder="t('common.marketPlaceholder')" style="width: 220px" disabled />
  748. <text>{{ t('permission.roleRegionNote') || '' }}</text>
  749. </el-form-item>
  750. <el-form-item prop="checkedKeys" :label="t('common_add.permissionList') + ':'" required>
  751. <el-tree v-if="data.length > 0" :data="data" show-checkbox node-key="id" ref="treeRef"
  752. :props="{ label: 'menuName', children: 'children' }"
  753. :default-checked-keys="permissionEditRoleObj.checkedKeys" :check-strictly="false"
  754. @check="handleEditRolePermissionCheck">
  755. <!-- <template #default="{ node, data }"> data删掉了不影响功能 -->
  756. <template #default="{ node }">
  757. <span>{{ node.label }}</span>
  758. </template>
  759. </el-tree>
  760. <div v-else style="display: flex; align-items: center; gap: 8px;">
  761. <span style="color: #999;">{{ t('common.noData') }}</span>
  762. </div>
  763. </el-form-item>
  764. <el-form-item v-show="editHasChannel" :label="t('common_add.channelName') + ':'" required>
  765. <el-select v-model="permissionEditRoleObj.channel" :placeholder="t('common_add.channelPlaceholder')" style="width: 220px" clearable>
  766. <el-option v-for="item in channelList" :key="item" :label="item" :value="item" />
  767. </el-select>
  768. </el-form-item>
  769. </el-form>
  770. <div>
  771. <el-button @click="closePermissionEditRoleVisible">{{ t('common.cancel') }}</el-button>
  772. <el-button type="primary" @click="permissionEditRole">
  773. {{ t('common.submit') }}
  774. </el-button>
  775. </div>
  776. </template>
  777. </el-dialog>
  778. </template>
  779. <style scoped lang="scss">
  780. // 新增用户按钮
  781. .add-item {
  782. margin-bottom: 1vh;
  783. }
  784. // 搜索的卡片样式
  785. .card1 {
  786. background: #F3FAFE;
  787. }
  788. // 表单的卡片样式
  789. .card2 {
  790. background: #E7F4FD;
  791. }
  792. // 表头背景等
  793. :deep(.el-table__header-wrapper),
  794. :deep(.el-table__body-wrapper),
  795. :deep(.el-table__cell),
  796. /* 表格 */
  797. :deep(.el-table__body td) {
  798. background-color: #F3FAFE !important;
  799. }
  800. /* 表头 */
  801. :deep(.el-table__header th) {
  802. background-color: #F3FAFE !important;
  803. }
  804. /* 鼠标悬停 */
  805. :deep(.el-table__row:hover > .el-table__cell) {
  806. background-color: #E5EBFE !important;
  807. }
  808. .head-card {
  809. display: flex;
  810. }
  811. .permission-cell {
  812. cursor: pointer;
  813. color: #409eff;
  814. /* 蓝色文字,提示可点击 */
  815. }
  816. </style>