index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. <script setup lang="ts">
  2. import {
  3. getRolePage,
  4. updateRole,
  5. addRole,
  6. deleteRoles,
  7. getRoleMenuIds,
  8. updateRoleMenus,
  9. } from "@/api/system/role";
  10. import { getMenuOptions } from "@/api/system/menu";
  11. defineOptions({
  12. name: "Role",
  13. inheritAttrs: false,
  14. });
  15. const queryFormRef = ref(ElForm);
  16. const roleFormRef = ref(ElForm);
  17. const menuRef = ref(ElTree);
  18. const loading = ref(false);
  19. const ids = ref<number[]>([]);
  20. const total = ref(0);
  21. const queryParams = reactive({
  22. pageNo: 1,
  23. pageSize: 10,
  24. });
  25. const roleList = ref<[]>();
  26. const dialog = reactive({
  27. title: "",
  28. visible: false,
  29. });
  30. const formData = ref({
  31. id: "",
  32. sort: 0,
  33. scope: 0,
  34. status: 0,
  35. state: 0,
  36. roleCode: "",
  37. roleName: "",
  38. });
  39. const rules = reactive({
  40. roleName: [{ required: true, message: "请输入角色名称", trigger: "blur" }],
  41. scope: [{ required: true, message: "请选择数据权限", trigger: "blur" }],
  42. state: [{ required: true, message: "请选择状态", trigger: "blur" }],
  43. });
  44. const menuDialogVisible = ref(false);
  45. const menuList = ref([]);
  46. interface CheckedRole {
  47. id?: number;
  48. name?: string;
  49. }
  50. let checkedRole: CheckedRole = reactive({});
  51. /** 查询 */
  52. function handleQuery() {
  53. loading.value = true;
  54. getRolePage(queryParams)
  55. .then(({ data }) => {
  56. roleList.value = data.records;
  57. total.value = data.totalCount;
  58. })
  59. .finally(() => {
  60. loading.value = false;
  61. });
  62. }
  63. /** 重置查询 */
  64. function resetQuery() {
  65. queryFormRef.value.resetFields();
  66. queryParams.pageNo = 1;
  67. handleQuery();
  68. }
  69. /** 行checkbox 选中事件 */
  70. function handleSelectionChange(selection: any) {
  71. ids.value = selection.map((item: any) => item.id);
  72. }
  73. /** 打开角色表单弹窗 */
  74. function openDialog(row?: any) {
  75. dialog.visible = true;
  76. if (row) {
  77. dialog.title = "修改角色";
  78. Object.assign(formData.value, row);
  79. } else {
  80. dialog.title = "新增角色";
  81. formData.value.id = undefined;
  82. formData.value.scope = 0;
  83. formData.value.state = 0;
  84. formData.value.roleCode = "";
  85. formData.value.roleName = "";
  86. }
  87. }
  88. /** 角色保存提交 */
  89. function handleSubmit() {
  90. roleFormRef.value.validate((valid: any) => {
  91. if (valid) {
  92. loading.value = true;
  93. const roleId = formData.value.id;
  94. if (roleId) {
  95. updateRole(formData.value)
  96. .then(() => {
  97. ElMessage.success("修改成功");
  98. closeDialog();
  99. resetQuery();
  100. })
  101. .finally(() => (loading.value = false));
  102. } else {
  103. addRole(formData.value)
  104. .then(() => {
  105. ElMessage.success("新增成功");
  106. closeDialog();
  107. resetQuery();
  108. })
  109. .finally(() => (loading.value = false));
  110. }
  111. }
  112. });
  113. }
  114. /** 关闭表单弹窗 */
  115. function closeDialog() {
  116. dialog.visible = false;
  117. resetForm();
  118. }
  119. /** 重置表单 */
  120. function resetForm() {
  121. roleFormRef.value.resetFields();
  122. roleFormRef.value.clearValidate();
  123. formData.id = undefined;
  124. formData.sort = 1;
  125. formData.status = 1;
  126. }
  127. /** 删除角色 */
  128. function handleDelete(roleId?: number) {
  129. const roleIds = [roleId || ids.value].join(",");
  130. if (!roleIds) {
  131. ElMessage.warning("请勾选删除项");
  132. return;
  133. }
  134. ElMessageBox.confirm("确认删除已选中的数据项?", "警告", {
  135. confirmButtonText: "确定",
  136. cancelButtonText: "取消",
  137. type: "warning",
  138. }).then(() => {
  139. loading.value = true;
  140. deleteRoles(ids.value)
  141. .then(() => {
  142. ElMessage.success("删除成功");
  143. resetQuery();
  144. })
  145. .finally(() => (loading.value = false));
  146. });
  147. }
  148. /** 打开分配菜单弹窗 */
  149. function openMenuDialog(row: any) {
  150. const roleId = row.id;
  151. if (roleId) {
  152. checkedRole = {
  153. id: roleId,
  154. name: row.roleName,
  155. };
  156. menuDialogVisible.value = true;
  157. loading.value = true;
  158. // 获取所有的菜单
  159. getMenuOptions().then((response) => {
  160. menuList.value = response.data;
  161. // 回显角色已拥有的菜单
  162. getRoleMenuIds(roleId)
  163. .then(({ data }) => {
  164. const checkedMenuIds = data;
  165. checkedMenuIds.forEach((menuId) =>
  166. menuRef.value.setChecked(menuId, true, false)
  167. );
  168. })
  169. .finally(() => {
  170. loading.value = false;
  171. });
  172. });
  173. }
  174. }
  175. /** 角色分配菜单保存提交 */
  176. function handleRoleMenuSubmit() {
  177. const roleId = checkedRole.id;
  178. if (roleId) {
  179. const checkedMenuIds: number[] = menuRef.value
  180. .getCheckedNodes(false, true)
  181. .map((node: any) => {
  182. return node.id;
  183. });
  184. loading.value = true;
  185. updateRoleMenus(roleId, checkedMenuIds)
  186. .then(() => {
  187. ElMessage.success("分配权限成功");
  188. menuDialogVisible.value = false;
  189. resetQuery();
  190. })
  191. .finally(() => {
  192. loading.value = false;
  193. });
  194. }
  195. }
  196. onMounted?.(() => {
  197. handleQuery();
  198. });
  199. </script>
  200. <template>
  201. <div class="app-container">
  202. <div class="search-container">
  203. <el-form ref="queryFormRef" :model="queryParams" :inline="true">
  204. <el-form-item prop="keywords" label="关键字">
  205. <el-input
  206. v-model="queryParams.keywords"
  207. placeholder="编码/名称"
  208. clearable
  209. @keyup.enter="handleQuery"
  210. />
  211. </el-form-item>
  212. <el-form-item>
  213. <el-button type="primary" @click="handleQuery"
  214. ><i-ep-search />搜索</el-button
  215. >
  216. <el-button @click="resetQuery"><i-ep-refresh />重置</el-button>
  217. </el-form-item>
  218. </el-form>
  219. </div>
  220. <el-card shadow="never" class="table-container">
  221. <template #header>
  222. <el-button
  223. type="primary"
  224. v-hasPerm="['sys:role:add']"
  225. @click="openDialog()"
  226. ><i-ep-plus />新增</el-button
  227. >
  228. <el-button
  229. type="danger"
  230. v-hasPerm="['sys:role:del']"
  231. :disabled="ids.length === 0"
  232. @click="handleDelete()"
  233. ><i-ep-delete />删除</el-button
  234. >
  235. </template>
  236. <el-table
  237. ref="dataTableRef"
  238. v-loading="loading"
  239. :data="roleList"
  240. highlight-current-row
  241. border
  242. @selection-change="handleSelectionChange"
  243. >
  244. <el-table-column type="selection" width="55" align="center" />
  245. <el-table-column label="角色编码" prop="roleCode" />
  246. <el-table-column label="角色名称" prop="roleName" />
  247. <el-table-column label="状态" align="center" width="100">
  248. <template #default="scope">
  249. <el-tag v-if="scope.row.state === 0" type="success">正常</el-tag>
  250. <el-tag v-else type="info">禁用</el-tag>
  251. </template>
  252. </el-table-column>
  253. <el-table-column label="创建时间" align="center" prop="created" />
  254. <el-table-column label="创建人" align="center" prop="creator" />
  255. <el-table-column fixed="right" label="操作" width="220">
  256. <template #default="scope">
  257. <el-button
  258. type="primary"
  259. size="small"
  260. link
  261. v-hasPerm="['sys:role:dis']"
  262. @click="openMenuDialog(scope.row)"
  263. >
  264. <i-ep-position />分配权限
  265. </el-button>
  266. <el-button
  267. type="primary"
  268. size="small"
  269. link
  270. v-hasPerm="['sys:role:edit']"
  271. @click="openDialog(scope.row)"
  272. >
  273. <i-ep-edit />编辑
  274. </el-button>
  275. <!-- <el-button
  276. type="primary"
  277. size="small"
  278. link
  279. @click="handleDelete(scope.row.id)"
  280. >
  281. <i-ep-delete />删除
  282. </el-button>-->
  283. </template>
  284. </el-table-column>
  285. </el-table>
  286. <pagination
  287. v-if="total > 0"
  288. v-model:total="total"
  289. v-model:page="queryParams.pageNo"
  290. v-model:limit="queryParams.pageSize"
  291. @pagination="handleQuery"
  292. />
  293. </el-card>
  294. <!-- 角色表单弹窗 -->
  295. <el-dialog
  296. v-model="dialog.visible"
  297. :title="dialog.title"
  298. width="500px"
  299. @close="closeDialog"
  300. >
  301. <el-form
  302. ref="roleFormRef"
  303. :model="formData"
  304. :rules="rules"
  305. label-width="100px"
  306. >
  307. <el-form-item label="角色名称" prop="roleName">
  308. <el-input v-model="formData.roleName" placeholder="请输入角色名称" />
  309. </el-form-item>
  310. <!-- <el-form-item label="角色编码" prop="roleCode">
  311. <el-input v-model="formData.roleCode" placeholder="请输入角色编码" />
  312. </el-form-item>-->
  313. <el-form-item label="数据权限" prop="scope">
  314. <el-select v-model="formData.scope">
  315. <el-option :key="0" label="全部数据" :value="0" />
  316. <el-option :key="1" label="部门及子部门数据" :value="1" />
  317. <el-option :key="2" label="本部门数据" :value="2" />
  318. <el-option :key="3" label="本人数据" :value="3" />
  319. </el-select>
  320. </el-form-item>
  321. <el-form-item label="状态" prop="state">
  322. <el-radio-group v-model="formData.state">
  323. <el-radio :value="0">正常</el-radio>
  324. <el-radio :value="1">停用</el-radio>
  325. </el-radio-group>
  326. </el-form-item>
  327. </el-form>
  328. <template #footer>
  329. <div class="dialog-footer">
  330. <el-button type="primary" @click="handleSubmit">确 定</el-button>
  331. <el-button @click="closeDialog">取 消</el-button>
  332. </div>
  333. </template>
  334. </el-dialog>
  335. <!-- 分配菜单弹窗 -->
  336. <el-dialog
  337. v-model="menuDialogVisible"
  338. :title="'【' + checkedRole.name + '】权限分配'"
  339. width="550px"
  340. >
  341. <el-scrollbar v-loading="loading" max-height="600px">
  342. <el-tree
  343. ref="menuRef"
  344. node-key="id"
  345. show-checkbox
  346. :check-strictly="true"
  347. :props="{
  348. children: 'childs',
  349. label: 'menuName',
  350. value: 'id',
  351. disabled: '',
  352. }"
  353. :data="menuList"
  354. :default-expand-all="false"
  355. >
  356. <template #default="{ data }">
  357. {{ data.menuName }}
  358. </template>
  359. </el-tree>
  360. </el-scrollbar>
  361. <template #footer>
  362. <div class="dialog-footer">
  363. <el-button type="primary" @click="handleRoleMenuSubmit"
  364. >确 定</el-button
  365. >
  366. <el-button @click="menuDialogVisible = false">取 消</el-button>
  367. </div>
  368. </template>
  369. </el-dialog>
  370. </div>
  371. </template>