index.vue 10 KB

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