index.vue 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. <script setup lang="ts">
  2. import { reactive, ref } from 'vue'
  3. import dayjs from 'dayjs'
  4. import { useI18n } from '@/hooks/web/useI18n'
  5. import {
  6. VxeFormEvents,
  7. VxeFormInstance,
  8. VxeFormItemProps,
  9. VxeGrid,
  10. VxeGridInstance,
  11. VxeGridProps
  12. } from 'vxe-table'
  13. import * as PostApi from '@/api/system/post'
  14. import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
  15. import { ContentWrap } from '@/components/ContentWrap'
  16. import { PostPageReqVO, PostVO } from '@/api/system/post/types'
  17. import { rules, allSchemas } from './post.data'
  18. import { ElMessage, ElMessageBox } from 'element-plus'
  19. const { t } = useI18n() // 国际化
  20. const xGrid = ref<VxeGridInstance>()
  21. const xForm = ref<VxeFormInstance>()
  22. const dialogVisible = ref(false) // 是否显示弹出层
  23. const dialogTitle = ref('edit') // 弹出层标题
  24. const actionType = ref('') // 操作按钮的类型
  25. const actionLoading = ref(false) // 遮罩层
  26. const gridOptions = reactive<VxeGridProps>({
  27. loading: false,
  28. rowConfig: {
  29. keyField: 'id',
  30. isHover: true
  31. },
  32. toolbarConfig: {
  33. custom: true,
  34. slots: {
  35. buttons: 'toolbar_buttons'
  36. }
  37. },
  38. printConfig: {
  39. columns: [
  40. { field: 'name' },
  41. { field: 'code' },
  42. { field: 'sort' },
  43. { field: 'status' },
  44. { field: 'createTime' }
  45. ]
  46. },
  47. formConfig: {
  48. titleWidth: 100,
  49. titleAlign: 'right',
  50. items: [
  51. {
  52. field: 'name',
  53. title: '岗位名称',
  54. span: 6,
  55. itemRender: { name: '$input', props: { placeholder: '请输入岗位名称' } }
  56. },
  57. {
  58. field: 'code',
  59. title: '岗位编码',
  60. span: 6,
  61. itemRender: { name: '$input', props: { placeholder: '请输入岗位编码' } }
  62. },
  63. {
  64. field: 'status',
  65. title: t('common.status'),
  66. span: 6,
  67. itemRender: { name: '$select', options: getIntDictOptions(DICT_TYPE.COMMON_STATUS) }
  68. },
  69. {
  70. span: 24,
  71. align: 'center',
  72. collapseNode: true,
  73. itemRender: {
  74. name: '$buttons',
  75. children: [
  76. { props: { type: 'submit', content: t('common.query'), status: 'primary' } },
  77. { props: { type: 'reset', content: t('common.reset') } }
  78. ]
  79. }
  80. }
  81. ]
  82. },
  83. columns: [
  84. { type: 'seq', title: t('common.index'), width: 100 },
  85. { field: 'name', title: '岗位名称' },
  86. { field: 'code', title: '岗位编码' },
  87. { field: 'sort', title: '岗位顺序' },
  88. {
  89. field: 'status',
  90. title: t('common.status'),
  91. slots: {
  92. default: 'status_default'
  93. }
  94. },
  95. {
  96. field: 'createTime',
  97. title: t('common.createTime'),
  98. width: 160,
  99. sortable: true,
  100. formatter: 'formatDate'
  101. },
  102. {
  103. field: 'action',
  104. title: t('table.action'),
  105. width: '240px',
  106. showOverflow: true,
  107. slots: {
  108. default: 'action_default'
  109. }
  110. }
  111. ],
  112. pagerConfig: {
  113. border: false,
  114. background: false,
  115. perfect: true,
  116. pageSize: 10,
  117. pagerCount: 7,
  118. pageSizes: [5, 10, 15, 20, 50, 100, 200, 500],
  119. layouts: ['PrevJump', 'PrevPage', 'Jump', 'PageCount', 'NextPage', 'NextJump', 'Sizes', 'Total']
  120. },
  121. proxyConfig: {
  122. seq: true, // 启用动态序号代理(分页之后索引自动计算为当前页的起始序号)
  123. props: {
  124. result: 'list',
  125. total: 'total'
  126. },
  127. ajax: {
  128. query: ({ page, form }) => {
  129. const queryParams: PostPageReqVO = Object.assign({}, form)
  130. queryParams.pageSize = page.pageSize
  131. queryParams.pageNo = page.currentPage
  132. return new Promise(async (resolve) => {
  133. resolve(await PostApi.getPostPageApi(queryParams))
  134. })
  135. }
  136. }
  137. }
  138. })
  139. const formData = ref<PostVO>({
  140. name: '',
  141. code: '',
  142. sort: 0,
  143. status: 0,
  144. remark: '',
  145. createTime: ''
  146. })
  147. const formItems = ref<VxeFormItemProps[]>([
  148. {
  149. field: 'id',
  150. title: 'id',
  151. visible: false
  152. },
  153. {
  154. field: 'name',
  155. title: '岗位名称',
  156. span: 12,
  157. itemRender: { name: '$input', props: { placeholder: '请输入岗位名称' } }
  158. },
  159. {
  160. field: 'code',
  161. title: '岗位编码',
  162. span: 12,
  163. itemRender: { name: '$input', props: { placeholder: '请输入岗位编码' } }
  164. },
  165. {
  166. field: 'sort',
  167. title: '岗位顺序',
  168. span: 12,
  169. itemRender: { name: '$input', props: { type: 'number', placeholder: '请输入岗位顺序' } }
  170. },
  171. {
  172. field: 'status',
  173. title: t('common.status'),
  174. span: 12,
  175. itemRender: {
  176. name: '$select',
  177. options: getIntDictOptions(DICT_TYPE.COMMON_STATUS),
  178. props: { placeholder: '请选择' }
  179. }
  180. },
  181. {
  182. align: 'center',
  183. span: 24,
  184. itemRender: {
  185. name: '$buttons',
  186. children: [
  187. { props: { type: 'submit', content: t('action.save'), status: 'primary' } },
  188. { props: { type: 'reset', content: t('common.reset') } }
  189. ]
  190. }
  191. }
  192. ])
  193. // 设置标题
  194. const setDialogTile = (type: string) => {
  195. dialogTitle.value = t('action.' + type)
  196. actionType.value = type
  197. dialogVisible.value = true
  198. }
  199. // ========== 详情相关 ==========
  200. const detailRef = ref() // 详情 Ref
  201. // 详情操作
  202. const handleDetail = (row: PostVO) => {
  203. setDialogTile('detail')
  204. detailRef.value = row
  205. }
  206. // 新增操作
  207. const handleCreate = () => {
  208. const $form = xForm.value
  209. $form?.reset()
  210. setDialogTile('create')
  211. }
  212. // 修改操作
  213. const handleUpdate = async (rowId: number) => {
  214. setDialogTile('update')
  215. // 设置数据
  216. const res = await PostApi.getPostApi(rowId)
  217. formData.value = res
  218. }
  219. // 删除操作
  220. const handleDelete = (rowId: number) => {
  221. ElMessageBox.confirm(t('common.delMessage'), t('common.confirmTitle'), {
  222. confirmButtonText: t('common.ok'),
  223. cancelButtonText: t('common.cancel'),
  224. type: 'warning'
  225. })
  226. .then(async () => {
  227. await PostApi.deletePostApi(rowId)
  228. })
  229. .finally(() => {
  230. ElMessage.success(t('common.delSuccess'))
  231. const $grid = xGrid.value
  232. $grid?.commitProxy('query')
  233. })
  234. }
  235. // 提交按钮
  236. const submitForm: VxeFormEvents.Submit = async () => {
  237. actionLoading.value = true
  238. // 提交请求
  239. try {
  240. const data = formData.value as PostVO
  241. if (actionType.value === 'create') {
  242. await PostApi.createPostApi(data)
  243. ElMessage.success(t('common.createSuccess'))
  244. } else {
  245. await PostApi.updatePostApi(data)
  246. ElMessage.success(t('common.updateSuccess'))
  247. }
  248. // 操作成功,重新加载列表
  249. dialogVisible.value = false
  250. } finally {
  251. actionLoading.value = false
  252. const $grid = xGrid.value
  253. $grid?.commitProxy('query')
  254. }
  255. }
  256. </script>
  257. <template>
  258. <ContentWrap>
  259. <vxe-grid ref="xGrid" v-bind="gridOptions">
  260. <template #toolbar_buttons>
  261. <el-button type="primary" v-hasPermi="['system:post:create']" @click="handleCreate">
  262. <Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}
  263. </el-button>
  264. </template>
  265. <template #status_default="{ row }">
  266. <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
  267. </template>
  268. <template #action_default="{ row }">
  269. <el-button
  270. link
  271. type="primary"
  272. v-hasPermi="['system:post:update']"
  273. @click="handleUpdate(row.id)"
  274. >
  275. <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
  276. </el-button>
  277. <el-button
  278. link
  279. type="primary"
  280. v-hasPermi="['system:post:update']"
  281. @click="handleDetail(row)"
  282. >
  283. <Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }}
  284. </el-button>
  285. <el-button
  286. link
  287. type="primary"
  288. v-hasPermi="['system:post:delete']"
  289. @click="handleDelete(row.id)"
  290. >
  291. <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
  292. </el-button>
  293. </template>
  294. </vxe-grid>
  295. </ContentWrap>
  296. <vxe-modal
  297. v-model="dialogVisible"
  298. id="myModal6"
  299. :title="dialogTitle"
  300. width="800"
  301. height="400"
  302. min-width="460"
  303. min-height="320"
  304. show-zoom
  305. resize
  306. remember
  307. storage
  308. transfer
  309. show-footer
  310. >
  311. <template #default>
  312. <!-- 对话框(添加 / 修改) -->
  313. <vxe-form
  314. ref="xForm"
  315. v-if="['create', 'update'].includes(actionType)"
  316. :data="formData"
  317. :items="formItems"
  318. :rules="rules"
  319. @submit="submitForm"
  320. />
  321. <Descriptions
  322. v-if="actionType === 'detail'"
  323. :schema="allSchemas.detailSchema"
  324. :data="detailRef"
  325. >
  326. <template #status="{ row }">
  327. <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
  328. </template>
  329. <template #createTime="{ row }">
  330. <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
  331. </template>
  332. </Descriptions>
  333. </template>
  334. </vxe-modal>
  335. </template>