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.

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