index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. <template>
  2. <div>
  3. <Card :bordered="false" dis-hover class="ivu-mt">
  4. <Form
  5. ref="roleData"
  6. :model="roleData"
  7. :label-width="labelWidth"
  8. :label-position="labelPosition"
  9. @submit.native.prevent
  10. >
  11. <Row type="flex" :gutter="24">
  12. <Col v-bind="grid">
  13. <FormItem label="规则状态:">
  14. <Select v-model="roleData.is_show" placeholder="请选择" clearable @on-change="getData">
  15. <Option value="1">显示</Option>
  16. <Option value="0">不显示</Option>
  17. </Select>
  18. </FormItem>
  19. </Col>
  20. <Col v-bind="grid">
  21. <FormItem label="按钮名称:" prop="status2" label-for="status2">
  22. <Input v-model="roleData.keyword" search enter-button placeholder="请输入按钮名称" @on-search="getData" />
  23. </FormItem>
  24. </Col>
  25. </Row>
  26. <Row type="flex">
  27. <Col v-bind="grid">
  28. <Button v-auth="['setting-system_menus-add']" type="primary" @click="menusAdd('添加规则')" icon="md-add"
  29. >添加规则</Button
  30. >
  31. </Col>
  32. </Row>
  33. </Form>
  34. <vxe-table
  35. :border="false"
  36. class="vxeTable mt25"
  37. highlight-hover-row
  38. highlight-current-row
  39. :loading="loading"
  40. ref="xTable"
  41. header-row-class-name="false"
  42. :tree-config="tabconfig"
  43. :data="tableData"
  44. row-id="id"
  45. >
  46. <vxe-table-column field="id" title="ID" tooltip min-width="70"></vxe-table-column>
  47. <vxe-table-column field="menu_name" tree-node title="按钮名称" min-width="200"></vxe-table-column>
  48. <vxe-table-column field="api_url" title="接口路径" min-width="150">
  49. <template v-slot="{ row }">
  50. <span>{{ row.methods ? '[' + row.methods + '] ' + row.api_url : row.api_url }}</span>
  51. </template>
  52. </vxe-table-column>
  53. <vxe-table-column field="unique_auth" title="前端权限" min-width="300"></vxe-table-column>
  54. <vxe-table-column field="menu_path" title="页面路由" min-width="240" tooltip="true"></vxe-table-column>
  55. <vxe-table-column field="flag" title="规则状态" min-width="120">
  56. <template v-slot="{ row }">
  57. <i-switch
  58. v-model="row.is_show"
  59. :value="row.is_show"
  60. :true-value="1"
  61. :false-value="0"
  62. @on-change="onchangeIsShow(row)"
  63. size="large"
  64. >
  65. <span slot="open">显示</span>
  66. <span slot="close">隐藏</span>
  67. </i-switch>
  68. </template>
  69. </vxe-table-column>
  70. <vxe-table-column field="date" title="操作" align="center" width="250" fixed="right">
  71. <template v-slot="{ row, index }">
  72. <span v-auth="['setting-system_menus-add']">
  73. <a @click="addRoute(row)" v-if="row.auth_type === 1">添加权限</a>
  74. <Divider type="vertical" v-if="row.auth_type === 1" />
  75. <a @click="addE(row, '添加子菜单')" v-if="row.auth_type === 1">添加子菜单</a>
  76. <!-- <a @click="addE(row, '添加规则')" v-else>添加规则</a> -->
  77. </span>
  78. <Divider type="vertical" v-if="row.auth_type === 1" />
  79. <a @click="edit(row, '编辑')">编辑</a>
  80. <Divider type="vertical" />
  81. <a @click="del(row, '删除规则')">删除</a>
  82. </template>
  83. </vxe-table-column>
  84. </vxe-table>
  85. </Card>
  86. <menus-from
  87. :formValidate="formValidate"
  88. :titleFrom="titleFrom"
  89. @getList="getList"
  90. ref="menusFrom"
  91. @clearFrom="clearFrom"
  92. ></menus-from>
  93. <Modal
  94. v-model="ruleModal"
  95. scrollable
  96. width="1100"
  97. title="权限列表"
  98. @on-ok="addRouters"
  99. @on-cancel="ruleModal = false"
  100. @on-visible-change="modalchange"
  101. >
  102. <div class="search-rule">
  103. <Input
  104. class="mr10"
  105. v-model="searchRule"
  106. placeholder="输入关键词搜索"
  107. clearable
  108. style="width: 300px"
  109. ref="search"
  110. @on-enter="searchRules"
  111. @on-clear="searchRules"
  112. />
  113. <Button class="mr10" type="primary" @click="searchRules">搜索</Button>
  114. <Button @click="init">重置</Button>
  115. </div>
  116. <Tabs v-model="routeType" @on-click="changTab">
  117. <TabPane label="公共接口" name="1"></TabPane>
  118. <TabPane label="基础接口" name="0"></TabPane>
  119. </Tabs>
  120. <div class="rule">
  121. <div
  122. class="rule-list"
  123. v-show="!arrs.length || arrs.includes(item.id)"
  124. :class="{ 'select-rule': seletRouteIds.includes(item.id) }"
  125. v-for="(item, index) in routeType == 1 ? foundationList : openList"
  126. :key="index"
  127. @click="selectRule(item)"
  128. >
  129. <div>接口名称:{{ item.real_name }}</div>
  130. <div>请求方式:{{ item.method }}</div>
  131. <div>接口地址:{{ item.path }}</div>
  132. </div>
  133. </div>
  134. </Modal>
  135. </div>
  136. </template>
  137. <script>
  138. import { mapState } from 'vuex';
  139. import { getTable, menusDetailsApi, isShowApi, editMenus, getRuleList, menusBatch } from '@/api/systemMenus';
  140. import formCreate from '@form-create/iview';
  141. import menusFrom from './components/menusFrom';
  142. export default {
  143. name: 'systemMenus',
  144. data() {
  145. return {
  146. tabconfig: { children: 'children', reserve: true, accordion: true },
  147. spinShow: false,
  148. ruleModal: false,
  149. searchRule: '',
  150. grid: {
  151. xl: 7,
  152. lg: 7,
  153. md: 12,
  154. sm: 24,
  155. xs: 24,
  156. },
  157. roleData: {
  158. is_show: '',
  159. keyword: '',
  160. },
  161. loading: false,
  162. tableData: [],
  163. FromData: null,
  164. icons: '',
  165. formValidate: {},
  166. titleFrom: '',
  167. modalTitleSs: '',
  168. routeType: '1',
  169. arrs: [],
  170. foundationList: [], // 基础接口列表
  171. openList: [], // 公开接口列表
  172. seletRoute: [], // 选中路由
  173. seletRouteIds: [], // 选中id
  174. menusId: 0, // 选中分类id
  175. };
  176. },
  177. components: { menusFrom, formCreate: formCreate.$form() },
  178. computed: {
  179. ...mapState('admin/layout', ['isMobile']),
  180. labelWidth() {
  181. return this.isMobile ? undefined : 75;
  182. },
  183. labelPosition() {
  184. return this.isMobile ? 'top' : 'right';
  185. },
  186. },
  187. mounted() {
  188. this.getData();
  189. },
  190. methods: {
  191. init() {
  192. this.searchRule = '';
  193. this.arrs = [];
  194. this.seletRouteIds = [];
  195. this.seletRoute = [];
  196. },
  197. addRouters() {
  198. let data = {
  199. menus: this.seletRoute,
  200. };
  201. menusBatch(data)
  202. .then((res) => {
  203. console.log(res);
  204. this.getData();
  205. })
  206. .catch((res) => {
  207. this.$Message.error(res.msg);
  208. });
  209. },
  210. selectRule(data) {
  211. if (this.seletRouteIds.includes(data.id)) {
  212. let i = this.seletRouteIds.findIndex((e) => e == data.id);
  213. this.seletRouteIds.splice(i, 1);
  214. this.seletRoute.splice(i, 1);
  215. } else {
  216. this.seletRouteIds.push(data.id);
  217. this.seletRoute.push({
  218. menu_name: data.name,
  219. unique_auth: '',
  220. api_url: data.path,
  221. path: this.menusId,
  222. method: data.method,
  223. });
  224. }
  225. },
  226. changTab(name) {
  227. console.log(name);
  228. this.searchRules();
  229. },
  230. // 搜索规则
  231. searchRules() {
  232. if (this.searchRule.trim()) {
  233. this.arrs = [];
  234. let arr = this.routeType == 1 ? this.foundationList : this.openList;
  235. for (var i = 0; i < arr.length; i++) {
  236. if (arr[i].real_name.indexOf(this.searchRule) !== -1) {
  237. this.arrs.push(arr[i].id);
  238. }
  239. }
  240. } else {
  241. this.arrs = [];
  242. }
  243. },
  244. addRoute(row) {
  245. this.menusId = row.id;
  246. this.getRuleList();
  247. },
  248. modalchange() {},
  249. // 获取权限列表
  250. getRuleList() {
  251. getRuleList().then((res) => {
  252. this.foundationList = [];
  253. this.openList = [];
  254. this.seletRouteIds = [];
  255. this.seletRoute = [];
  256. res.data.map((e) => {
  257. if (e.type) {
  258. this.foundationList.push(e);
  259. } else {
  260. this.openList.push(e);
  261. }
  262. });
  263. this.ruleModal = true;
  264. });
  265. },
  266. // 修改规则状态
  267. onchangeIsShow(row) {
  268. let data = {
  269. id: row.id,
  270. is_show: row.is_show,
  271. };
  272. isShowApi(data)
  273. .then(async (res) => {
  274. this.$Message.success(res.msg);
  275. this.$store.dispatch('menus/getMenusNavList');
  276. })
  277. .catch((res) => {
  278. this.$Message.error(res.msg);
  279. });
  280. },
  281. // 请求列表
  282. getList() {
  283. this.formValidate = Object.assign({}, this.$options.data().formValidate);
  284. this.getData();
  285. },
  286. // 清除表单数据
  287. clearFrom() {
  288. this.formValidate = Object.assign({}, this.$options.data().formValidate);
  289. },
  290. // 添加子菜单
  291. addE(row, title) {
  292. this.formValidate = {};
  293. let pid = row.id.toString();
  294. if (pid) {
  295. menusDetailsApi(row.id)
  296. .then(async (res) => {
  297. this.formValidate.path = res.data.path;
  298. this.formValidate.path.push(row.id);
  299. this.formValidate.pid = pid;
  300. this.$refs.menusFrom.modals = true;
  301. this.$refs.menusFrom.valids = false;
  302. this.titleFrom = title;
  303. this.formValidate.auth_type = 1;
  304. this.formValidate.is_show = 0;
  305. this.formValidate.is_show_path = 0;
  306. })
  307. .catch((res) => {
  308. this.$Message.error(res.msg);
  309. });
  310. } else {
  311. this.formValidate.pid = pid;
  312. this.$refs.menusFrom.modals = true;
  313. this.$refs.menusFrom.valids = false;
  314. this.titleFrom = title;
  315. this.formValidate.auth_type = 1;
  316. this.formValidate.is_show = 0;
  317. this.formValidate.is_show_path = 0;
  318. }
  319. // this.formValidate.pid = row.id.toString();
  320. // this.$refs.menusFrom.modals = true;
  321. // this.$refs.menusFrom.valids = false;
  322. // this.titleFrom = title;
  323. // this.formValidate.auth_type = 1;
  324. // this.formValidate.is_show = '0';
  325. },
  326. // 删除
  327. del(row, tit) {
  328. let delfromData = {
  329. title: tit,
  330. url: `/setting/menus/${row.id}`,
  331. method: 'DELETE',
  332. ids: '',
  333. };
  334. this.$modalSure(delfromData)
  335. .then((res) => {
  336. this.$Message.success(res.msg);
  337. this.getData();
  338. this.$store.dispatch('menus/getMenusNavList');
  339. })
  340. .catch((res) => {
  341. this.$Message.error(res.msg);
  342. });
  343. },
  344. // 规则详情
  345. menusDetails(id) {
  346. menusDetailsApi(id)
  347. .then(async (res) => {
  348. this.formValidate = res.data;
  349. this.$refs.menusFrom.modals = true;
  350. })
  351. .catch((res) => {
  352. this.$Message.error(res.msg);
  353. });
  354. },
  355. // 编辑
  356. edit(row, title, index) {
  357. this.formValidate = {};
  358. this.menusDetails(row.id);
  359. this.titleFrom = title;
  360. this.$refs.menusFrom.valids = false;
  361. this.$refs.menusFrom.getAddFrom(row.id);
  362. },
  363. // 添加
  364. menusAdd(title) {
  365. this.formValidate = {};
  366. this.$refs.menusFrom.modals = true;
  367. this.$refs.menusFrom.valids = false;
  368. // this.formValidate = Object.assign(this.$data, this.$options.formValidate());
  369. this.titleFrom = title;
  370. this.formValidate.auth_type = 1;
  371. this.formValidate.is_show = 0;
  372. this.formValidate.is_show_path = 0;
  373. },
  374. // 新增页面表单
  375. // getAddFrom () {
  376. // this.spinShow = true;
  377. // addMenus(this.roleData).then(async res => {
  378. // this.FromData = res.data;
  379. // this.$refs.menusFrom.modals = true;
  380. // this.spinShow = false;
  381. // }).catch(res => {
  382. // this.spinShow = false;
  383. // this.$Message.error(res.msg);
  384. // })
  385. // },
  386. // 列表
  387. getData() {
  388. this.loading = true;
  389. this.roleData.is_show = this.roleData.is_show || '';
  390. getTable(this.roleData)
  391. .then(async (res) => {
  392. this.tableData = res.data;
  393. this.loading = false;
  394. })
  395. .catch((res) => {
  396. this.loading = false;
  397. this.$Message.error(res.msg);
  398. });
  399. },
  400. // 关闭按钮
  401. cancel() {
  402. this.$emit('onCancel');
  403. },
  404. },
  405. };
  406. </script>
  407. <style scoped lang="stylus">
  408. .vxeTable {
  409. >>> .vxe-table--header-wrapper {
  410. background: #fff !important;
  411. }
  412. }
  413. .rule {
  414. display: flex;
  415. flex-wrap: wrap;
  416. max-height: 600px;
  417. overflow-y: scroll;
  418. }
  419. /*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
  420. .rule::-webkit-scrollbar {
  421. width: 10px;
  422. height: 10px;
  423. background-color: #f5f5f5;
  424. }
  425. /*定义滚动条轨道 内阴影+圆角*/
  426. .rule::-webkit-scrollbar-track {
  427. border-radius: 4px;
  428. background-color: #f5f5f5;
  429. }
  430. /*定义滑块 内阴影+圆角*/
  431. .rule::-webkit-scrollbar-thumb {
  432. border-radius: 4px;
  433. background-color: #ccc;
  434. }
  435. .rule-list {
  436. background-color: #f2f2f2;
  437. width: 32%;
  438. margin: 5px;
  439. border-radius: 3px;
  440. padding: 10px;
  441. color: #333;
  442. cursor: pointer;
  443. transition: all 0.1s;
  444. }
  445. .rule-list:hover {
  446. background-color: #c5d1dd;
  447. }
  448. .rule-list div {
  449. white-space: nowrap;
  450. }
  451. .select-rule {
  452. background-color: #c5d1dd;
  453. }
  454. </style>