index.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. <script setup lang="ts">
  2. import {
  3. httpRoleAll,
  4. httpMenuAll,
  5. httpUpdate,
  6. httpDetail
  7. } from "/@/api/interest/action";
  8. import { reactive, ref, onMounted, computed, nextTick } from "vue";
  9. import { ElMessage } from "element-plus";
  10. import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
  11. import { useNav } from "/@/layout/hooks/nav";
  12. const { logout } = useNav();
  13. defineOptions({
  14. name: "User"
  15. });
  16. const roleList = ref([]);
  17. const loading = ref(true);
  18. const backupMenuactionList = ref([]);
  19. const menuactionList = ref([]);
  20. const editType = ref("add");
  21. const action_list = ref([]);
  22. const action_data_list = ref([]);
  23. const private_data_list = ref([]);
  24. const ruleForm = reactive<menuType>({
  25. roleid: "",
  26. role_name: "",
  27. level: "1",
  28. action: [],
  29. private_data: []
  30. });
  31. // 全选/全不选
  32. const handleCheckAllChange = (checkAll, index, item, subIndex) => {
  33. menuactionList.value[index].child[subIndex].checkAll = checkAll;
  34. // this.$set(menuactionList.value, index, item);
  35. menuactionList.value[index].child[subIndex].action.forEach(element => {
  36. const findindex = menuactionList.value[index].child[
  37. subIndex
  38. ].checkList.findIndex(findItem => findItem === element.id);
  39. if (checkAll && findindex == -1) {
  40. menuactionList.value[index].child[subIndex].checkList.push(element.id);
  41. } else if (!checkAll && findindex > -1) {
  42. menuactionList.value[index].child[subIndex].checkList.splice(
  43. findindex,
  44. 1
  45. );
  46. }
  47. });
  48. };
  49. // 全选/全不选
  50. const handleFieldAllChange = (fieldAll, index, item, subIndex) => {
  51. menuactionList.value[index].child[subIndex].fieldAll = fieldAll;
  52. // this.$set(menuactionList.value, index, item);
  53. menuactionList.value[index].child[subIndex].action_data.forEach(element => {
  54. const findindex = menuactionList.value[index].child[
  55. subIndex
  56. ].fieldList.findIndex(findItem => findItem === element.id);
  57. if (fieldAll && findindex == -1) {
  58. menuactionList.value[index].child[subIndex].fieldList.push(element.id);
  59. } else if (!fieldAll && findindex > -1) {
  60. menuactionList.value[index].child[subIndex].fieldList.splice(
  61. findindex,
  62. 1
  63. );
  64. }
  65. });
  66. };
  67. // 复选框组内的选中/不选中
  68. const handleCheckedGroupChange = (event, index, item, subIndex) => {
  69. menuactionList.value[index].child[subIndex].checkAll = menuactionList.value[
  70. index
  71. ].child[subIndex].action.every(
  72. evitem =>
  73. menuactionList.value[index].child[subIndex].checkList.findIndex(
  74. finditem => finditem === evitem.id
  75. ) > -1
  76. );
  77. // this.$set(menuactionList.value, index, item);
  78. };
  79. // 复选框组内的选中/不选中
  80. const handleFieldGroupChange = (event, index, item, subIndex) => {
  81. menuactionList.value[index].child[subIndex].fieldAll = menuactionList.value[
  82. index
  83. ].child[subIndex].action_data.every(
  84. evitem =>
  85. menuactionList.value[index].child[subIndex].fieldList.findIndex(
  86. finditem => finditem === evitem.id
  87. ) > -1
  88. );
  89. // this.$set(menuactionList.value, index, item);
  90. };
  91. // 单项复选框选中/不选中
  92. const handleCheckedChange = (checked, id, index, subIndex, item) => {
  93. // console.log(checked, id, index, subIndex);
  94. if (checked) {
  95. // 选中时检查pid的选中状态
  96. menuactionList.value[index].child[subIndex].checkList.indexOf(id) == -1 &&
  97. menuactionList.value[index].child[subIndex].checkList.push(id);
  98. } else {
  99. const find = menuactionList.value[index].child[
  100. subIndex
  101. ].checkList.findIndex(e => e == id);
  102. if (find > -1) {
  103. menuactionList.value[index].child[subIndex].checkList.splice(find, 1);
  104. }
  105. menuactionList.value[index].child[subIndex].checkAll = false;
  106. }
  107. // this.$set(menuactionList.value, index, item);
  108. };
  109. // 单项复选框选中/不选中
  110. const handleFieldChange = (checked, id, index, subIndex, item) => {
  111. // console.log(checked, id, index, subIndex);
  112. if (checked) {
  113. // 选中时检查pid的选中状态
  114. menuactionList.value[index].child[subIndex].fieldList.indexOf(id) == -1 &&
  115. menuactionList.value[index].child[subIndex].fieldList.push(id);
  116. } else {
  117. const find = menuactionList.value[index].child[
  118. subIndex
  119. ].fieldList.findIndex(e => e == id);
  120. if (find > -1) {
  121. menuactionList.value[index].child[subIndex].fieldList.splice(find, 1);
  122. }
  123. menuactionList.value[index].child[subIndex].fieldAll = false;
  124. }
  125. // this.$set(menuactionList.value, index, item);
  126. // console.log(menuactionList.value[index].child[subIndex]);
  127. };
  128. //选择角色
  129. const switchRoleHandle = async item => {
  130. const { id } = item;
  131. ruleForm.roleid = id;
  132. await nextTick(async () => {
  133. await refreshRoleDetail(id);
  134. });
  135. };
  136. // 保存
  137. const submitForm = async () => {
  138. action_list.value = [];
  139. action_data_list.value = [];
  140. private_data_list.value = [];
  141. menuactionList.value.forEach(x => {
  142. x.child.forEach(y => {
  143. action_data_list.value.push(...y.fieldList);
  144. action_list.value.push(...y.checkList);
  145. if (y.is_private_change === "1") {
  146. private_data_list.value.push(y.id);
  147. }
  148. });
  149. });
  150. if (action_list.value.length === 0) {
  151. ElMessage.error("请选择功能!");
  152. return;
  153. }
  154. const model = {
  155. roleid: ruleForm.roleid,
  156. role_name: ruleForm.role_name,
  157. level: ruleForm.level,
  158. action: action_list.value,
  159. // action_data: this.action_data,
  160. private_data: private_data_list.value
  161. };
  162. loading.value = true;
  163. const { code, data, message } = await httpUpdate(model);
  164. loading.value = false;
  165. if (code === 0) {
  166. ElMessage.success(message);
  167. } else if (code >= 100 && code <= 104) {
  168. logout();
  169. } else {
  170. ElMessage.error(message);
  171. }
  172. };
  173. const getMenuAll = async () => {
  174. const { code, data, message } = await httpMenuAll({});
  175. if (code === 0) {
  176. let arr = JSON.parse(JSON.stringify(data ?? []));
  177. arr = arr.filter(item => item.child && item.child.length > 0);
  178. arr = arr.map(x => {
  179. x.child.map(y => {
  180. y.checkAll = false;
  181. y.checkList = [];
  182. y.fieldAll = false;
  183. y.fieldList = [];
  184. y.is_private_change = "0";
  185. if (y.is_private === "0") {
  186. y.private = [];
  187. } else {
  188. y.private = [
  189. {
  190. id: "0",
  191. label: "公有数据"
  192. },
  193. {
  194. id: "1",
  195. label: "私有数据"
  196. }
  197. ];
  198. }
  199. return y;
  200. });
  201. return x;
  202. });
  203. backupMenuactionList.value = arr;
  204. // menuactionList.value = arr;
  205. } else if (code > 100 && code < 140) {
  206. logout();
  207. } else {
  208. ElMessage.error(message);
  209. }
  210. };
  211. const getRoleAll = async () => {
  212. const { code, data, message } = await httpRoleAll({});
  213. if (code === 0) {
  214. roleList.value = data ?? [];
  215. } else if (code > 100 && code < 140) {
  216. logout();
  217. } else {
  218. ElMessage.error(message);
  219. }
  220. };
  221. // 刷新角色详情
  222. const refreshRoleDetail = async roleid => {
  223. loading.value = true;
  224. const { code, data, message } = await httpDetail({ roleid });
  225. if (code === 0) {
  226. const { action, action_data, private_data, id, role_name, level } =
  227. data ?? {};
  228. ruleForm.roleid = id;
  229. ruleForm.role_name = role_name ?? "";
  230. ruleForm.level = level ?? "1";
  231. action_list.value = action ?? [];
  232. action_data_list.value = action_data ?? [];
  233. private_data_list.value = private_data ?? [];
  234. await refreshRoleCheckAllStatus();
  235. loading.value = false;
  236. } else if (code >= 100 && code <= 104) {
  237. loading.value = false;
  238. logout();
  239. } else {
  240. loading.value = false;
  241. ElMessage.error(message);
  242. }
  243. };
  244. // 刷新选择状态
  245. const refreshRoleCheckAllStatus = async () => {
  246. menuactionList.value = JSON.parse(JSON.stringify(backupMenuactionList.value));
  247. console.log(private_data_list.value);
  248. menuactionList.value.forEach((x, xi) => {
  249. if (x.child && x.child.length > 0) {
  250. x.child.forEach((y, yi) => {
  251. // let id = y.id;
  252. if (y.action && y.action.length > 0) {
  253. y.action.forEach(z => {
  254. const Aindex = action_list.value.findIndex(a => a === z.id);
  255. if (Aindex !== -1) {
  256. y.checkList.push(action_list.value[Aindex]);
  257. }
  258. if (y.action.length === y.checkList.length) {
  259. y.checkAll = true;
  260. }
  261. });
  262. }
  263. if (y.action_data && y.action_data.length > 0) {
  264. y.action_data.map(z => {
  265. const Bindex = action_data_list.value.findIndex(a => a === z.id);
  266. if (Bindex !== -1) {
  267. y.fieldList.push(action_data_list.value[Bindex]);
  268. }
  269. });
  270. if (y.action_data.length === y.fieldList.length) {
  271. y.fieldAll = true;
  272. }
  273. }
  274. if (y.private && y.private.length === 2) {
  275. let Cindex =
  276. private_data_list.value.length > 0
  277. ? private_data_list.value.findIndex(a => a === y.id)
  278. : -1;
  279. if (Cindex !== -1) {
  280. y.is_private_change = "1";
  281. } else {
  282. y.is_private_change = "0";
  283. }
  284. } else {
  285. y.is_private_change = "0";
  286. }
  287. });
  288. }
  289. // this.$set(this.actionList, xi, x);
  290. });
  291. };
  292. async function onSearch() {
  293. loading.value = true;
  294. await getRoleAll();
  295. await getMenuAll();
  296. if (roleList.value.length > 0) {
  297. await refreshRoleDetail(roleList.value[0].id);
  298. }
  299. loading.value = false;
  300. }
  301. let indeterminateCheck = computed(() => {
  302. return item => {
  303. // 选中子节点的数量
  304. const selectItemLength = item.action.filter(
  305. filitem =>
  306. item.checkList.findIndex(finditem => finditem === filitem.id) > -1
  307. ).length;
  308. // 未选中子节点的数量
  309. const noSlectItemLength = item.action.filter(
  310. filitem =>
  311. item.checkList.findIndex(finditem => finditem === filitem.id) == -1
  312. ).length;
  313. // // 当前节点的index
  314. // 存在选中子节点且存在未选中子节点为中间态
  315. return selectItemLength > 0 && noSlectItemLength > 0;
  316. };
  317. });
  318. let indeterminateField = computed(() => {
  319. return item => {
  320. // console.log(item);
  321. // 选中子节点的数量
  322. const selectItemLength = item.action_data.filter(
  323. filitem =>
  324. item.fieldList.findIndex(finditem => finditem === filitem.id) > -1
  325. ).length;
  326. // 未选中子节点的数量
  327. const noSlectItemLength = item.action_data.filter(
  328. filitem =>
  329. item.fieldList.findIndex(finditem => finditem === filitem.id) == -1
  330. ).length;
  331. // // 当前节点的index
  332. // 存在选中子节点且存在未选中子节点为中间态
  333. return selectItemLength > 0 && noSlectItemLength > 0;
  334. };
  335. });
  336. onMounted(() => {
  337. onSearch();
  338. });
  339. </script>
  340. <template>
  341. <div class="action">
  342. <div class="action_show">
  343. <div class="action_show_box">
  344. <ul class="role-list">
  345. <p class="role-list__title">角色列表</p>
  346. <!-- -->
  347. <!-- -->
  348. <!-- v-if="isBtnDisabled && item.id == roleActive.id" -->
  349. <p
  350. v-if="roleList.length == 0"
  351. style="line-height: 60px; text-align: center; color: #858599"
  352. >
  353. 暂无数据
  354. </p>
  355. <li
  356. v-for="(item, index) in roleList"
  357. :key="'role' + index"
  358. class="role-list__item"
  359. :class="{ active: item.id == ruleForm.roleid }"
  360. @click="!loading && switchRoleHandle(item)"
  361. >
  362. {{ item.role_name }}
  363. <el-button
  364. v-if="loading && item.id == ruleForm.roleid"
  365. class="fr"
  366. link
  367. :size="'mini'"
  368. :icon="useRenderIcon('Loading')"
  369. />
  370. </li>
  371. </ul>
  372. <div class="rule-view">
  373. <div class="rule-list" style="padding: 0 0 100px 0">
  374. <el-row
  375. v-for="(item, index) in menuactionList"
  376. :key="'menu' + item.id + index"
  377. >
  378. <el-col
  379. v-if="item.child && item.child.length > 0"
  380. class="ffff"
  381. :span="24"
  382. >
  383. <div class="ftitle">
  384. <div
  385. v-for="(si, sii) in item.menu_name"
  386. :key="'title' + sii + si"
  387. >
  388. {{ si }}
  389. </div>
  390. </div>
  391. <div class="fbody">
  392. <div
  393. class="fbody-item"
  394. v-for="(subItem, subIndex) in item.child"
  395. :key="'yemian' + subItem.id + subIndex"
  396. >
  397. <template
  398. v-if="
  399. !(
  400. subItem.action &&
  401. subItem.action.length === 0 &&
  402. subItem.action_data &&
  403. subItem.action_data.length === 0
  404. )
  405. "
  406. ><div class="stitle">
  407. <span class="_h2">{{ subItem.menu_name }}</span>
  408. <el-radio-group
  409. style="margin: 0 0 0 20px"
  410. :size="'mini'"
  411. v-if="
  412. subItem &&
  413. subItem.private &&
  414. subItem.private.length === 2
  415. "
  416. v-model="subItem.is_private_change"
  417. >
  418. <el-radio-button
  419. v-for="(radioN, ri) in subItem.private"
  420. :key="radioN.label + ri"
  421. :label="radioN.id"
  422. >{{ radioN.label }}</el-radio-button
  423. >
  424. </el-radio-group>
  425. </div>
  426. <div
  427. class="scheck"
  428. v-if="subItem.action && subItem.action.length > 0"
  429. >
  430. <div class="checkAll">
  431. <el-checkbox
  432. v-model="subItem.checkAll"
  433. :disabled="editType === 'view'"
  434. :indeterminate="indeterminateCheck(subItem)"
  435. @change="
  436. handleCheckAllChange(
  437. $event,
  438. index,
  439. item,
  440. subIndex
  441. )
  442. "
  443. >功能全选</el-checkbox
  444. >
  445. </div>
  446. <div class="checkItem">
  447. <el-checkbox-group
  448. v-model="subItem.checkList"
  449. :disabled="editType === 'view'"
  450. @change="
  451. handleCheckedGroupChange(
  452. $event,
  453. index,
  454. item,
  455. subIndex
  456. )
  457. "
  458. >
  459. <el-checkbox
  460. :disabled="editType === 'view'"
  461. v-for="children in subItem.action"
  462. :key="'checkItem' + children.id"
  463. :label="children.id"
  464. @change="
  465. handleCheckedChange(
  466. $event,
  467. children.id,
  468. index,
  469. subIndex,
  470. item
  471. )
  472. "
  473. >{{ children.action_name }}</el-checkbox
  474. >
  475. </el-checkbox-group>
  476. </div>
  477. </div>
  478. <div
  479. class="sfield"
  480. v-if="
  481. subItem.action_data && subItem.action_data.length > 0
  482. "
  483. >
  484. <div class="checkAll">
  485. <el-checkbox
  486. v-model="subItem.fieldAll"
  487. :disabled="editType === 'view'"
  488. :indeterminate="indeterminateField(subItem)"
  489. @change="
  490. handleFieldAllChange(
  491. $event,
  492. index,
  493. item,
  494. subIndex
  495. )
  496. "
  497. >字段全选</el-checkbox
  498. >
  499. </div>
  500. <div class="checkItem">
  501. <el-checkbox-group
  502. v-model="subItem.fieldList"
  503. :disabled="editType === 'view'"
  504. @change="
  505. handleFieldGroupChange(
  506. $event,
  507. index,
  508. item,
  509. subIndex
  510. )
  511. "
  512. >
  513. <el-checkbox
  514. v-for="children in subItem.action_data"
  515. :key="'FieldItem' + children.id"
  516. :label="children.id"
  517. :disabled="editType === 'view'"
  518. @change="
  519. handleFieldChange(
  520. $event,
  521. children.id,
  522. index,
  523. subIndex,
  524. item
  525. )
  526. "
  527. >{{ children.field_name }}</el-checkbox
  528. >
  529. </el-checkbox-group>
  530. </div>
  531. </div>
  532. </template>
  533. </div>
  534. </div>
  535. </el-col>
  536. </el-row>
  537. </div>
  538. </div>
  539. </div>
  540. <div class="rule-bottom">
  541. <el-button size="small" type="primary" @click="submitForm"
  542. >提 交</el-button
  543. >
  544. </div>
  545. </div>
  546. </div>
  547. </template>
  548. <style scoped lang="scss">
  549. .action {
  550. height: calc(100vh - 85px);
  551. position: relative;
  552. background: #fff;
  553. width: 100%;
  554. text-align: center;
  555. overflow: hidden;
  556. .action_show {
  557. position: relative;
  558. width: 100%;
  559. height: calc(100vh - 85px);
  560. .rule-bottom {
  561. padding: 20px 30px 8px 0;
  562. // background: #fff;
  563. // width: 100px;
  564. text-align: right;
  565. position: fixed;
  566. right: 0px;
  567. bottom: 0px;
  568. &::before {
  569. content: "";
  570. top: 0;
  571. right: 0;
  572. height: 2px;
  573. width: 100%;
  574. background-color: #e4e7ed;
  575. z-index: 1;
  576. }
  577. }
  578. .action_show_box {
  579. position: relative;
  580. height: 100%;
  581. // calc(100% - 50px);
  582. min-height: 100%;
  583. //calc(100% - 50px);
  584. display: flex;
  585. text-align: left;
  586. .role-list {
  587. position: relative;
  588. height: 100%;
  589. overflow-y: auto;
  590. width: 250px;
  591. padding: 8px 16px;
  592. min-height: 100%;
  593. flex-shrink: 0;
  594. &::after {
  595. content: "";
  596. position: absolute;
  597. top: 0;
  598. right: 0;
  599. height: 100%;
  600. width: 2px;
  601. background-color: #e4e7ed;
  602. z-index: 1;
  603. }
  604. .role-list__title {
  605. color: #b4b6c0;
  606. line-height: 32px;
  607. }
  608. .role-list__item {
  609. position: relative;
  610. white-space: nowrap;
  611. text-overflow: ellipsis;
  612. overflow: hidden;
  613. height: 32px;
  614. line-height: 32px;
  615. padding-left: 8px;
  616. color: rgb(48, 49, 51);
  617. cursor: pointer;
  618. i {
  619. position: absolute;
  620. right: 0;
  621. line-height: 32px;
  622. }
  623. }
  624. .role-list__item.active {
  625. color: #63cbe7;
  626. background: #f7f7f7;
  627. }
  628. }
  629. .rule-view {
  630. position: relative;
  631. height: 100%;
  632. width: calc(100% - 250px);
  633. overflow-y: scroll;
  634. // padding: 0 0 0 16px;
  635. .ffff {
  636. width: 100%;
  637. display: flex;
  638. align-items: stretch;
  639. .ftitle {
  640. width: 50px;
  641. text-align: center;
  642. border-right: 1px solid #dfe6ec;
  643. border-bottom: 1px solid #dfe6ec;
  644. padding: 12px 14px;
  645. display: flex;
  646. align-items: center;
  647. flex-direction: column;
  648. justify-content: center;
  649. div {
  650. font-size: 17px;
  651. height: 22px;
  652. line-height: 22px;
  653. text-align: center;
  654. color: #97a8be;
  655. }
  656. }
  657. .fbody {
  658. width: calc(100% - 50px);
  659. .fbody-item {
  660. border-right: 1px solid #dfe6ec;
  661. border-bottom: 1px solid #dfe6ec;
  662. .stitle {
  663. padding: 18px 18px 12px 18px;
  664. border-bottom: 1px dashed #dfe6ec;
  665. font-size: 14px;
  666. color: #97a8be;
  667. ._h2 {
  668. display: inline-block;
  669. width: 100px;
  670. }
  671. }
  672. .scheck {
  673. padding: 15px 0 10px 0;
  674. display: flex;
  675. width: 100%;
  676. .checkAll {
  677. width: 140px;
  678. text-align: right;
  679. padding: 0 35px 0 0;
  680. }
  681. .checkItem {
  682. width: calc(100% - 140px);
  683. }
  684. }
  685. .sfield {
  686. padding: 0 0 10px 0;
  687. display: flex;
  688. width: 100%;
  689. .checkAll {
  690. width: 140px;
  691. text-align: right;
  692. padding: 0 35px 0 0;
  693. }
  694. .checkItem {
  695. width: calc(100% - 140px);
  696. }
  697. }
  698. }
  699. }
  700. }
  701. }
  702. }
  703. }
  704. }
  705. </style>