index.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. <script setup lang="ts">
  2. import { reactive, ref, unref } from 'vue'
  3. import dayjs from 'dayjs'
  4. import { DICT_TYPE, getDictOptions } from '@/utils/dict'
  5. import { useTable } from '@/hooks/web/useTable'
  6. import { useI18n } from '@/hooks/web/useI18n'
  7. import { FormExpose } from '@/components/Form'
  8. import type { RoleVO } from '@/api/system/role/types'
  9. import { rules, allSchemas } from './role.data'
  10. import * as RoleApi from '@/api/system/role'
  11. import Dialog from '@/components/Dialog/src/Dialog.vue'
  12. import {
  13. ElForm,
  14. ElFormItem,
  15. ElInput,
  16. ElSelect,
  17. ElOption,
  18. ElMessage,
  19. ElTree,
  20. ElCard,
  21. ElCheckbox
  22. } from 'element-plus'
  23. import { listSimpleMenusApi } from '@/api/system/menu'
  24. import { listSimpleDeptApi } from '@/api/system/dept'
  25. import { handleTree } from '@/utils/tree'
  26. import { SystemDataScopeEnum } from '@/utils/constants'
  27. const { t } = useI18n() // 国际化
  28. // ========== 列表相关 ==========
  29. const { register, tableObject, methods } = useTable<RoleVO>({
  30. getListApi: RoleApi.getRolePageApi,
  31. delListApi: RoleApi.deleteRoleApi
  32. })
  33. const { getList, setSearchParams, delList } = methods
  34. // ========== CRUD 相关 ==========
  35. const loading = ref(false) // 遮罩层
  36. const actionType = ref('') // 操作按钮的类型
  37. const dialogVisible = ref(false) // 是否显示弹出层
  38. const dialogTitle = ref('edit') // 弹出层标题
  39. const formRef = ref<FormExpose>() // 表单 Ref
  40. // 设置标题
  41. const setDialogTile = (type: string) => {
  42. dialogTitle.value = t('action.' + type)
  43. actionType.value = type
  44. dialogVisible.value = true
  45. }
  46. // 新增操作
  47. const handleCreate = () => {
  48. setDialogTile('create')
  49. // 重置表单
  50. unref(formRef)?.getElFormRef()?.resetFields()
  51. }
  52. // 修改操作
  53. const handleUpdate = async (row: RoleVO) => {
  54. setDialogTile('update')
  55. // 设置数据
  56. const res = await RoleApi.getRoleApi(row.id)
  57. unref(formRef)?.setValues(res)
  58. }
  59. // 提交按钮
  60. const submitForm = async () => {
  61. loading.value = true
  62. // 提交请求
  63. try {
  64. const data = unref(formRef)?.formModel as RoleVO
  65. if (actionType.value === 'create') {
  66. await RoleApi.createRoleApi(data)
  67. ElMessage.success(t('common.createSuccess'))
  68. } else {
  69. await RoleApi.updateRoleApi(data)
  70. ElMessage.success(t('common.updateSuccess'))
  71. }
  72. // 操作成功,重新加载列表
  73. dialogVisible.value = false
  74. await getList()
  75. } finally {
  76. loading.value = false
  77. }
  78. }
  79. // 删除操作
  80. const handleDelete = (row: RoleVO) => {
  81. delList(row.id, false)
  82. }
  83. // ========== 详情相关 ==========
  84. const detailRef = ref() // 详情 Ref
  85. // 详情操作
  86. const handleDetail = async (row: RoleVO) => {
  87. // 设置数据
  88. detailRef.value = row
  89. setDialogTile('detail')
  90. }
  91. // ========== 数据权限 ==========
  92. const dataScopeForm = reactive({
  93. name: '',
  94. code: '',
  95. dataScope: 0,
  96. checkStrictly: true,
  97. checkList: []
  98. })
  99. const defaultProps = {
  100. children: 'children',
  101. label: 'name',
  102. value: 'id'
  103. }
  104. const treeOptions = ref([]) // 菜单树形结构
  105. const treeRef = ref<InstanceType<typeof ElTree>>()
  106. const dialogScopeVisible = ref(false)
  107. const dialogScopeTitle = ref('数据权限')
  108. const actionScopeType = ref('')
  109. const dataScopeDictDatas = ref()
  110. // 选项
  111. const treeNodeAll = ref(false)
  112. // 权限操作
  113. const handleScope = async (type: string, row: RoleVO) => {
  114. dataScopeForm.name = row.name
  115. dataScopeForm.code = row.code
  116. if (type === 'menu') {
  117. const menuRes = await listSimpleMenusApi()
  118. treeOptions.value = handleTree(menuRes)
  119. dataScopeDictDatas.value = getDictOptions(DICT_TYPE.SYSTEM_DATA_SCOPE)
  120. } else if (type === 'dept') {
  121. const deptRes = await listSimpleDeptApi()
  122. treeOptions.value = handleTree(deptRes)
  123. }
  124. actionScopeType.value = type
  125. dialogScopeVisible.value = true
  126. }
  127. // 树权限(父子联动)
  128. const handleCheckedTreeConnect = (value) => {
  129. dataScopeForm.checkStrictly = value ? true : false
  130. }
  131. // 全选/全不选
  132. const handleCheckedTreeNodeAll = (value) => {
  133. treeRef.value?.setCheckedNodes(value ? dataScopeForm.checkList : [])
  134. }
  135. // TODO:保存
  136. const submitScope = () => {
  137. console.info()
  138. }
  139. // ========== 初始化 ==========
  140. getList()
  141. </script>
  142. <template>
  143. <!-- 搜索工作区 -->
  144. <ContentWrap>
  145. <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
  146. </ContentWrap>
  147. <ContentWrap>
  148. <!-- 操作工具栏 -->
  149. <div class="mb-10px">
  150. <el-button type="primary" v-hasPermi="['system:role:create']" @click="handleCreate">
  151. <Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}
  152. </el-button>
  153. </div>
  154. <!-- 列表 -->
  155. <Table
  156. :columns="allSchemas.tableColumns"
  157. :selection="false"
  158. :data="tableObject.tableList"
  159. :loading="tableObject.loading"
  160. :pagination="{
  161. total: tableObject.total
  162. }"
  163. v-model:pageSize="tableObject.pageSize"
  164. v-model:currentPage="tableObject.currentPage"
  165. @register="register"
  166. >
  167. <template #type="{ row }">
  168. <DictTag :type="DICT_TYPE.SYSTEM_ROLE_TYPE" :value="row.type" />
  169. </template>
  170. <template #status="{ row }">
  171. <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
  172. </template>
  173. <template #createTime="{ row }">
  174. <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
  175. </template>
  176. <template #action="{ row }">
  177. <el-button
  178. link
  179. type="primary"
  180. v-hasPermi="['system:role:update']"
  181. @click="handleUpdate(row)"
  182. >
  183. <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
  184. </el-button>
  185. <el-button
  186. link
  187. type="primary"
  188. v-hasPermi="['system:role:update']"
  189. @click="handleDetail(row)"
  190. >
  191. <Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }}
  192. </el-button>
  193. <el-button
  194. link
  195. type="primary"
  196. v-hasPermi="['system:permission:assign-role-menu']"
  197. @click="handleScope('menu', row)"
  198. >
  199. <Icon icon="ep:basketball" class="mr-1px" /> 菜单权限
  200. </el-button>
  201. <el-button
  202. link
  203. type="primary"
  204. v-hasPermi="['system:permission:assign-role-data-scope']"
  205. @click="handleScope('data', row)"
  206. >
  207. <Icon icon="ep:coin" class="mr-1px" /> 数据权限
  208. </el-button>
  209. <el-button
  210. link
  211. type="primary"
  212. v-hasPermi="['system:role:delete']"
  213. @click="handleDelete(row)"
  214. >
  215. <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
  216. </el-button>
  217. </template>
  218. </Table>
  219. </ContentWrap>
  220. <Dialog v-model="dialogVisible" :title="dialogTitle">
  221. <!-- 对话框(添加 / 修改) -->
  222. <Form
  223. v-if="['create', 'update'].includes(actionType)"
  224. :schema="allSchemas.formSchema"
  225. :rules="rules"
  226. ref="formRef"
  227. />
  228. <!-- 对话框(详情) -->
  229. <Descriptions
  230. v-if="actionType === 'detail'"
  231. :schema="allSchemas.detailSchema"
  232. :data="detailRef"
  233. >
  234. <template #type="{ row }">
  235. <DictTag :type="DICT_TYPE.SYSTEM_ROLE_TYPE" :value="row.type" />
  236. </template>
  237. <template #status="{ row }">
  238. <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
  239. </template>
  240. <template #createTime="{ row }">
  241. <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
  242. </template>
  243. </Descriptions>
  244. <!-- 操作按钮 -->
  245. <template #footer>
  246. <el-button
  247. v-if="['create', 'update'].includes(actionType)"
  248. type="primary"
  249. :loading="loading"
  250. @click="submitForm"
  251. >
  252. {{ t('action.save') }}
  253. </el-button>
  254. <el-button @click="dialogVisible = false">{{ t('dialog.close') }}</el-button>
  255. </template>
  256. </Dialog>
  257. <Dialog v-model="dialogScopeVisible" :title="dialogScopeTitle">
  258. <el-form :model="dataScopeForm">
  259. <el-form-item label="角色名称">
  260. <el-input v-model="dataScopeForm.name" :disabled="true" />
  261. </el-form-item>
  262. <el-form-item label="角色标识">
  263. <el-input v-model="dataScopeForm.code" :disabled="true" />
  264. </el-form-item>
  265. <!-- 分配角色的数据权限对话框 -->
  266. <el-form-item label="权限范围" v-if="actionScopeType === 'data'">
  267. <el-select v-model="dataScopeForm.dataScope">
  268. <el-option
  269. v-for="item in dataScopeDictDatas"
  270. :key="parseInt(item.value)"
  271. :label="item.label"
  272. :value="parseInt(item.value)"
  273. />
  274. </el-select>
  275. </el-form-item>
  276. <!-- 分配角色的菜单权限对话框 -->
  277. <el-form-item
  278. label="权限范围"
  279. v-if="
  280. actionScopeType === 'menu' || dataScopeForm.dataScope === SystemDataScopeEnum.DEPT_CUSTOM
  281. "
  282. >
  283. <el-card class="box-card">
  284. <template #header>
  285. <el-checkbox
  286. :checked="!dataScopeForm.checkStrictly"
  287. @change="handleCheckedTreeConnect($event)"
  288. >父子联动(选中父节点,自动选择子节点)
  289. </el-checkbox>
  290. <el-checkbox v-model="treeNodeAll" @change="handleCheckedTreeNodeAll($event)">
  291. 全选/全不选
  292. </el-checkbox>
  293. </template>
  294. <el-tree
  295. ref="treeRef"
  296. node-key="id"
  297. show-checkbox
  298. default-expand-all
  299. :check-strictly="dataScopeForm.checkStrictly"
  300. :props="defaultProps"
  301. :data="treeOptions"
  302. empty-text="加载中,请稍后"
  303. />
  304. </el-card>
  305. </el-form-item>
  306. </el-form>
  307. <!-- 操作按钮 -->
  308. <template #footer>
  309. <el-button type="primary" :loading="loading" @click="submitScope">
  310. {{ t('action.save') }}
  311. </el-button>
  312. <el-button @click="dialogScopeVisible = false">{{ t('dialog.close') }}</el-button>
  313. </template>
  314. </Dialog>
  315. </template>