refactor: vxe crud

pull/2/head
xingyu4j 2022-11-13 13:16:11 +08:00
parent 7cbd6cfb68
commit 120417b792
16 changed files with 190 additions and 119 deletions

View File

@ -1,13 +1,32 @@
import request from '@/config/axios'
import type { MenuVO } from './types'
export interface MenuVO {
id: number
name: string
permission: string
type: number
sort: number
parentId: number
path: string
icon: string
component: string
status: number
visible: boolean
keepAlive: boolean
createTime: string
}
export interface MenuPageReqVO {
name?: string
status?: number
}
// 查询菜单(精简)列表
export const listSimpleMenusApi = () => {
return request.get({ url: '/system/menu/list-all-simple' })
}
// 查询菜单列表
export const getMenuListApi = (params) => {
export const getMenuListApi = (params: MenuPageReqVO) => {
return request.get({ url: '/system/menu/list', params })
}

View File

@ -1,15 +0,0 @@
export type MenuVO = {
id: number
name: string
permission: string
type: number
sort: number
parentId: number
path: string
icon: string
component: string
status: number
visible: boolean
keepAlive: boolean
createTime: string
}

View File

@ -1,8 +1,24 @@
import request from '@/config/axios'
import type { NoticeVO } from './types'
export interface NoticeVO {
id: number
title: string
type: number
content: string
status: number
remark: string
creator: string
createTime: string
updater: string
updateTime: string
}
export interface NoticePageReqVO extends BasePage {
title?: string
status?: number
}
// 查询公告列表
export const getNoticePageApi = (params) => {
export const getNoticePageApi = (params: NoticePageReqVO) => {
return request.get({ url: '/system/notice/page', params })
}

View File

@ -1,12 +0,0 @@
export type NoticeVO = {
id: number
title: string
type: number
content: string
status: number
remark: string
creator: string
createTime: string
updater: string
updateTime: string
}

View File

@ -1,5 +1,26 @@
import request from '@/config/axios'
import type { PostVO, PostPageReqVO, PostExportReqVO } from './types'
export interface PostVO {
id?: number
name: string
code: string
sort: number
status: number
remark: string
createTime?: string
}
export interface PostPageReqVO extends BasePage {
code?: string
name?: string
status?: number
}
export interface PostExportReqVO {
code?: string
name?: string
status?: number
}
// 查询岗位列表
export const getPostPageApi = async (params: PostPageReqVO) => {
@ -31,7 +52,6 @@ export const deletePostApi = async (id: number) => {
}
// 导出岗位
// TODO @星语:导出这块,咱怎么弄哈
export const exportPostApi = async (params: PostExportReqVO) => {
return await request.download({ url: '/system/post/export', params })
}

View File

@ -1,24 +0,0 @@
export type PostVO = {
id?: number
name: string
code: string
sort: number
status: number
remark: string
createTime?: string
}
// TODO @星语:要不要搞个 Page 基类呀?和后端对应
export type PostPageReqVO = {
code: string
name: string
status?: number
pageSize?: number
pageNo?: number
}
export type PostExportReqVO = {
code: string
name: string
status?: number
}

View File

@ -38,7 +38,7 @@ onUpdated(() => {
dictData?.colorType === '' ||
dictData?.colorType === undefined
"
:key="dictData?.value"
:key="dictData?.value.toString()"
:class="dictData?.cssClass"
>
{{ dictData?.label }}

View File

@ -71,6 +71,18 @@ export const useMessage = () => {
}
)
},
// 导出窗体
exportConfirm(content?: string, tip?: string) {
return ElMessageBox.confirm(
content ? content : t('common.exportMessage'),
tip ? tip : t('common.confirmTitle'),
{
confirmButtonText: t('common.ok'),
cancelButtonText: t('common.cancel'),
type: 'warning'
}
)
},
// 提交内容
prompt(content: string, tip: string) {
return ElMessageBox.prompt(content, tip, {

View File

@ -13,6 +13,7 @@ interface UseVxeGridConfig<T = any> {
getListApi: (option: any) => Promise<T>
delListApi?: (option: any) => Promise<T>
exportListApi?: (option: any) => Promise<T>
exportName?: string
}
const appStore = useAppStore()
@ -88,10 +89,29 @@ export const useVxeGrid = <T = any>(config?: UseVxeGridConfig<T>) => {
return new Promise(async (resolve) => {
resolve(await config?.getListApi(queryParams))
})
},
queryAll: ({ form }) => {
const queryParams = Object.assign({}, JSON.parse(JSON.stringify(form)))
return new Promise(async (resolve) => {
if (config?.exportListApi) {
resolve(await config?.exportListApi(queryParams))
} else {
resolve(await config?.getListApi(queryParams))
}
})
}
}
},
exportConfig: {
filename: config?.exportName,
// 默认选中类型
type: 'csv',
// 自定义数据量列表
modes: ['current', 'all'],
columns: config?.allSchemas.printSchema
}
})
const delList = (ids: string | number | string[] | number[]) => {
return new Promise(async () => {
message.delConfirm().then(() => {

View File

@ -3,7 +3,7 @@ import { store } from '../index'
import { DictDataVO } from '@/api/system/dict/types'
export interface DictValueType {
value: string
value: string | number | boolean
label: string
clorType: string
cssClass: string

View File

@ -15,7 +15,7 @@ const dictStore = useDictStoreWithOut()
export interface DictDataType {
dictType: string
label: string
value: string | number
value: string | number | boolean
colorType: ElementPlusInfoType | '' | 'default' | 'primary'
cssClass: string
}
@ -34,10 +34,10 @@ export const getDictOptions = (dictType: string) => {
export const getIntDictOptions = (dictType: string) => {
const dictOptions: DictDataType[] = []
dictStore.getDictMap.forEach((dict: DictDataType) => {
if (dict.dictType + '' === dictType) {
if (dict.dictType.toString() === dictType) {
dictOptions.push({
...dict,
value: parseInt(dict.value + '')
value: dict.value
})
}
})

View File

@ -42,7 +42,6 @@
</template>
</vxe-toolbar>
<!-- 列表 -->
<!-- TODO 星语是不是也搞成 grid 会好点后续代码就统一走 grid 风格 -->
<vxe-table
show-overflow
keep-source
@ -84,14 +83,14 @@
preIcon="ep:edit"
:title="t('action.edit')"
v-hasPermi="['system:menu:update']"
@click="handleUpdate(row)"
@click="handleUpdate(row.id)"
/>
<!-- 操作删除 -->
<XTextButton
preIcon="ep:delete"
:title="t('action.del')"
v-hasPermi="['system:menu:delete']"
@click="handleDelete(row)"
@click="handleDelete(row.id)"
/>
</template>
</vxe-column>
@ -102,6 +101,7 @@
<template #default>
<!-- 对话框(添加 / 修改) -->
<el-form
ref="formRef"
:model="menuForm"
:rules="rules"
:inline="true"
@ -254,7 +254,6 @@
import { onMounted, reactive, ref } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
import { useMessage } from '@/hooks/web/useMessage'
// TODO @ 'element-plus' '@/components/Tooltip' '@/components/Icon'
import {
ElRow,
ElCol,
@ -266,14 +265,14 @@ import {
ElTreeSelect,
ElOption,
ElRadioGroup,
ElRadioButton
ElRadioButton,
FormInstance
} from 'element-plus'
import { Tooltip } from '@/components/Tooltip'
import { IconSelect } from '@/components/Icon'
import { VxeTableInstance } from 'vxe-table'
// import
import * as MenuApi from '@/api/system/menu'
import { MenuVO } from '@/api/system/menu/types'
import { required } from '@/utils/formRules.js'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants'
@ -291,7 +290,8 @@ const dialogTitle = ref('edit') // 弹出层标题
const actionType = ref('') //
const actionLoading = ref(false) //
//
const menuForm = ref<MenuVO>({
const formRef = ref<FormInstance>()
const menuForm = ref<MenuApi.MenuVO>({
id: 0,
name: '',
permission: '',
@ -316,19 +316,12 @@ const rules = reactive({
// ========== [] ==========
// []
// TODO @menuProps
const menuProps = {
checkStrictly: true,
children: 'children',
label: 'name',
value: 'id'
}
// TODO @Tree
interface Tree {
id: number
name: string
children?: Tree[] | any[]
}
const menuOptions = ref<any[]>([]) //
const getTree = async () => {
menuOptions.value = []
@ -339,9 +332,9 @@ const getTree = async () => {
}
// ========== ==========
const queryParams = reactive({
name: null,
status: null
const queryParams = reactive<MenuApi.MenuPageReqVO>({
name: undefined,
status: undefined
})
const getList = async () => {
tableLoading.value = true
@ -357,31 +350,47 @@ const handleQuery = async () => {
//
const resetQuery = async () => {
queryParams.name = null
queryParams.status = null
queryParams.name = undefined
queryParams.status = undefined
await getList()
}
// ========== / ==========
//
const setDialogTile = (type: string) => {
const setDialogTile = async (type: string) => {
await getTree()
dialogTitle.value = t('action.' + type)
actionType.value = type
dialogVisible.value = true
}
//
//
const handleCreate = () => {
setDialogTile('create')
// TODO @
formRef.value?.resetFields()
menuForm.value = {
id: 0,
name: '',
permission: '',
type: SystemMenuTypeEnum.DIR,
sort: 1,
parentId: 0,
path: '',
icon: '',
component: '',
status: CommonStatusEnum.ENABLE,
visible: true,
keepAlive: true,
createTime: ''
}
}
//
const handleUpdate = async (row: MenuVO) => {
const handleUpdate = async (rowId: number) => {
setDialogTile('update')
//
const res = await MenuApi.getMenuApi(row.id)
const res = await MenuApi.getMenuApi(rowId)
menuForm.value = res
}
@ -411,11 +420,11 @@ const submitForm = async () => {
await MenuApi.updateMenuApi(menuForm.value)
message.success(t('common.updateSuccess'))
}
//
dialogVisible.value = false
await getList()
} finally {
dialogVisible.value = false
actionLoading.value = false
//
await getList()
}
}
@ -426,9 +435,9 @@ const isExternal = (path: string) => {
// ========== ==========
//
const handleDelete = async (row: MenuVO) => {
message.confirm(t('common.delDataMessage'), t('common.confirmTitle')).then(async () => {
await MenuApi.deleteMenuApi(row.id)
const handleDelete = async (rowId: number) => {
message.delConfirm().then(async () => {
await MenuApi.deleteMenuApi(rowId)
message.success(t('common.delSuccess'))
await getList()
})
@ -437,7 +446,5 @@ const handleDelete = async (row: MenuVO) => {
// ========== ==========
onMounted(async () => {
await getList()
// TODO @
getTree()
})
</script>

View File

@ -21,7 +21,7 @@
preIcon="ep:view"
:title="t('action.detail')"
v-hasPermi="['system:notice:update']"
@click="handleDetail(row)"
@click="handleDetail(row.id)"
/>
<XTextButton
preIcon="ep:delete"
@ -36,10 +36,10 @@
<template #default>
<!-- 对话框(添加 / 修改) -->
<Form
ref="formRef"
v-if="['create', 'update'].includes(actionType)"
:schema="allSchemas.formSchema"
:rules="rules"
ref="formRef"
/>
<!-- 对话框(详情) -->
<Descriptions
@ -63,30 +63,31 @@
</template>
<script setup lang="ts">
import { ref, unref } from 'vue'
import * as NoticeApi from '@/api/system/notice'
import { NoticeVO } from '@/api/system/notice/types'
import { rules, allSchemas } from './notice.data'
import { useI18n } from '@/hooks/web/useI18n'
import { useMessage } from '@/hooks/web/useMessage'
import { useVxeGrid } from '@/hooks/web/useVxeGrid'
import { VxeGridInstance } from 'vxe-table'
import { FormExpose } from '@/components/Form'
import * as NoticeApi from '@/api/system/notice'
import { rules, allSchemas } from './notice.data'
const { t } = useI18n() //
const message = useMessage() //
const xGrid = ref<VxeGridInstance>() // grid Ref
const { gridOptions } = useVxeGrid<NoticeApi.NoticeVO>({
allSchemas: allSchemas,
getListApi: NoticeApi.getNoticePageApi
})
const dialogVisible = ref(false) //
const dialogTitle = ref('edit') //
const actionType = ref('') //
const actionLoading = ref(false) // Loading
const xGrid = ref<VxeGridInstance>() // grid Ref
const formRef = ref<FormExpose>() // Ref
const detailRef = ref() // Ref
const { gridOptions } = useVxeGrid<NoticeVO>({
allSchemas: allSchemas,
getListApi: NoticeApi.getNoticePageApi
})
//
const setDialogTile = (type: string) => {
dialogTitle.value = t('action.' + type)
@ -110,9 +111,11 @@ const handleUpdate = async (rowId: number) => {
}
//
const handleDetail = (row: NoticeVO) => {
const handleDetail = async (rowId: number) => {
setDialogTile('detail')
detailRef.value = row
//
const res = await NoticeApi.getNoticeApi(rowId)
detailRef.value = res
}
//
@ -137,7 +140,7 @@ const submitForm = async () => {
actionLoading.value = true
//
try {
const data = unref(formRef)?.formModel as NoticeVO
const data = unref(formRef)?.formModel as NoticeApi.NoticeVO
if (actionType.value === 'create') {
await NoticeApi.createNoticeApi(data)
message.success(t('common.createSuccess'))

View File

@ -25,8 +25,7 @@ const crudSchemas = reactive<VxeCrudSchema>({
{
title: '公告类型',
field: 'type',
dictType: DICT_TYPE.SYSTEM_NOTICE_TYPE,
isSearch: true
dictType: DICT_TYPE.SYSTEM_NOTICE_TYPE
},
{
title: t('common.status'),

View File

@ -11,6 +11,13 @@
v-hasPermi="['system:post:create']"
@click="handleCreate()"
/>
<XButton
type="primary"
preIcon="ep:download"
:title="t('action.export')"
v-hasPermi="['system:post:export']"
@click="handleExport()"
/>
</template>
<template #actionbtns_default="{ row }">
<!-- 操作修改 -->
@ -25,7 +32,7 @@
preIcon="ep:view"
:title="t('action.detail')"
v-hasPermi="['system:post:update']"
@click="handleDetail(row)"
@click="handleDetail(row.id)"
/>
<!-- 操作删除 -->
<XTextButton
@ -42,10 +49,10 @@
<template #default>
<!-- 表单添加/修改 -->
<Form
ref="formRef"
v-if="['create', 'update'].includes(actionType)"
:schema="allSchemas.formSchema"
:rules="rules"
ref="formRef"
/>
<!-- 表单详情 -->
<Descriptions
@ -78,14 +85,14 @@ import { VxeGridInstance } from 'vxe-table'
import { FormExpose } from '@/components/Form'
// import
import * as PostApi from '@/api/system/post'
import { PostVO } from '@/api/system/post/types'
import { rules, allSchemas } from './post.data'
import download from '@/utils/download'
const { t } = useI18n() //
const message = useMessage() //
//
const xGrid = ref<VxeGridInstance>() // Grid Ref
const { gridOptions } = useVxeGrid<PostVO>({
const { gridOptions } = useVxeGrid<PostApi.PostVO>({
allSchemas: allSchemas,
getListApi: PostApi.getPostPageApi
})
@ -111,6 +118,16 @@ const handleCreate = () => {
unref(formRef)?.getElFormRef()?.resetFields()
}
//
const handleExport = async () => {
const queryParams = Object.assign(
{},
JSON.parse(JSON.stringify(xGrid.value?.getRefMaps().refForm.value.data))
)
const res = await PostApi.exportPostApi(queryParams)
download.excel(res, '岗位列表.xls')
}
//
const handleUpdate = async (rowId: number) => {
setDialogTile('update')
@ -120,10 +137,10 @@ const handleUpdate = async (rowId: number) => {
}
//
const handleDetail = (row: PostVO) => {
const handleDetail = async (rowId: number) => {
setDialogTile('detail')
// TODO @
detailRef.value = row
const res = await PostApi.getPostApi(rowId)
detailRef.value = res
}
//
@ -144,13 +161,12 @@ const handleDelete = async (rowId: number) => {
const submitForm = async () => {
const elForm = unref(formRef)?.getElFormRef()
if (!elForm) return
// TODO @
elForm.validate(async (valid) => {
if (valid) {
actionLoading.value = true
//
try {
const data = unref(formRef)?.formModel as PostVO
const data = unref(formRef)?.formModel as PostApi.PostVO
if (actionType.value === 'create') {
await PostApi.createPostApi(data)
message.success(t('common.createSuccess'))

View File

@ -36,4 +36,14 @@ declare global {
code: string
data: T extends any ? T : T & any
}
declare interface BasePage {
pageSize?: number
pageNo?: number
}
declare interface Tree {
id: number
name: string
children?: Tree[] | any[]
}
}