index.vue 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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 detailRef = ref() // 详情 Ref
  81. // 详情操作
  82. const handleDetail = async (row: RoleVO) => {
  83. // 设置数据
  84. detailRef.value = row
  85. setDialogTile('detail')
  86. }
  87. // ========== 数据权限 ==========
  88. const dataScopeForm = reactive({
  89. name: '',
  90. code: '',
  91. dataScope: 0,
  92. checkStrictly: true,
  93. checkList: []
  94. })
  95. const defaultProps = {
  96. children: 'children',
  97. label: 'name',
  98. value: 'id'
  99. }
  100. const treeOptions = ref([]) // 菜单树形结构
  101. const treeRef = ref<InstanceType<typeof ElTree>>()
  102. const dialogScopeVisible = ref(false)
  103. const dialogScopeTitle = ref('数据权限')
  104. const actionScopeType = ref('')
  105. const dataScopeDictDatas = ref()
  106. // 选项
  107. const treeNodeAll = ref(false)
  108. // 权限操作
  109. const handleScope = async (type: string, row: RoleVO) => {
  110. dataScopeForm.name = row.name
  111. dataScopeForm.code = row.code
  112. if (type === 'menu') {
  113. const menuRes = await listSimpleMenusApi()
  114. treeOptions.value = handleTree(menuRes)
  115. dataScopeDictDatas.value = getDictOptions(DICT_TYPE.SYSTEM_DATA_SCOPE)
  116. } else if (type === 'dept') {
  117. const deptRes = await listSimpleDeptApi()
  118. treeOptions.value = handleTree(deptRes)
  119. }
  120. actionScopeType.value = type
  121. dialogScopeVisible.value = true
  122. }
  123. // 树权限(父子联动)
  124. const handleCheckedTreeConnect = (value) => {
  125. dataScopeForm.checkStrictly = value ? true : false
  126. }
  127. // 全选/全不选
  128. const handleCheckedTreeNodeAll = (value) => {
  129. treeRef.value?.setCheckedNodes(value ? dataScopeForm.checkList : [])
  130. }
  131. // TODO:保存
  132. const submitScope = () => {
  133. console.info()
  134. }
  135. // ========== 初始化 ==========
  136. getList()
  137. </script>
  138. <template>
  139. <!-- 搜索工作区 -->
  140. <ContentWrap>
  141. <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
  142. </ContentWrap>
  143. <ContentWrap>
  144. <!-- 操作工具栏 -->
  145. <div class="mb-10px">
  146. <el-button type="primary" v-hasPermi="['system:role:create']" @click="handleCreate">
  147. <Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}
  148. </el-button>
  149. </div>
  150. <!-- 列表 -->
  151. <Table
  152. :columns="allSchemas.tableColumns"
  153. :selection="false"
  154. :data="tableObject.tableList"
  155. :loading="tableObject.loading"
  156. :pagination="{
  157. total: tableObject.total
  158. }"
  159. v-model:pageSize="tableObject.pageSize"
  160. v-model:currentPage="tableObject.currentPage"
  161. @register="register"
  162. >
  163. <template #type="{ row }">
  164. <DictTag :type="DICT_TYPE.SYSTEM_ROLE_TYPE" :value="row.type" />
  165. </template>
  166. <template #status="{ row }">
  167. <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
  168. </template>
  169. <template #createTime="{ row }">
  170. <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
  171. </template>
  172. <template #action="{ row }">
  173. <el-button
  174. link
  175. type="primary"
  176. v-hasPermi="['system:role:update']"
  177. @click="handleUpdate(row)"
  178. >
  179. <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
  180. </el-button>
  181. <el-button
  182. link
  183. type="primary"
  184. v-hasPermi="['system:role:update']"
  185. @click="handleDetail(row)"
  186. >
  187. <Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }}
  188. </el-button>
  189. <el-button
  190. link
  191. type="primary"
  192. v-hasPermi="['system:permission:assign-role-menu']"
  193. @click="handleScope('menu', row)"
  194. >
  195. <Icon icon="ep:basketball" class="mr-1px" /> 菜单权限
  196. </el-button>
  197. <el-button
  198. link
  199. type="primary"
  200. v-hasPermi="['system:permission:assign-role-data-scope']"
  201. @click="handleScope('data', row)"
  202. >
  203. <Icon icon="ep:coin" class="mr-1px" /> 数据权限
  204. </el-button>
  205. <el-button
  206. link
  207. type="primary"
  208. v-hasPermi="['system:role:delete']"
  209. @click="delList(row.id, false)"
  210. >
  211. <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
  212. </el-button>
  213. </template>
  214. </Table>
  215. </ContentWrap>
  216. <Dialog v-model="dialogVisible" :title="dialogTitle">
  217. <!-- 对话框(添加 / 修改) -->
  218. <Form
  219. v-if="['create', 'update'].includes(actionType)"
  220. :schema="allSchemas.formSchema"
  221. :rules="rules"
  222. ref="formRef"
  223. />
  224. <!-- 对话框(详情) -->
  225. <Descriptions
  226. v-if="actionType === 'detail'"
  227. :schema="allSchemas.detailSchema"
  228. :data="detailRef"
  229. >
  230. <template #type="{ row }">
  231. <DictTag :type="DICT_TYPE.SYSTEM_ROLE_TYPE" :value="row.type" />
  232. </template>
  233. <template #status="{ row }">
  234. <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
  235. </template>
  236. <template #createTime="{ row }">
  237. <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
  238. </template>
  239. </Descriptions>
  240. <!-- 操作按钮 -->
  241. <template #footer>
  242. <el-button
  243. v-if="['create', 'update'].includes(actionType)"
  244. type="primary"
  245. :loading="loading"
  246. @click="submitForm"
  247. >
  248. {{ t('action.save') }}
  249. </el-button>
  250. <el-button @click="dialogVisible = false">{{ t('dialog.close') }}</el-button>
  251. </template>
  252. </Dialog>
  253. <Dialog v-model="dialogScopeVisible" :title="dialogScopeTitle">
  254. <el-form :model="dataScopeForm">
  255. <el-form-item label="角色名称">
  256. <el-input v-model="dataScopeForm.name" :disabled="true" />
  257. </el-form-item>
  258. <el-form-item label="角色标识">
  259. <el-input v-model="dataScopeForm.code" :disabled="true" />
  260. </el-form-item>
  261. <!-- 分配角色的数据权限对话框 -->
  262. <el-form-item label="权限范围" v-if="actionScopeType === 'data'">
  263. <el-select v-model="dataScopeForm.dataScope">
  264. <el-option
  265. v-for="item in dataScopeDictDatas"
  266. :key="parseInt(item.value)"
  267. :label="item.label"
  268. :value="parseInt(item.value)"
  269. />
  270. </el-select>
  271. </el-form-item>
  272. <!-- 分配角色的菜单权限对话框 -->
  273. <el-form-item
  274. label="权限范围"
  275. v-if="
  276. actionScopeType === 'menu' || dataScopeForm.dataScope === SystemDataScopeEnum.DEPT_CUSTOM
  277. "
  278. >
  279. <el-card class="box-card">
  280. <template #header>
  281. <el-checkbox
  282. :checked="!dataScopeForm.checkStrictly"
  283. @change="handleCheckedTreeConnect($event)"
  284. >父子联动(选中父节点,自动选择子节点)
  285. </el-checkbox>
  286. <el-checkbox v-model="treeNodeAll" @change="handleCheckedTreeNodeAll($event)">
  287. 全选/全不选
  288. </el-checkbox>
  289. </template>
  290. <el-tree
  291. ref="treeRef"
  292. node-key="id"
  293. show-checkbox
  294. default-expand-all
  295. :check-strictly="dataScopeForm.checkStrictly"
  296. :props="defaultProps"
  297. :data="treeOptions"
  298. empty-text="加载中,请稍后"
  299. />
  300. </el-card>
  301. </el-form-item>
  302. </el-form>
  303. <!-- 操作按钮 -->
  304. <template #footer>
  305. <el-button type="primary" :loading="loading" @click="submitScope">
  306. {{ t('action.save') }}
  307. </el-button>
  308. <el-button @click="dialogScopeVisible = false">{{ t('dialog.close') }}</el-button>
  309. </template>
  310. </Dialog>
  311. </template>