index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. <template>
  2. <div class="page-container list-sontainer">
  3. <div :gutter="10" class="list-btns-container">
  4. <el-button type="primary" size="small" icon="Plus" @click="handleAdd"
  5. v-hasPermi="['system:role:add']">新增</el-button>
  6. <el-button type="success" size="small" icon="Edit" :disabled="single" @click="handleUpdate"
  7. v-hasPermi="['system:role:edit']">修改</el-button>
  8. <el-button type="danger" size="small" icon="Delete" :disabled="multiple" @click="handleDelete"
  9. v-hasPermi="['system:role:remove']">删除</el-button>
  10. <!-- <el-button type="warning" size="small" icon="Download" @click="handleExport"
  11. v-hasPermi="['system:role:export']">导出</el-button> -->
  12. <!-- <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> -->
  13. </div>
  14. <el-form class="list-search-container" :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true"
  15. label-width="68px">
  16. <el-form-item label="角色名称:" prop="roleName" style="width: 220px">
  17. <el-input size="small" v-model="queryParams.roleName" placeholder="请输入角色名称" clearable
  18. @keyup.enter="handleQuery" />
  19. </el-form-item>
  20. <!-- <el-form-item label="权限字符:" prop="roleKey" style="width: 220px">
  21. <el-input size="small" v-model="queryParams.roleKey" placeholder="请输入权限字符" clearable @keyup.enter="handleQuery" />
  22. </el-form-item> -->
  23. <!-- <el-form-item label="状态:" prop="status" style="width: 220px">
  24. <el-select size="small" v-model="queryParams.status" placeholder="角色状态" clearable>
  25. <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
  26. </el-select>
  27. </el-form-item> -->
  28. <!-- <el-form-item label="创建时间:" style="width: 260px">
  29. <el-date-picker size="small" v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-"
  30. start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
  31. </el-form-item> -->
  32. <el-form-item>
  33. <el-button size="small" type="primary" icon="Search" @click="handleQuery">搜索</el-button>
  34. <el-button size="small" icon="Refresh" @click="resetQuery">重置</el-button>
  35. </el-form-item>
  36. </el-form>
  37. <!-- 表格数据 -->
  38. <el-table size="small" v-loading="loading" border :data="roleList" @selection-change="handleSelectionChange">
  39. <el-table-column type="selection" width="55" align="center" />
  40. <!--<el-table-column label="角色编号" prop="roleId" width="120" />-->
  41. <el-table-column label="角色名称" align="center" prop="roleName" :show-overflow-tooltip="true" width="150" />
  42. <el-table-column label="权限字符" align="center" prop="roleKey" :show-overflow-tooltip="true" width="150" />
  43. <el-table-column label="排序" align="center" prop="roleSort" width="100" />
  44. <!-- <el-table-column label="状态" align="center" width="100">
  45. <template #default="scope">
  46. <el-switch v-model="scope.row.status" active-value="0" inactive-value="1"
  47. @change="handleStatusChange(scope.row)"></el-switch>
  48. </template>
  49. </el-table-column> -->
  50. <el-table-column label="创建时间" align="center" prop="createTime" width="200">
  51. <template #default="scope">
  52. <span>{{ parseTime(scope.row.createTime) }}</span>
  53. </template>
  54. </el-table-column>
  55. <el-table-column label="备注" align="center" prop="remark" />
  56. <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
  57. <template #default="scope">
  58. <el-button link size="small" type="warning" @click="handleUpdate(scope.row)" v-hasPermi="['system:role:edit']">
  59. 修改</el-button>
  60. <!-- <el-tooltip content="删除" placement="top" v-if="scope.row.roleId !== 1">
  61. <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)"
  62. v-hasPermi="['system:role:remove']"></el-button>
  63. </el-tooltip> -->
  64. <!-- <el-tooltip content="数据权限" placement="top" v-if="scope.row.roleId !== 1">
  65. <el-button link type="success" icon="CircleCheck" @click="handleDataScope(scope.row)"
  66. v-hasPermi="['system:role:edit']"></el-button>
  67. </el-tooltip> -->
  68. <!-- <el-tooltip content="分配用户" placement="top" v-if="scope.row.roleId !== 1">
  69. <el-button link type="primary" icon="User" @click="handleAuthUser(scope.row)"
  70. v-hasPermi="['system:role:edit']"></el-button>
  71. </el-tooltip> -->
  72. </template>
  73. </el-table-column>
  74. </el-table>
  75. <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
  76. @pagination="getList" />
  77. <!-- 添加或修改角色配置对话框 -->
  78. <el-dialog :title="title" v-model="open" width="500px" append-to-body draggable>
  79. <el-form ref="roleRef" :model="form" :rules="rules" label-width="100px">
  80. <el-form-item label="角色名称" prop="roleName">
  81. <el-input v-model="form.roleName" placeholder="请输入角色名称" />
  82. </el-form-item>
  83. <el-form-item prop="roleKey">
  84. <template #label>
  85. <span>
  86. <el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top">
  87. <el-icon><question-filled /></el-icon>
  88. </el-tooltip>
  89. 权限字符
  90. </span>
  91. </template>
  92. <el-input v-model="form.roleKey" placeholder="请输入权限字符" />
  93. </el-form-item>
  94. <el-form-item label="角色顺序" prop="roleSort">
  95. <el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
  96. </el-form-item>
  97. <!-- <el-form-item label="状态">
  98. <el-radio-group v-model="form.status">
  99. <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
  100. </el-radio-group>
  101. </el-form-item> -->
  102. <el-form-item label="菜单权限">
  103. <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
  104. <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
  105. <el-checkbox v-model="form.menuCheckStrictly"
  106. @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
  107. <el-tree class="tree-border" :data="menuOptions" show-checkbox ref="menuRef" node-key="id"
  108. :check-strictly="!form.menuCheckStrictly" empty-text="加载中,请稍候"
  109. :props="{ label: 'label', children: 'children' }"></el-tree>
  110. </el-form-item>
  111. <el-form-item label="备注">
  112. <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
  113. </el-form-item>
  114. </el-form>
  115. <template #footer>
  116. <div class="dialog-footer">
  117. <el-button type="primary" @click="submitForm">确 定</el-button>
  118. <el-button @click="cancel">取 消</el-button>
  119. </div>
  120. </template>
  121. </el-dialog>
  122. <!-- 分配角色数据权限对话框 -->
  123. <el-dialog :title="title" v-model="openDataScope" width="500px" append-to-body draggable>
  124. <el-form :model="form" label-width="80px">
  125. <el-form-item label="角色名称">
  126. <el-input v-model="form.roleName" :disabled="true" />
  127. </el-form-item>
  128. <el-form-item label="权限字符">
  129. <el-input v-model="form.roleKey" :disabled="true" />
  130. </el-form-item>
  131. <el-form-item label="权限范围">
  132. <el-select v-model="form.dataScope" @change="dataScopeSelectChange">
  133. <el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label"
  134. :value="item.value"></el-option>
  135. </el-select>
  136. </el-form-item>
  137. <el-form-item label="数据权限" v-show="form.dataScope == 2">
  138. <el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
  139. <el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
  140. <el-checkbox v-model="form.deptCheckStrictly"
  141. @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
  142. <el-tree class="tree-border" :data="deptOptions" show-checkbox default-expand-all ref="deptRef" node-key="id"
  143. :check-strictly="!form.deptCheckStrictly" empty-text="加载中,请稍候"
  144. :props="{ label: 'label', children: 'children' }"></el-tree>
  145. </el-form-item>
  146. </el-form>
  147. <template #footer>
  148. <div class="dialog-footer">
  149. <el-button type="primary" @click="submitDataScope">确 定</el-button>
  150. <el-button @click="cancelDataScope">取 消</el-button>
  151. </div>
  152. </template>
  153. </el-dialog>
  154. </div>
  155. </template>
  156. <script setup name="Role">
  157. import {
  158. addRole,
  159. changeRoleStatus,
  160. dataScope,
  161. delRole,
  162. getRole,
  163. listRole,
  164. updateRole,
  165. deptTreeSelect,
  166. } from "@/api/system/role";
  167. import {
  168. roleMenuTreeselect,
  169. treeselect as menuTreeselect,
  170. } from "@/api/system/menu";
  171. const router = useRouter();
  172. const { proxy } = getCurrentInstance();
  173. const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
  174. const roleList = ref([]);
  175. const open = ref(false);
  176. const loading = ref(true);
  177. const showSearch = ref(true);
  178. const ids = ref([]);
  179. const single = ref(true);
  180. const multiple = ref(true);
  181. const total = ref(0);
  182. const title = ref("");
  183. const dateRange = ref([]);
  184. const menuOptions = ref([]);
  185. const menuExpand = ref(false);
  186. const menuNodeAll = ref(false);
  187. const deptExpand = ref(true);
  188. const deptNodeAll = ref(false);
  189. const deptOptions = ref([]);
  190. const openDataScope = ref(false);
  191. const menuRef = ref(null);
  192. const deptRef = ref(null);
  193. /** 数据范围选项
  194. const dataScopeOptions = ref([
  195. { value: '1', label: '全部数据权限' },
  196. { value: '2', label: '自定数据权限' },
  197. { value: '3', label: '本部门数据权限' },
  198. { value: '4', label: '本部门及以下数据权限' },
  199. { value: '5', label: '仅本人数据权限' }
  200. ])
  201. */
  202. const dataScopeOptions = ref([
  203. { value: "1", label: "全部数据权限" },
  204. { value: "4", label: "租户内数据权限" },
  205. { value: "5", label: "仅本人数据权限" },
  206. ]);
  207. const data = reactive({
  208. form: {},
  209. queryParams: {
  210. pageNum: 1,
  211. pageSize: 20,
  212. roleName: undefined,
  213. roleKey: undefined,
  214. status: undefined,
  215. },
  216. rules: {
  217. roleName: [
  218. { required: true, message: "角色名称不能为空", trigger: "blur" },
  219. ],
  220. roleKey: [{ required: true, message: "权限字符不能为空", trigger: "blur" }],
  221. roleSort: [
  222. { required: true, message: "角色顺序不能为空", trigger: "blur" },
  223. ],
  224. },
  225. });
  226. const { queryParams, form, rules } = toRefs(data);
  227. /** 查询角色列表 */
  228. function getList() {
  229. loading.value = true;
  230. listRole(proxy.addDateRange(queryParams.value, dateRange.value)).then(
  231. (response) => {
  232. roleList.value = response.rows;
  233. total.value = response.total;
  234. loading.value = false;
  235. }
  236. );
  237. }
  238. /** 搜索按钮操作 */
  239. function handleQuery() {
  240. queryParams.value.pageNum = 1;
  241. getList();
  242. }
  243. /** 重置按钮操作 */
  244. function resetQuery() {
  245. dateRange.value = [];
  246. proxy.resetForm("queryRef");
  247. handleQuery();
  248. }
  249. /** 删除按钮操作 */
  250. function handleDelete(row) {
  251. const roleIds = row.roleId || ids.value;
  252. proxy.$modal
  253. .confirm("是否确认删除?")
  254. .then(function () {
  255. return delRole(roleIds);
  256. })
  257. .then(() => {
  258. getList();
  259. proxy.$modal.msgSuccess("删除成功");
  260. })
  261. .catch(() => { });
  262. }
  263. /** 导出按钮操作 */
  264. function handleExport() {
  265. queryParams.value.ids = ids.value;
  266. proxy.download(
  267. "system/role/export",
  268. {
  269. ...queryParams.value,
  270. },
  271. `role_${new Date().getTime()}.xlsx`
  272. );
  273. }
  274. /** 多选框选中数据 */
  275. function handleSelectionChange(selection) {
  276. ids.value = selection.map((item) => item.roleId);
  277. single.value = selection.length != 1;
  278. multiple.value = !selection.length;
  279. }
  280. /** 角色状态修改 */
  281. function handleStatusChange(row) {
  282. let text = row.status === "0" ? "启用" : "停用";
  283. proxy.$modal
  284. .confirm('确认要"' + text + '""' + row.roleName + '"角色吗?')
  285. .then(function () {
  286. return changeRoleStatus(row.roleId, row.status);
  287. })
  288. .then(() => {
  289. proxy.$modal.msgSuccess(text + "成功");
  290. })
  291. .catch(function () {
  292. row.status = row.status === "0" ? "1" : "0";
  293. });
  294. }
  295. /** 更多操作 */
  296. function handleCommand(command, row) {
  297. switch (command) {
  298. case "handleDataScope":
  299. handleDataScope(row);
  300. break;
  301. case "handleAuthUser":
  302. handleAuthUser(row);
  303. break;
  304. default:
  305. break;
  306. }
  307. }
  308. /** 分配用户 */
  309. function handleAuthUser(row) {
  310. router.push("/system/role-auth/user/" + row.roleId);
  311. }
  312. /** 查询菜单树结构 */
  313. function getMenuTreeselect() {
  314. menuTreeselect().then((response) => {
  315. menuOptions.value = response.data;
  316. });
  317. }
  318. /** 所有部门节点数据 */
  319. function getDeptAllCheckedKeys() {
  320. // 目前被选中的部门节点
  321. let checkedKeys = deptRef.value.getCheckedKeys();
  322. // 半选中的部门节点
  323. let halfCheckedKeys = deptRef.value.getHalfCheckedKeys();
  324. checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
  325. return checkedKeys;
  326. }
  327. /** 重置新增的表单以及其他数据 */
  328. function reset() {
  329. if (menuRef.value != undefined) {
  330. menuRef.value.setCheckedKeys([]);
  331. }
  332. menuExpand.value = false;
  333. menuNodeAll.value = false;
  334. deptExpand.value = true;
  335. deptNodeAll.value = false;
  336. form.value = {
  337. roleId: undefined,
  338. roleName: undefined,
  339. roleKey: undefined,
  340. roleSort: 0,
  341. status: "0",
  342. menuIds: [],
  343. deptIds: [],
  344. menuCheckStrictly: true,
  345. deptCheckStrictly: true,
  346. remark: undefined,
  347. };
  348. proxy.resetForm("roleRef");
  349. }
  350. /** 添加角色 */
  351. function handleAdd() {
  352. reset();
  353. getMenuTreeselect();
  354. open.value = true;
  355. title.value = "添加角色";
  356. }
  357. /** 修改角色 */
  358. function handleUpdate(row) {
  359. reset();
  360. const roleId = row.roleId || ids.value;
  361. const roleMenu = getRoleMenuTreeselect(roleId);
  362. getRole(roleId).then((response) => {
  363. form.value = response.data;
  364. form.value.roleSort = Number(form.value.roleSort);
  365. open.value = true;
  366. nextTick(() => {
  367. roleMenu.then((res) => {
  368. let checkedKeys = res.checkedKeys;
  369. checkedKeys.forEach((v) => {
  370. nextTick(() => {
  371. menuRef.value.setChecked(v, true, false);
  372. });
  373. });
  374. });
  375. });
  376. title.value = "修改角色";
  377. });
  378. }
  379. /** 根据角色ID查询菜单树结构 */
  380. function getRoleMenuTreeselect(roleId) {
  381. return roleMenuTreeselect(roleId).then((response) => {
  382. menuOptions.value = response.menus;
  383. return response;
  384. });
  385. }
  386. /** 根据角色ID查询部门树结构 */
  387. function getDeptTree(roleId) {
  388. return deptTreeSelect(roleId).then((response) => {
  389. deptOptions.value = response.depts;
  390. return response;
  391. });
  392. }
  393. /** 树权限(展开/折叠)*/
  394. function handleCheckedTreeExpand(value, type) {
  395. if (type == "menu") {
  396. let treeList = menuOptions.value;
  397. for (let i = 0; i < treeList.length; i++) {
  398. menuRef.value.store.nodesMap[treeList[i].id].expanded = value;
  399. }
  400. } else if (type == "dept") {
  401. let treeList = deptOptions.value;
  402. for (let i = 0; i < treeList.length; i++) {
  403. deptRef.value.store.nodesMap[treeList[i].id].expanded = value;
  404. }
  405. }
  406. }
  407. /** 树权限(全选/全不选) */
  408. function handleCheckedTreeNodeAll(value, type) {
  409. if (type == "menu") {
  410. menuRef.value.setCheckedNodes(value ? menuOptions.value : []);
  411. } else if (type == "dept") {
  412. deptRef.value.setCheckedNodes(value ? deptOptions.value : []);
  413. }
  414. }
  415. /** 树权限(父子联动) */
  416. function handleCheckedTreeConnect(value, type) {
  417. if (type == "menu") {
  418. form.value.menuCheckStrictly = value ? true : false;
  419. } else if (type == "dept") {
  420. form.value.deptCheckStrictly = value ? true : false;
  421. }
  422. }
  423. /** 所有菜单节点数据 */
  424. function getMenuAllCheckedKeys() {
  425. // 目前被选中的菜单节点
  426. let checkedKeys = menuRef.value.getCheckedKeys();
  427. // 半选中的菜单节点
  428. let halfCheckedKeys = menuRef.value.getHalfCheckedKeys();
  429. checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
  430. return checkedKeys;
  431. }
  432. /** 提交按钮 */
  433. function submitForm() {
  434. proxy.$refs["roleRef"].validate((valid) => {
  435. if (valid) {
  436. if (form.value.roleId != undefined) {
  437. form.value.menuIds = getMenuAllCheckedKeys();
  438. updateRole(form.value).then((response) => {
  439. proxy.$modal.msgSuccess("修改成功");
  440. open.value = false;
  441. getList();
  442. });
  443. } else {
  444. form.value.menuIds = getMenuAllCheckedKeys();
  445. addRole(form.value).then((response) => {
  446. proxy.$modal.msgSuccess("新增成功");
  447. open.value = false;
  448. getList();
  449. });
  450. }
  451. }
  452. });
  453. }
  454. /** 取消按钮 */
  455. function cancel() {
  456. open.value = false;
  457. reset();
  458. }
  459. /** 选择角色权限范围触发 */
  460. function dataScopeSelectChange(value) {
  461. if (value !== "2") {
  462. deptRef.value.setCheckedKeys([]);
  463. }
  464. }
  465. /** 分配数据权限操作 */
  466. function handleDataScope(row) {
  467. reset();
  468. const deptTreeSelect = getDeptTree(row.roleId);
  469. getRole(row.roleId).then((response) => {
  470. form.value = response.data;
  471. openDataScope.value = true;
  472. nextTick(() => {
  473. deptTreeSelect.then((res) => {
  474. nextTick(() => {
  475. if (deptRef.value) {
  476. deptRef.value.setCheckedKeys(res.checkedKeys);
  477. }
  478. });
  479. });
  480. });
  481. title.value = "分配数据权限";
  482. });
  483. }
  484. /** 提交按钮(数据权限) */
  485. function submitDataScope() {
  486. if (form.value.roleId != undefined) {
  487. form.value.deptIds = getDeptAllCheckedKeys();
  488. dataScope(form.value).then((response) => {
  489. proxy.$modal.msgSuccess("修改成功");
  490. openDataScope.value = false;
  491. getList();
  492. });
  493. }
  494. }
  495. /** 取消按钮(数据权限)*/
  496. function cancelDataScope() {
  497. openDataScope.value = false;
  498. reset();
  499. }
  500. getList();
  501. </script>