Merge branch 'dev' of gitee.com:yudaocode/yudao-ui-admin-vue3 into dev

Signed-off-by: 凌太虚 <343015202@qq.com>
This commit is contained in:
凌太虚 2023-03-22 14:26:18 +00:00 committed by Gitee
commit 8f49426cc3
45 changed files with 2561 additions and 1654 deletions

View File

@ -11,7 +11,7 @@ export type UserGroupVO = {
}
// 创建用户组
export const createUserGroupApi = async (data: UserGroupVO) => {
export const createUserGroup = async (data: UserGroupVO) => {
return await request.post({
url: '/bpm/user-group/create',
data: data
@ -19,7 +19,7 @@ export const createUserGroupApi = async (data: UserGroupVO) => {
}
// 更新用户组
export const updateUserGroupApi = async (data: UserGroupVO) => {
export const updateUserGroup = async (data: UserGroupVO) => {
return await request.put({
url: '/bpm/user-group/update',
data: data
@ -27,21 +27,21 @@ export const updateUserGroupApi = async (data: UserGroupVO) => {
}
// 删除用户组
export const deleteUserGroupApi = async (id: number) => {
export const deleteUserGroup = async (id: number) => {
return await request.delete({ url: '/bpm/user-group/delete?id=' + id })
}
// 获得用户组
export const getUserGroupApi = async (id: number) => {
export const getUserGroup = async (id: number) => {
return await request.get({ url: '/bpm/user-group/get?id=' + id })
}
// 获得用户组分页
export const getUserGroupPageApi = async (params) => {
export const getUserGroupPage = async (params) => {
return await request.get({ url: '/bpm/user-group/page', params })
}
// 获取用户组精简信息列表
export const listSimpleUserGroupsApi = async () => {
export const listSimpleUserGroup = async () => {
return await request.get({ url: '/bpm/user-group/list-all-simple' })
}

View File

@ -46,7 +46,7 @@ export interface ApiErrorLogExportReqVO {
}
// 查询列表API 访问日志
export const getApiErrorLogPageApi = (params: ApiErrorLogPageReqVO) => {
export const getApiErrorLogPageApi = (params: PageParam) => {
return request.get({ url: '/infra/api-error-log/page', params })
}
@ -58,7 +58,7 @@ export const updateApiErrorLogPageApi = (id: number, processStatus: number) => {
}
// 导出API 访问日志
export const exportApiErrorLogApi = (params: ApiErrorLogExportReqVO) => {
export const exportApiErrorLogApi = (params) => {
return request.download({
url: '/infra/api-error-log/export-excel',
params

View File

@ -1,36 +1,49 @@
import request from '@/config/axios'
import type { DictDataVO, DictDataPageReqVO, DictDataExportReqVO } from './types'
export type DictDataVO = {
id: number | undefined
sort: number | undefined
label: string
value: string
dictType: string
status: number
colorType: string
cssClass: string
remark: string
createTime: Date
}
// 查询字典数据(精简)列表
export const listSimpleDictDataApi = () => {
export const listSimpleDictData = () => {
return request.get({ url: '/system/dict-data/list-all-simple' })
}
// 查询字典数据列表
export const getDictDataPageApi = (params: DictDataPageReqVO) => {
export const getDictDataPage = (params: PageParam) => {
return request.get({ url: '/system/dict-data/page', params })
}
// 查询字典数据详情
export const getDictDataApi = (id: number) => {
export const getDictData = (id: number) => {
return request.get({ url: '/system/dict-data/get?id=' + id })
}
// 新增字典数据
export const createDictDataApi = (data: DictDataVO) => {
export const createDictData = (data: DictDataVO) => {
return request.post({ url: '/system/dict-data/create', data })
}
// 修改字典数据
export const updateDictDataApi = (data: DictDataVO) => {
export const updateDictData = (data: DictDataVO) => {
return request.put({ url: '/system/dict-data/update', data })
}
// 删除字典数据
export const deleteDictDataApi = (id: number) => {
export const deleteDictData = (id: number) => {
return request.delete({ url: '/system/dict-data/delete?id=' + id })
}
// 导出字典类型数据
export const exportDictDataApi = (params: DictDataExportReqVO) => {
export const exportDictDataApi = (params) => {
return request.get({ url: '/system/dict-data/export', params })
}

View File

@ -1,36 +1,44 @@
import request from '@/config/axios'
import type { DictTypeVO, DictTypePageReqVO, DictTypeExportReqVO } from './types'
export type DictTypeVO = {
id: number | undefined
name: string
type: string
status: number
remark: string
createTime: Date
}
// 查询字典(精简)列表
export const listSimpleDictTypeApi = () => {
export const listSimpleDictType = () => {
return request.get({ url: '/system/dict-type/list-all-simple' })
}
// 查询字典列表
export const getDictTypePageApi = (params: DictTypePageReqVO) => {
export const getDictTypePage = (params: PageParam) => {
return request.get({ url: '/system/dict-type/page', params })
}
// 查询字典详情
export const getDictTypeApi = (id: number) => {
export const getDictType = (id: number) => {
return request.get({ url: '/system/dict-type/get?id=' + id })
}
// 新增字典
export const createDictTypeApi = (data: DictTypeVO) => {
export const createDictType = (data: DictTypeVO) => {
return request.post({ url: '/system/dict-type/create', data })
}
// 修改字典
export const updateDictTypeApi = (data: DictTypeVO) => {
export const updateDictType = (data: DictTypeVO) => {
return request.put({ url: '/system/dict-type/update', data })
}
// 删除字典
export const deleteDictTypeApi = (id: number) => {
export const deleteDictType = (id: number) => {
return request.delete({ url: '/system/dict-type/delete?id=' + id })
}
// 导出字典类型
export const exportDictTypeApi = (params: DictTypeExportReqVO) => {
export const exportDictType = (params) => {
return request.get({ url: '/system/dict-type/export', params })
}

View File

@ -1,46 +0,0 @@
export type DictTypeVO = {
id: number
name: string
type: string
status: number
remark: string
createTime: Date
}
export type DictTypePageReqVO = {
name: string
type: string
status: number
createTime: Date[]
}
export type DictTypeExportReqVO = {
name: string
type: string
status: number
createTime: Date[]
}
export type DictDataVO = {
id: number
sort: number
label: string
value: string
dictType: string
status: number
colorType: string
cssClass: string
remark: string
createTime: Date
}
export type DictDataPageReqVO = {
label: string
dictType: string
status: number
}
export type DictDataExportReqVO = {
label: string
dictType: string
status: number
}

View File

@ -1,10 +1,10 @@
import request from '@/config/axios'
export interface ErrorCodeVO {
id: number
id: number | undefined
type: number
applicationName: string
code: number
code: number | undefined
message: string
memo: string
createTime: Date

View File

@ -11,18 +11,12 @@ export interface OAuth2TokenVO {
expiresTime: Date
}
export interface OAuth2TokenPageReqVO extends PageParam {
userId?: number
userType?: number
clientId?: string
}
// 查询 token列表
export const getAccessTokenPageApi = (params: OAuth2TokenPageReqVO) => {
export const getAccessTokenPage = (params: PageParam) => {
return request.get({ url: '/system/oauth2-token/page', params })
}
// 删除 token
export const deleteAccessTokenApi = (accessToken: number) => {
export const deleteAccessToken = (accessToken: number) => {
return request.delete({ url: '/system/oauth2-token/delete?accessToken=' + accessToken })
}

View File

@ -10,49 +10,37 @@ export interface PostVO {
createTime?: Date
}
export interface PostPageReqVO extends PageParam {
code?: string
name?: string
status?: number
}
export interface PostExportReqVO {
code?: string
name?: string
status?: number
}
// 查询岗位列表
export const getPostPageApi = async (params: PostPageReqVO) => {
export const getPostPage = async (params: PageParam) => {
return await request.get({ url: '/system/post/page', params })
}
// 获取岗位精简信息列表
export const listSimplePostsApi = async () => {
export const getSimplePostList = async () => {
return await request.get({ url: '/system/post/list-all-simple' })
}
// 查询岗位详情
export const getPostApi = async (id: number) => {
export const getPost = async (id: number) => {
return await request.get({ url: '/system/post/get?id=' + id })
}
// 新增岗位
export const createPostApi = async (data: PostVO) => {
export const createPost = async (data: PostVO) => {
return await request.post({ url: '/system/post/create', data })
}
// 修改岗位
export const updatePostApi = async (data: PostVO) => {
export const updatePost = async (data: PostVO) => {
return await request.put({ url: '/system/post/update', data })
}
// 删除岗位
export const deletePostApi = async (id: number) => {
export const deletePost = async (id: number) => {
return await request.delete({ url: '/system/post/delete?id=' + id })
}
// 导出岗位
export const exportPostApi = async (params: PostExportReqVO) => {
export const exportPost = async (params) => {
return await request.download({ url: '/system/post/export', params })
}

View File

@ -86,6 +86,6 @@ export const updateUserStatusApi = (id: number, status: number) => {
}
// 获取用户精简信息列表
export const getListSimpleUsersApi = () => {
export const getSimpleUserList = () => {
return request.get({ url: '/system/user/list-all-simple' })
}

View File

@ -104,6 +104,31 @@ const remainingRouter: AppRouteRecordRaw[] = [
}
]
},
{
path: '/dict',
component: Layout,
name: 'dict',
meta: {
hidden: true
},
children: [
{
path: 'type/data/:dictType',
component: () => import('@/views/system/dict/data.vue'),
name: 'data',
meta: {
title: '字典数据',
noCache: true,
hidden: true,
canTo: true,
icon: '',
activeMenu: 'system/dict/data'
}
}
]
},
{
path: '/codegen',
component: Layout,

View File

@ -3,7 +3,7 @@ import { store } from '../index'
import { DictDataVO } from '@/api/system/dict/types'
import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
const { wsCache } = useCache('sessionStorage')
import { listSimpleDictDataApi } from '@/api/system/dict/dict.data'
import { listSimpleDictData } from '@/api/system/dict/dict.data'
export interface DictValueType {
value: any
@ -44,7 +44,7 @@ export const useDictStore = defineStore('dict', {
this.dictMap = dictMap
this.isSetDict = true
} else {
const res = await listSimpleDictDataApi()
const res = await listSimpleDictData()
// 设置数据
const dictDataMap = new Map<string, any>()
res.forEach((dictData: DictDataVO) => {
@ -74,7 +74,7 @@ export const useDictStore = defineStore('dict', {
},
async resetDict() {
wsCache.delete(CACHE_KEY.DICT_CACHE)
const res = await listSimpleDictDataApi()
const res = await listSimpleDictData()
// 设置数据
const dictDataMap = new Map<string, any>()
res.forEach((dictData: DictDataVO) => {

View File

@ -30,6 +30,7 @@ declare module '@vue/runtime-core' {
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
ElCard: typeof import('element-plus/es')['ElCard']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
ElCol: typeof import('element-plus/es')['ElCol']
ElCollapse: typeof import('element-plus/es')['ElCollapse']
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']

View File

@ -0,0 +1,132 @@
<template>
<Dialog :title="modelTitle" v-model="modelVisible">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
<el-form-item label="组名" prop="name">
<el-input v-model="formData.name" placeholder="请输入组名" />
</el-form-item>
<el-form-item label="描述">
<el-input type="textarea" v-model="formData.name" placeholder="请输入描述" />
</el-form-item>
<el-form-item label="成员" prop="memberUserIds">
<el-select v-model="formData.memberUserIds" multiple placeholder="请选择成员">
<el-option
v-for="user in userList"
:key="user.id"
:label="user.nickname"
:value="user.id"
/>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="formData.status">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="modelVisible = false"> </el-button>
</div>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { CommonStatusEnum } from '@/utils/constants'
import * as UserGroupApi from '@/api/bpm/userGroup'
import * as UserApi from '@/api/system/user'
const { t } = useI18n() //
const message = useMessage() //
const modelVisible = ref(false) //
const modelTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
name: undefined,
description: undefined,
memberUserIds: undefined,
status: CommonStatusEnum.ENABLE
})
const formRules = reactive({
name: [{ required: true, message: '组名不能为空', trigger: 'blur' }],
description: [{ required: true, message: '描述不能为空', trigger: 'blur' }],
memberUserIds: [{ required: true, message: '成员不能为空', trigger: 'blur' }],
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
const userList = ref([]) //
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
modelVisible.value = true
modelTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
formData.value = await UserGroupApi.getUserGroup(id)
} finally {
formLoading.value = false
}
}
//
userList.value = await UserApi.getSimpleUserList()
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
if (!formRef) return
const valid = await formRef.value.validate()
if (!valid) return
//
formLoading.value = true
try {
const data = formData.value as unknown as UserGroupApi.UserGroupVO
if (formType.value === 'create') {
await UserGroupApi.createUserGroup(data)
message.success(t('common.createSuccess'))
} else {
await UserGroupApi.updateUserGroup(data)
message.success(t('common.updateSuccess'))
}
modelVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
name: undefined,
description: undefined,
memberUserIds: undefined,
status: CommonStatusEnum.ENABLE
}
formRef.value?.resetFields()
}
</script>

View File

@ -1,64 +0,0 @@
import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
const { t } = useI18n() // 国际化
// 表单校验
export const rules = reactive({
name: [required],
description: [required],
memberUserIds: [required],
status: [required]
})
// CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id',
primaryType: 'id',
primaryTitle: '编号',
action: true,
searchSpan: 8,
columns: [
{
title: '组名',
field: 'name',
isSearch: true
},
{
title: '成员',
field: 'memberUserIds',
table: {
slots: {
default: 'memberUserIds_default'
}
}
},
{
title: '描述',
field: 'description'
},
{
title: t('common.status'),
field: 'status',
dictType: DICT_TYPE.COMMON_STATUS,
dictClass: 'number',
isSearch: true
},
{
title: t('common.createTime'),
field: 'createTime',
formatter: 'formatDate',
isForm: false,
isSearch: true,
search: {
show: true,
itemRender: {
name: 'XDataTimePicker'
}
},
table: {
width: 180
}
}
]
})
export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

View File

@ -1,182 +1,184 @@
<template>
<ContentWrap>
<!-- 列表 -->
<XTable @register="registerTable">
<template #toolbar_buttons>
<!-- 操作新增 -->
<XButton
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="组名" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入组名"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable class="!w-240px">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
value-format="yyyy-MM-dd HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button
type="primary"
preIcon="ep:zoom-in"
:title="t('action.add')"
@click="openForm('create')"
v-hasPermi="['bpm:user-group:create']"
@click="handleCreate()"
/>
</template>
<template #memberUserIds_default="{ row }">
<span v-for="userId in row.memberUserIds" :key="userId">
{{ getUserNickname(userId) }} &nbsp;
</span>
</template>
<template #actionbtns_default="{ row }">
<!-- 操作修改 -->
<XTextButton
preIcon="ep:edit"
:title="t('action.edit')"
v-hasPermi="['bpm:user-group:update']"
@click="handleUpdate(row.id)"
/>
<!-- 操作详情 -->
<XTextButton
preIcon="ep:view"
:title="t('action.detail')"
v-hasPermi="['bpm:user-group:query']"
@click="handleDetail(row.id)"
/>
<!-- 操作删除 -->
<XTextButton
preIcon="ep:delete"
:title="t('action.del')"
v-hasPermi="['bpm:user-group:delete']"
@click="deleteData(row.id)"
/>
</template>
</XTable>
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<XModal v-model="dialogVisible" :title="dialogTitle" :mask-closable="false">
<!-- 对话框(添加 / 修改) -->
<Form
v-if="['create', 'update'].includes(actionType)"
:schema="allSchemas.formSchema"
:rules="rules"
ref="formRef"
>
<template #memberUserIds="form">
<el-select v-model="form.memberUserIds" multiple>
<el-option v-for="item in users" :key="item.id" :label="item.nickname" :value="item.id" />
</el-select>
</template>
</Form>
<!-- 对话框(详情) -->
<Descriptions
v-if="actionType === 'detail'"
:schema="allSchemas.detailSchema"
:data="detailData"
>
<template #memberUserIds="{ row }">
<span v-for="userId in row.memberUserIds" :key="userId">
{{ getUserNickname(userId) }} &nbsp;
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list">
<el-table-column label="编号" align="center" prop="id" />
<el-table-column label="组名" align="center" prop="name" />
<el-table-column label="描述" align="center" prop="description" />
<el-table-column label="成员" align="center">
<template #default="scope">
<span v-for="userId in scope.row.memberUserIds" :key="userId" class="pr-5px">
{{ userList.find((user) => user.id === userId)?.nickname }}
</span>
</template>
</Descriptions>
<!-- 操作按钮 -->
<template #footer>
<!-- 按钮保存 -->
<XButton
v-if="['create', 'update'].includes(actionType)"
type="primary"
:title="t('action.save')"
:loading="actionLoading"
@click="submitForm"
/>
<!-- 按钮关闭 -->
<XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
</el-table-column>
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
</XModal>
</el-table-column>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
/>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['bpm:user-group:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['bpm:user-group:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<UserGroupForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
// import
<script setup lang="ts" name="UserGroup">
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import * as UserGroupApi from '@/api/bpm/userGroup'
import { getListSimpleUsersApi, UserVO } from '@/api/system/user'
import { allSchemas, rules } from './group.data'
import { FormExpose } from '@/components/Form'
const { t } = useI18n() //
import * as UserApi from '@/api/system/user'
import UserGroupForm from './UserGroupForm.vue'
const message = useMessage() //
//
const [registerTable, { reload, deleteData }] = useXTable({
allSchemas: allSchemas,
getListApi: UserGroupApi.getUserGroupPageApi,
deleteApi: UserGroupApi.deleteUserGroupApi
const { t } = useI18n() //
const loading = ref(true) //
const total = ref(0) //
const list = ref([]) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
name: null,
status: null,
createTime: []
})
//
const users = ref<UserVO[]>([])
const queryFormRef = ref() //
const userList = ref([]) //
const getUserNickname = (userId) => {
for (const user of users.value) {
if (user.id === userId) {
return user.nickname
}
}
return '未知(' + userId + ')'
}
// ========== CRUD ==========
const actionLoading = ref(false) //
const actionType = ref('') //
const dialogVisible = ref(false) //
const dialogTitle = ref('edit') //
const formRef = ref<FormExpose>() // Ref
const detailData = ref() // Ref
//
const setDialogTile = (type: string) => {
dialogTitle.value = t('action.' + type)
actionType.value = type
dialogVisible.value = true
}
//
const handleCreate = () => {
setDialogTile('create')
}
//
const handleUpdate = async (rowId: number) => {
setDialogTile('update')
//
const res = await UserGroupApi.getUserGroupApi(rowId)
unref(formRef)?.setValues(res)
}
//
const handleDetail = async (rowId: number) => {
setDialogTile('detail')
detailData.value = await UserGroupApi.getUserGroupApi(rowId)
}
//
const submitForm = async () => {
const elForm = unref(formRef)?.getElFormRef()
if (!elForm) return
elForm.validate(async (valid) => {
if (valid) {
actionLoading.value = true
//
/** 查询参数列表 */
const getList = async () => {
loading.value = true
try {
const data = unref(formRef)?.formModel as UserGroupApi.UserGroupVO
if (actionType.value === 'create') {
await UserGroupApi.createUserGroupApi(data)
message.success(t('common.createSuccess'))
} else {
await UserGroupApi.updateUserGroupApi(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
const data = await UserGroupApi.getUserGroupPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
actionLoading.value = false
//
await reload()
loading.value = false
}
}
})
}
// ========== ==========
onMounted(() => {
getListSimpleUsersApi().then((data) => {
users.value = data
})
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await UserGroupApi.deleteUserGroup(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 初始化 **/
onMounted(async () => {
await getList()
//
userList.value = await UserApi.getSimpleUserList()
})
</script>

View File

@ -378,7 +378,7 @@ onMounted(() => {
//
getDetail()
//
UserApi.getListSimpleUsersApi().then((data) => {
UserApi.getSimpleUserList().then((data) => {
userOptions.value.push(...data)
})
})

View File

@ -139,9 +139,9 @@ import { FormInstance } from 'element-plus'
// import
import * as TaskAssignRuleApi from '@/api/bpm/taskAssignRule'
import { listSimpleRolesApi } from '@/api/system/role'
import { listSimplePostsApi } from '@/api/system/post'
import { getListSimpleUsersApi } from '@/api/system/user'
import { listSimpleUserGroupsApi } from '@/api/bpm/userGroup'
import { getSimplePostList } from '@/api/system/post'
import { getSimpleUserList } from '@/api/system/user'
import { listSimpleUserGroup } from '@/api/bpm/userGroup'
import { listSimpleDeptApi } from '@/api/system/dept'
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
import { handleTree, defaultProps } from '@/utils/tree'
@ -336,17 +336,17 @@ onMounted(() => {
})
//
postOptions.value = []
listSimplePostsApi().then((data) => {
getSimplePostList().then((data) => {
postOptions.value.push(...data)
})
//
userOptions.value = []
getListSimpleUsersApi().then((data) => {
getSimpleUserList().then((data) => {
userOptions.value.push(...data)
})
//
userGroupOptions.value = []
listSimpleUserGroupsApi().then((data) => {
listSimpleUserGroup().then((data) => {
userGroupOptions.value.push(...data)
})
if (!isShow) {

View File

@ -1,76 +0,0 @@
import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
// CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id',
primaryType: 'id',
primaryTitle: '日志编号',
action: true,
actionWidth: '300',
columns: [
{
title: '链路追踪',
field: 'traceId',
isTable: false
},
{
title: '用户编号',
field: 'userId',
isSearch: true
},
{
title: '用户类型',
field: 'userType',
dictType: DICT_TYPE.USER_TYPE,
isSearch: true
},
{
title: '应用名',
field: 'applicationName',
isSearch: true
},
{
title: '请求方法名',
field: 'requestMethod'
},
{
title: '请求地址',
field: 'requestUrl',
isSearch: true
},
{
title: '异常发生时间',
field: 'exceptionTime',
formatter: 'formatDate',
search: {
show: true,
itemRender: {
name: 'XDataTimePicker'
}
}
},
{
title: '异常名',
field: 'exceptionName'
},
{
title: '处理状态',
field: 'processStatus',
dictType: DICT_TYPE.INFRA_API_ERROR_LOG_PROCESS_STATUS,
dictClass: 'number',
isSearch: true
},
{
title: '处理人',
field: 'processUserId',
isTable: false
},
{
title: '处理时间',
field: 'processTime',
formatter: 'formatDate',
isTable: false
}
]
})
export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

View File

@ -0,0 +1,76 @@
<template>
<Dialog title="详情" v-model="modelVisible" :scroll="true" :max-height="500" width="800">
<el-descriptions border :column="1">
<el-descriptions-item label="日志主键" min-width="120">
{{ detailData.id }}
</el-descriptions-item>
<el-descriptions-item label="链路追踪">
{{ detailData.traceId }}
</el-descriptions-item>
<el-descriptions-item label="应用名">
{{ detailData.applicationName }}
</el-descriptions-item>
<el-descriptions-item label="用户信息">
{{ detailData.userId }} |
<dict-tag :type="DICT_TYPE.USER_TYPE" :value="detailData.userType" />
| {{ detailData.userIp }} | {{ detailData.userAgent }}
</el-descriptions-item>
<el-descriptions-item label="请求信息">
{{ detailData.requestMethod }} | {{ detailData.requestUrl }}
</el-descriptions-item>
<el-descriptions-item label="请求参数">
{{ detailData.requestParams }}
</el-descriptions-item>
<el-descriptions-item label="异常时间">
{{ formatDate(detailData.exceptionTime, 'YYYY-MM-DD HH:mm:ss') }}
</el-descriptions-item>
<el-descriptions-item label="异常名">
{{ detailData.exceptionName }}
</el-descriptions-item>
<el-descriptions-item label="异常名" v-if="detailData.exceptionStackTrace">
<el-input
type="textarea"
:readonly="true"
:autosize="{ maxRows: 20 }"
v-model="detailData.exceptionStackTrace"
/>
</el-descriptions-item>
<el-descriptions-item label="处理状态">
<dict-tag
:type="DICT_TYPE.INFRA_API_ERROR_LOG_PROCESS_STATUS"
:value="detailData.processStatus"
/>
</el-descriptions-item>
<el-descriptions-item label="处理人" v-if="detailData.processUserId">
{{ detailData.processUserId }}
</el-descriptions-item>
<el-descriptions-item label="处理时间" v-if="detailData.processTime">
{{ formatDate(detailData.processTime, 'YYYY-MM-DD HH:mm:ss') }}
</el-descriptions-item>
</el-descriptions>
</Dialog>
</template>
<script setup lang="ts">
import { DICT_TYPE } from '@/utils/dict'
import { formatDate } from '@/utils/formatTime'
import * as ApiErrorLog from '@/api/infra/apiErrorLog'
const modelVisible = ref(false) //
const detailLoading = ref(false) //
const detailData = ref() //
/** 打开弹窗 */
const openModal = async (data: ApiErrorLog.ApiErrorLogVO) => {
modelVisible.value = true
//
detailLoading.value = true
try {
detailData.value = data
} finally {
detailLoading.value = false
}
}
defineExpose({ openModal }) // openModal
</script>

View File

@ -1,99 +1,242 @@
<template>
<ContentWrap>
<content-wrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="用户编号" prop="userId">
<el-input
v-model="queryParams.userId"
placeholder="请输入用户编号"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="用户类型" prop="userType">
<el-select
v-model="queryParams.userType"
placeholder="请选择用户类型"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getDictOptions(DICT_TYPE.USER_TYPE)"
:key="parseInt(dict.value)"
:label="dict.label"
:value="parseInt(dict.value)"
/>
</el-select>
</el-form-item>
<el-form-item label="应用名" prop="applicationName">
<el-input
v-model="queryParams.applicationName"
placeholder="请输入应用名"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="异常时间" prop="exceptionTime">
<el-date-picker
v-model="queryParams.exceptionTime"
value-format="yyyy-MM-dd HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="处理状态" prop="processStatus">
<el-select v-model="queryParams.processStatus" placeholder="请选择处理状态" clearable>
<el-option
v-for="dict in getDictOptions(DICT_TYPE.INFRA_API_ERROR_LOG_PROCESS_STATUS)"
:key="parseInt(dict.value)"
:label="dict.label"
:value="parseInt(dict.value)"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['infra:api-error-log:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</content-wrap>
<!-- 列表 -->
<XTable @register="registerTable">
<!-- 操作导出 -->
<template #toolbar_buttons>
<XButton
type="warning"
preIcon="ep:download"
:title="t('action.export')"
@click="exportList('错误数据.xls')"
<content-wrap>
<el-table v-loading="loading" :data="list">
<el-table-column label="日志编号" align="center" prop="id" />
<el-table-column label="用户编号" align="center" prop="userId" />
<el-table-column label="用户类型" align="center" prop="userType">
<template #default="scope">
<dict-tag :type="DICT_TYPE.USER_TYPE" :value="scope.row.userType" />
</template>
</el-table-column>
<el-table-column label="应用名" align="center" prop="applicationName" />
<el-table-column label="请求方法名" align="center" prop="requestMethod" />
<el-table-column label="请求地址" align="center" prop="requestUrl" width="250" />
<el-table-column label="异常发生时间" align="center" prop="exceptionTime" width="180">
<template #default="scope">
<span>{{ scope.row.exceptionTime }}</span>
</template>
</el-table-column>
<el-table-column label="异常名" align="center" prop="exceptionName" width="250" />
<el-table-column label="处理状态" align="center" prop="processStatus">
<template #default="scope">
<dict-tag
:type="DICT_TYPE.INFRA_API_ERROR_LOG_PROCESS_STATUS"
:value="scope.row.processStatus"
/>
</template>
<template #duration_default="{ row }">
<span>{{ row.duration + 'ms' }}</span>
</template>
<template #resultCode_default="{ row }">
<span>{{ row.resultCode === 0 ? '成功' : '失败(' + row.resultMsg + ')' }}</span>
</template>
<template #actionbtns_default="{ row }">
<!-- 操作详情 -->
<XTextButton
preIcon="ep:view"
:title="t('action.detail')"
</el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openModal(scope.row)"
v-hasPermi="['infra:api-access-log:query']"
@click="handleDetail(row)"
/>
<XTextButton
preIcon="ep:cpu"
title="已处理"
v-if="row.processStatus === InfraApiErrorLogProcessStatusEnum.INIT"
>
详细
</el-button>
<el-button
link
type="primary"
v-if="scope.row.processStatus === InfraApiErrorLogProcessStatusEnum.INIT"
@click="
handleProcessClick(InfraApiErrorLogProcessStatusEnum.DONE, '已处理', scope.row.id)
"
v-hasPermi="['infra:api-error-log:update-status']"
@click="handleProcessClick(row, InfraApiErrorLogProcessStatusEnum.DONE, '已处理')"
/>
<XTextButton
preIcon="ep:mute-notification"
title="已忽略"
v-if="row.processStatus === InfraApiErrorLogProcessStatusEnum.INIT"
>
已处理
</el-button>
<el-button
link
type="primary"
icon="el-icon-check"
v-if="scope.row.processStatus === InfraApiErrorLogProcessStatusEnum.INIT"
@click="
handleProcessClick(InfraApiErrorLogProcessStatusEnum.IGNORE, '已忽略', scope.row.id)
"
v-hasPermi="['infra:api-error-log:update-status']"
@click="handleProcessClick(row, InfraApiErrorLogProcessStatusEnum.IGNORE, '已忽略')"
>
已忽略
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</template>
</XTable>
</ContentWrap>
<XModal v-model="dialogVisible" :title="dialogTitle">
<!-- 对话框(详情) -->
<Descriptions :schema="allSchemas.detailSchema" :data="detailData" />
<!-- 操作按钮 -->
<template #footer>
<XButton :title="t('dialog.close')" @click="dialogVisible = false" />
</template>
</XModal>
</content-wrap>
<!-- 表单弹窗详情 -->
<api-error-log-detail ref="modalRef" />
</template>
<script setup lang="ts" name="ApiErrorLog">
import { allSchemas } from './apiErrorLog.data'
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
import download from '@/utils/download'
import * as ApiErrorLogApi from '@/api/infra/apiErrorLog'
import ApiErrorLogDetail from './detail.vue'
import { InfraApiErrorLogProcessStatusEnum } from '@/utils/constants'
const message = useMessage() //
const { t } = useI18n() //
const message = useMessage()
// ========== ==========
const [registerTable, { reload, exportList }] = useXTable({
allSchemas: allSchemas,
getListApi: ApiErrorLogApi.getApiErrorLogPageApi,
exportListApi: ApiErrorLogApi.exportApiErrorLogApi
const loading = ref(true) //
const total = ref(0) //
const list = ref([]) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
userId: null,
userType: null,
applicationName: null,
requestUrl: null,
processStatus: null,
exceptionTime: []
})
// ========== ==========
const detailData = ref() // Ref
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const queryFormRef = ref() //
const exportLoading = ref(false) //
//
const handleDetail = (row: ApiErrorLogApi.ApiErrorLogVO) => {
//
detailData.value = row
dialogTitle.value = t('action.detail')
dialogVisible.value = true
/** 查询参数列表 */
const getList = async () => {
loading.value = true
try {
const data = await ApiErrorLogApi.getApiErrorLogPageApi(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
//
const handleProcessClick = (
row: ApiErrorLogApi.ApiErrorLogVO,
processSttatus: number,
type: string
) => {
message
.confirm('确认标记为' + type + '?', t('common.reminder'))
.then(async () => {
await ApiErrorLogApi.updateApiErrorLogPageApi(row.id, processSttatus)
message.success(t('common.updateSuccess'))
})
.finally(async () => {
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 详情操作 */
const modalRef = ref()
const openModal = (data: ApiErrorLogApi.ApiErrorLogVO) => {
modalRef.value.openModal(data)
}
/** 处理已处理 / 已忽略的操作 **/
const handleProcessClick = async (processStatus: number, type: string, id: number) => {
try {
//
await message.confirm('确认标记为' + type + '?')
//
await ApiErrorLogApi.updateApiErrorLogPageApi(id, processStatus)
await message.success(type)
//
await reload()
})
.catch(() => {})
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await ApiErrorLogApi.exportApiErrorLogApi(queryParams)
download.excel(data, '操作日志.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -114,7 +114,7 @@
import { PropType } from 'vue'
import { DictTypeVO } from '@/api/system/dict/types'
import { CodegenColumnVO } from '@/api/infra/codegen/types'
import { listSimpleDictTypeApi } from '@/api/system/dict/dict.type'
import { listSimpleDictType } from '@/api/system/dict/dict.type'
const props = defineProps({
info: {
@ -125,7 +125,7 @@ const props = defineProps({
/** 查询字典下拉列表 */
const dictOptions = ref<DictTypeVO[]>()
const getDictOptions = async () => {
const res = await listSimpleDictTypeApi()
const res = await listSimpleDictType()
dictOptions.value = res
}
onMounted(async () => {

View File

@ -1,13 +1,20 @@
<template>
<!-- 搜索 -->
<content-wrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true">
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="参数名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入参数名称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="参数键名" prop="key">
@ -16,10 +23,16 @@
placeholder="请输入参数键名"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="系统内置" prop="type">
<el-select v-model="queryParams.type" placeholder="请选择系统内置" clearable>
<el-select
v-model="queryParams.type"
placeholder="请选择系统内置"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getDictOptions(DICT_TYPE.INFRA_CONFIG_TYPE)"
:key="parseInt(dict.value)"
@ -36,6 +49,7 @@
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item>

View File

@ -90,10 +90,10 @@
<script setup lang="ts" name="Dept">
import { handleTree } from '@/utils/tree'
import * as DeptApi from '@/api/system/dept'
import { getListSimpleUsersApi, UserVO } from '@/api/system/user'
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
import DeptForm from './form.vue'
import { dateFormatter } from '@/utils/formatTime'
import { getSimpleUserList, UserVO } from '@/api/system/user'
const message = useMessage() //
const { t } = useI18n() //
//
@ -115,7 +115,7 @@ const loading = ref(true) // 列表的加载中
//
const getUserList = async () => {
const res = await getListSimpleUsersApi()
const res = await getSimpleUserList()
userOption.value = res
}

View File

@ -0,0 +1,177 @@
<template>
<Dialog :title="modelTitle" v-model="modelVisible">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="80px"
v-loading="formLoading"
>
<el-form-item label="字典类型" prop="type">
<el-input
:disabled="typeof formData.id !== 'undefined'"
v-model="formData.dictType"
placeholder="请输入参数名称"
/>
</el-form-item>
<el-form-item label="数据标签" prop="label">
<el-input v-model="formData.label" placeholder="请输入数据标签" />
</el-form-item>
<el-form-item label="数据键值" prop="value">
<el-input v-model="formData.value" placeholder="请输入数据键值" />
</el-form-item>
<el-form-item label="显示排序" prop="sort">
<el-input-number v-model="formData.sort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="formData.status">
<el-radio
v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="parseInt(dict.value)"
:label="parseInt(dict.value)"
>{{ dict.label }}</el-radio
>
</el-radio-group>
</el-form-item>
<el-form-item label="颜色类型" prop="colorType">
<el-select v-model="formData.colorType">
<el-option
v-for="item in colorTypeOptions"
:key="item.value"
:label="item.label + '(' + item.value + ')'"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="CSS Class" prop="cssClass">
<el-input v-model="formData.cssClass" placeholder="请输入 CSS Class" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="modelVisible = false"> </el-button>
</div>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
import * as DictDataApi from '@/api/system/dict/dict.data'
import { CommonStatusEnum } from '@/utils/constants'
const { t } = useI18n() //
const message = useMessage() //
const modelVisible = ref(false) //
const modelTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
sort: undefined,
label: '',
value: '',
dictType: '',
status: CommonStatusEnum.ENABLE,
colorType: '',
cssClass: '',
remark: ''
})
const formRules = reactive({
label: [{ required: true, message: '数据标签不能为空', trigger: 'blur' }],
value: [{ required: true, message: '数据键值不能为空', trigger: 'blur' }],
sort: [{ required: true, message: '数据顺序不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
//
const colorTypeOptions = readonly([
{
value: 'default',
label: '默认'
},
{
value: 'primary',
label: '主要'
},
{
value: 'success',
label: '成功'
},
{
value: 'info',
label: '信息'
},
{
value: 'warning',
label: '警告'
},
{
value: 'danger',
label: '危险'
}
])
/** 打开弹窗 */
const openModal = async (type: string, id?: number) => {
modelVisible.value = true
modelTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
formData.value = await DictDataApi.getDictData(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ openModal }) // openModal
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
if (!formRef) return
const valid = await formRef.value.validate()
if (!valid) return
//
formLoading.value = true
try {
const data = formData.value as DictDataApi.DictDataVO
if (formType.value === 'create') {
await DictDataApi.createDictData(data)
message.success(t('common.createSuccess'))
} else {
await DictDataApi.updateDictData(data)
message.success(t('common.updateSuccess'))
}
modelVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
sort: undefined,
label: '',
value: '',
dictType: '',
status: CommonStatusEnum.ENABLE,
colorType: '',
cssClass: '',
remark: ''
}
formRef.value?.resetFields()
}
</script>

View File

@ -0,0 +1,202 @@
<template>
<content-wrap>
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="字典名称" prop="dictType">
<el-select v-model="queryParams.dictType" class="!w-240px">
<el-option v-for="item in dicts" :key="item.type" :label="item.name" :value="item.type" />
</el-select>
</el-form-item>
<el-form-item label="字典标签" prop="label">
<el-input
v-model="queryParams.label"
placeholder="请输入字典标签"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="数据状态" clearable class="!w-240px">
<el-option
v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button type="primary" @click="openModal('create')" v-hasPermi="['system:dict:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['system:dict:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</content-wrap>
<!-- 列表 -->
<content-wrap>
<el-table v-loading="loading" :data="list">
<el-table-column label="字典编码" align="center" prop="id" />
<el-table-column label="字典标签" align="center" prop="label" />
<el-table-column label="字典键值" align="center" prop="value" />
<el-table-column label="字典排序" align="center" prop="sort" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="颜色类型" align="center" prop="colorType" />
<el-table-column label="CSS Class" align="center" prop="cssClass" />
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
<el-table-column
label="创建时间"
align="center"
prop="createTime"
width="180"
:formatter="dateFormatter"
/>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openModal('update', scope.row.id)"
v-hasPermi="['system:dict:update']"
>
修改
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['system:dict:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</content-wrap>
<!-- 表单弹窗添加/修改 -->
<data-form ref="modalRef" @success="getList" />
</template>
<script setup lang="ts" name="Data">
import * as DictDataApi from '@/api/system/dict/dict.data'
import * as DictTypeApi from '@/api/system/dict/dict.type'
import { getDictOptions, DICT_TYPE } from '@/utils/dict'
import download from '@/utils/download'
import { dateFormatter } from '@/utils/formatTime'
import DataForm from './data.form.vue'
const message = useMessage() //
const { t } = useI18n() //
const route = useRoute() //
const loading = ref(true) //
const total = ref(0) //
const list = ref([]) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
label: '',
status: undefined,
dictType: route.params.dictType
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const dicts = ref<DictTypeApi.DictTypeVO[]>() //
/** 查询参数列表 */
const getList = async () => {
loading.value = true
try {
const data = await DictDataApi.getDictDataPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const modalRef = ref()
const openModal = (type: string, id?: number) => {
modalRef.value.openModal(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await DictDataApi.deleteDictData(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await DictDataApi.exportDictDataApi(queryParams)
download.excel(data, '字典数据.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 查询字典(精简)列表 */
const getDictList = async () => {
dicts.value = await DictTypeApi.listSimpleDictType()
}
/** 初始化 **/
onMounted(() => {
getList()
// )
getDictList()
})
</script>

View File

@ -1,104 +0,0 @@
import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
// 国际化
const { t } = useI18n()
// 表单校验
export const dictDataRules = reactive({
label: [required],
value: [required],
sort: [required]
})
// crudSchemas
export const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id',
primaryType: null,
action: true,
actionWidth: '140px',
searchSpan: 12,
columns: [
{
title: '字典类型',
field: 'dictType',
isTable: false,
isForm: false
},
{
title: '数据标签',
field: 'label',
isSearch: true
},
{
title: '数据键值',
field: 'value'
},
// {
// title: '标签类型',
// field: 'colorType',
// form: {
// component: 'Select',
// componentProps: {
// options: [
// {
// label: 'default',
// value: ''
// },
// {
// label: 'success',
// value: 'success'
// },
// {
// label: 'info',
// value: 'info'
// },
// {
// label: 'warning',
// value: 'warning'
// },
// {
// label: 'danger',
// value: 'danger'
// }
// ]
// }
// },
// isTable: false
// },
{
title: '颜色',
field: 'cssClass',
isTable: false,
form: {
component: 'ColorPicker',
componentProps: {
predefine: ['#ffffff', '#409eff', '#67c23a', '#e6a23c', '#f56c6c', '#909399', '#c71585']
}
}
},
{
title: '显示排序',
field: 'sort',
isTable: false
},
{
title: t('common.status'),
field: 'status',
dictType: DICT_TYPE.COMMON_STATUS,
dictClass: 'number'
},
{
title: t('form.remark'),
field: 'remark',
form: {
component: 'Input',
componentProps: {
type: 'textarea',
rows: 4
},
colProps: {
span: 24
}
},
isTable: false
}
]
})
export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

View File

@ -1,65 +0,0 @@
import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
const { t } = useI18n() // 国际化
// 表单校验
export const dictTypeRules = reactive({
name: [required],
type: [required]
})
// 新增 + 修改
const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id',
primaryType: null,
action: true,
actionWidth: '140px',
searchSpan: 12,
columns: [
{
title: '字典名称',
field: 'name',
isSearch: true
},
{
title: '字典类型',
field: 'type',
isSearch: true
},
{
title: t('common.status'),
field: 'status',
dictType: DICT_TYPE.COMMON_STATUS,
dictClass: 'number',
table: {
width: 70
}
},
{
title: t('common.createTime'),
field: 'createTime',
formatter: 'formatDate',
isForm: false,
isTable: false,
search: {
show: true,
itemRender: {
name: 'XDataTimePicker'
}
}
},
{
title: t('form.remark'),
field: 'remark',
isTable: false,
form: {
componentProps: {
type: 'textarea',
rows: 4
},
colProps: {
span: 24
}
}
}
]
})
export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

View File

@ -0,0 +1,123 @@
<template>
<Dialog :title="modelTitle" v-model="modelVisible">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="80px"
v-loading="formLoading"
>
<el-form-item label="字典名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入字典名称" />
</el-form-item>
<el-form-item label="字典类型" prop="type">
<el-input
:disabled="typeof formData.id !== 'undefined'"
v-model="formData.type"
placeholder="请输入参数名称"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="formData.status">
<el-radio
v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="parseInt(dict.value)"
:label="parseInt(dict.value)"
>{{ dict.label }}</el-radio
>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="modelVisible = false"> </el-button>
</div>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
import * as DictTypeApi from '@/api/system/dict/dict.type'
import { CommonStatusEnum } from '@/utils/constants'
const { t } = useI18n() //
const message = useMessage() //
const modelVisible = ref(false) //
const modelTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
name: '',
type: '',
status: CommonStatusEnum.ENABLE,
remark: ''
})
const formRules = reactive({
name: [{ required: true, message: '字典名称不能为空', trigger: 'blur' }],
type: [{ required: true, message: '字典类型不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
/** 打开弹窗 */
const openModal = async (type: string, id?: number) => {
modelVisible.value = true
modelTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
formData.value = await DictTypeApi.getDictType(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ openModal }) // openModal
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
if (!formRef) return
const valid = await formRef.value.validate()
if (!valid) return
//
formLoading.value = true
try {
const data = formData.value as DictTypeApi.DictTypeVO
if (formType.value === 'create') {
await DictTypeApi.createDictType(data)
message.success(t('common.createSuccess'))
} else {
await DictTypeApi.updateDictType(data)
message.success(t('common.updateSuccess'))
}
modelVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
type: '',
name: '',
status: CommonStatusEnum.ENABLE,
remark: ''
}
formRef.value?.resetFields()
}
</script>

View File

@ -1,257 +1,211 @@
<template>
<div class="flex">
<!-- ====== 字典分类 ====== -->
<el-card class="w-1/2 dict" :gutter="12" shadow="always">
<template #header>
<div class="card-header">
<span>字典分类</span>
</div>
</template>
<XTable @register="registerType" @cell-click="cellClickEvent">
<!-- 操作新增类型 -->
<template #toolbar_buttons>
<XButton
type="primary"
preIcon="ep:zoom-in"
:title="t('action.add')"
v-hasPermi="['system:dict:create']"
@click="handleTypeCreate()"
/>
</template>
<template #actionbtns_default="{ row }">
<!-- 操作编辑类型 -->
<XTextButton
preIcon="ep:edit"
:title="t('action.edit')"
v-hasPermi="['system:dict:update']"
@click="handleTypeUpdate(row.id)"
/>
<!-- 操作删除类型 -->
<XTextButton
preIcon="ep:delete"
:title="t('action.del')"
v-hasPermi="['system:dict:delete']"
@click="typeDeleteData(row.id)"
/>
</template>
</XTable>
<!-- @星语分页和列表重叠在一起了 -->
</el-card>
<!-- ====== 字典数据 ====== -->
<el-card class="w-1/2 dict ml-3" :gutter="12" shadow="hover">
<template #header>
<div class="card-header">
<span>字典数据</span>
</div>
</template>
<!-- 列表 -->
<div v-if="!tableTypeSelect">
<span>请从左侧选择</span>
</div>
<div v-if="tableTypeSelect">
<!-- 列表 -->
<XTable @register="registerData">
<!-- 操作新增数据 -->
<template #toolbar_buttons>
<XButton
type="primary"
preIcon="ep:zoom-in"
:title="t('action.add')"
v-hasPermi="['system:dict:create']"
@click="handleDataCreate()"
/>
</template>
<template #actionbtns_default="{ row }">
<!-- 操作修改数据 -->
<XTextButton
v-hasPermi="['system:dict:update']"
preIcon="ep:edit"
:title="t('action.edit')"
@click="handleDataUpdate(row.id)"
/>
<!-- 操作删除数据 -->
<XTextButton
v-hasPermi="['system:dict:delete']"
preIcon="ep:delete"
:title="t('action.del')"
@click="dataDeleteData(row.id)"
/>
</template>
</XTable>
</div>
</el-card>
<XModal id="dictModel" v-model="dialogVisible" :title="dialogTitle">
<Form
v-if="['typeCreate', 'typeUpdate'].includes(actionType)"
:schema="DictTypeSchemas.allSchemas.formSchema"
:rules="DictTypeSchemas.dictTypeRules"
ref="typeFormRef"
<!-- 搜索工作栏 -->
<content-wrap>
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<template #type>
<template v-if="actionType == 'typeUpdate'">
<el-tag>{{ dictTypeValue }}</el-tag>
</template>
<template v-else><el-input v-model="dictTypeValue" /> </template>
</template>
</Form>
<Form
v-if="['dataCreate', 'dataUpdate'].includes(actionType)"
:schema="DictDataSchemas.allSchemas.formSchema"
:rules="DictDataSchemas.dictDataRules"
ref="dataFormRef"
<el-form-item label="字典名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入字典名称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
<!-- 操作按钮 -->
<template #footer>
<XButton
v-if="['typeCreate', 'typeUpdate'].includes(actionType)"
</el-form-item>
<el-form-item label="字典类型" prop="type">
<el-input
v-model="queryParams.type"
placeholder="请输入字典类型"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="字典状态" clearable class="!w-240px">
<el-option
v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="parseInt(dict.value)"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
value-format="yyyy-MM-dd HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button type="primary" @click="openModal('create')" v-hasPermi="['system:dict:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['system:dict:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</content-wrap>
<!-- 列表 -->
<content-wrap>
<el-table v-loading="loading" :data="list">
<el-table-column label="字典编号" align="center" prop="id" />
<el-table-column label="字典名称" align="center" prop="name" show-overflow-tooltip />
<el-table-column label="字典类型" align="center" prop="type" width="300" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column
label="创建时间"
:formatter="dateFormatter"
align="center"
prop="createTime"
width="180"
/>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
:title="t('action.save')"
:loading="actionLoading"
@click="submitTypeForm"
/>
<XButton
v-if="['dataCreate', 'dataUpdate'].includes(actionType)"
type="primary"
:title="t('action.save')"
:loading="actionLoading"
@click="submitDataForm"
/>
<XButton :title="t('dialog.close')" @click="dialogVisible = false" />
@click="openModal('update', scope.row.id)"
v-hasPermi="['system:dict:update']"
>
修改
</el-button>
<router-link :to="'/dict/type/data/' + scope.row.type">
<el-button link type="primary">数据</el-button>
</router-link>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['system:dict:delete']"
>
删除
</el-button>
</template>
</XModal>
</div>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</content-wrap>
<!-- 表单弹窗添加/修改 -->
<dict-type-form ref="modalRef" @success="getList" />
</template>
<script setup lang="ts" name="Dict">
import { VxeTableEvents } from 'vxe-table'
import type { FormExpose } from '@/components/Form'
import * as DictTypeSchemas from './dict.type'
import * as DictDataSchemas from './dict.data'
import { getDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import * as DictTypeApi from '@/api/system/dict/dict.type'
import * as DictDataApi from '@/api/system/dict/dict.data'
import { DictDataVO, DictTypeVO } from '@/api/system/dict/types'
const { t } = useI18n() //
import DictTypeForm from './form.vue'
import download from '@/utils/download'
const message = useMessage() //
const { t } = useI18n() //
const [registerType, { reload: typeGetList, deleteData: typeDeleteData }] = useXTable({
allSchemas: DictTypeSchemas.allSchemas,
getListApi: DictTypeApi.getDictTypePageApi,
deleteApi: DictTypeApi.deleteDictTypeApi
})
const loading = ref(true) //
const total = ref(0) //
const list = ref([]) //
const queryParams = reactive({
dictType: null
pageNo: 1,
pageSize: 10,
name: '',
type: '',
status: undefined,
createTime: []
})
const [registerData, { reload: dataGetList, deleteData: dataDeleteData }] = useXTable({
allSchemas: DictDataSchemas.allSchemas,
params: queryParams,
getListApi: DictDataApi.getDictDataPageApi,
deleteApi: DictDataApi.deleteDictDataApi
})
// ========== ==========
const dictTypeValue = ref('')
//
const handleTypeCreate = () => {
dictTypeValue.value = ''
setDialogTile('typeCreate')
}
const handleTypeUpdate = async (rowId: number) => {
setDialogTile('typeUpdate')
//
const res = await DictTypeApi.getDictTypeApi(rowId)
dictTypeValue.value = res.type
unref(typeFormRef)?.setValues(res)
}
const queryFormRef = ref() //
const exportLoading = ref(false) //
//
const handleDataCreate = () => {
setDialogTile('dataCreate')
}
const handleDataUpdate = async (rowId: number) => {
setDialogTile('dataUpdate')
//
const res = await DictDataApi.getDictDataApi(rowId)
unref(dataFormRef)?.setValues(res)
}
//
const parentType = ref('')
const tableTypeSelect = ref(false)
const cellClickEvent: VxeTableEvents.CellClick = async ({ row }) => {
tableTypeSelect.value = true
queryParams.dictType = row['type']
await nextTick()
await dataGetList()
parentType.value = row['type']
}
//
const dialogVisible = ref(false) //
const dialogTitle = ref('edit') //
const actionLoading = ref(false) //
const typeFormRef = ref<FormExpose>() // Ref
const dataFormRef = ref<FormExpose>() // Ref
const actionType = ref('') //
//
const setDialogTile = (type: string) => {
dialogTitle.value = t('action.' + type)
actionType.value = type
dialogVisible.value = true
}
// dictTypeValueform
watch(dictTypeValue, (val) => {
unref(typeFormRef)?.setValues({ type: val })
})
//
const submitTypeForm = async () => {
const elForm = unref(typeFormRef)?.getElFormRef()
if (!elForm) return
elForm.validate(async (valid) => {
if (valid && dictTypeValue.value != '') {
actionLoading.value = true
//
/** 查询字典类型列表 */
const getList = async () => {
loading.value = true
try {
const data = unref(typeFormRef)?.formModel as DictTypeVO
if (actionType.value === 'typeCreate') {
data.type = dictTypeValue.value
await DictTypeApi.createDictTypeApi(data)
message.success(t('common.createSuccess'))
} else if (actionType.value === 'typeUpdate') {
await DictTypeApi.updateDictTypeApi(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
const data = await DictTypeApi.getDictTypePage(queryParams)
list.value = data.list
total.value = data.total
} finally {
actionLoading.value = false
typeGetList()
loading.value = false
}
}
})
}
const submitDataForm = async () => {
const elForm = unref(dataFormRef)?.getElFormRef()
if (!elForm) return
elForm.validate(async (valid) => {
if (valid) {
actionLoading.value = true
//
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const modalRef = ref()
const openModal = (type: string, id?: number) => {
modalRef.value.openModal(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
const data = unref(dataFormRef)?.formModel as DictDataVO
if (actionType.value === 'dataCreate') {
data.dictType = parentType.value
await DictDataApi.createDictDataApi(data)
message.success(t('common.createSuccess'))
} else if (actionType.value === 'dataUpdate') {
await DictDataApi.updateDictDataApi(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
} finally {
actionLoading.value = false
dataGetList()
}
}
})
//
await message.delConfirm()
//
await DictTypeApi.deleteDictType(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await DictTypeApi.exportDictType(queryParams)
download.excel(data, '字典类型.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -1,54 +0,0 @@
import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
const { t } = useI18n() // 国际化
// 表单校验
export const rules = reactive({
applicationName: [required],
code: [required],
message: [required]
})
// 新增 + 修改
const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id',
primaryType: 'id',
primaryTitle: '编号',
action: true,
columns: [
{
title: '错误码类型',
field: 'type',
dictType: DICT_TYPE.SYSTEM_ERROR_CODE_TYPE,
dictClass: 'number',
isSearch: true
},
{
title: '应用名',
field: 'applicationName',
isSearch: true
},
{
title: '错误码编码',
field: 'code',
isSearch: true
},
{
title: '错误码错误提示',
field: 'message',
isSearch: true
},
{
title: t('common.createTime'),
field: 'createTime',
formatter: 'formatDate',
isForm: false,
search: {
show: true,
itemRender: {
name: 'XDataTimePicker'
}
}
}
]
})
export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

View File

@ -0,0 +1,112 @@
<template>
<Dialog :title="modelTitle" v-model="modelVisible">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
<el-form-item label="应用名" prop="applicationName">
<el-input v-model="formData.applicationName" placeholder="请输入应用名" clearable />
</el-form-item>
<el-form-item label="错误码编码" prop="code">
<el-input v-model="formData.code" placeholder="请输入错误码编码" clearable />
</el-form-item>
<el-form-item label="错误码提示" prop="message">
<el-input v-model="formData.message" placeholder="请输入错误码提示" clearable />
</el-form-item>
<el-form-item label="备注" prop="memo">
<el-input v-model="formData.memo" placeholder="请输入备注" clearable />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="modelVisible = false"> </el-button>
</div>
</template>
</Dialog>
</template>
<script setup lang="ts">
import * as ErrorCodeApi from '@/api/system/errorCode'
const { t } = useI18n() //
const message = useMessage() //
const modelVisible = ref(false) //
const modelTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
//
const formData = ref({
id: undefined,
code: undefined,
applicationName: '',
message: '',
memo: ''
})
//
const formRules = reactive({
applicationName: [{ required: true, message: '应用名不能为空', trigger: 'blur' }],
code: [{ required: true, message: '错误码编码不能为空', trigger: 'blur' }],
message: [{ required: true, message: '错误码提示不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
/** 打开弹窗 */
const openModal = async (type: string, id?: number) => {
modelVisible.value = true
modelTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
formData.value = await ErrorCodeApi.getErrorCodeApi(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ openModal }) // openModal
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
if (!formRef) return
const valid = await formRef.value.validate()
if (!valid) return
//
formLoading.value = true
try {
const data = formData.value as ErrorCodeApi.ErrorCodeVO
if (formType.value === 'create') {
await ErrorCodeApi.createErrorCodeApi(data)
message.success(t('common.createSuccess'))
} else {
await ErrorCodeApi.updateErrorCodeApi(data)
message.success(t('common.updateSuccess'))
}
modelVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 表单重置 */
const resetForm = () => {
formData.value = {
id: undefined,
applicationName: '',
code: undefined,
message: '',
memo: ''
}
formRef.value?.resetFields()
}
</script>

View File

@ -1,145 +1,229 @@
<template>
<ContentWrap>
<!-- 列表 -->
<XTable @register="registerTable">
<!-- 操作新增 -->
<template #toolbar_buttons>
<XButton
<!-- 搜索工作栏 -->
<content-wrap>
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="90px"
>
<el-form-item label="错误码类型" prop="type">
<el-select v-model="queryParams.type" placeholder="请选择错误码类型" clearable>
<el-option
v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_ERROR_CODE_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
class="!w-240px"
/>
</el-select>
</el-form-item>
<el-form-item label="应用名" prop="applicationName">
<el-input
v-model="queryParams.applicationName"
placeholder="请输入应用名"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="错误码编码" prop="code">
<el-input
v-model="queryParams.code"
placeholder="请输入错误码编码"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="错误码提示" prop="message">
<el-input
v-model="queryParams.message"
placeholder="请输入错误码提示"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button
type="primary"
preIcon="ep:zoom-in"
:title="t('action.add')"
@click="openModal('create')"
v-hasPermi="['system:error-code:create']"
@click="handleCreate()"
/>
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['system:error-code:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</content-wrap>
<!-- 列表 -->
<content-wrap>
<el-table v-loading="loading" :data="list">
<el-table-column label="编号" align="center" prop="id" />
<el-table-column label="类型" align="center" prop="type" width="80">
<template #default="scope">
<dict-tag :type="DICT_TYPE.SYSTEM_ERROR_CODE_TYPE" :value="scope.row.type" />
</template>
<template #actionbtns_default="{ row }">
<!-- 操作修改 -->
<XTextButton
preIcon="ep:edit"
:title="t('action.edit')"
v-hasPermi="['system:error-code:update']"
@click="handleUpdate(row.id)"
</el-table-column>
<el-table-column label="应用名" align="center" prop="applicationName" width="200" />
<el-table-column label="错误码编码" align="center" prop="code" width="120" />
<el-table-column label="错误码提示" align="center" prop="message" width="300" />
<el-table-column label="备注" align="center" prop="memo" width="200" />
<el-table-column
label="创建时间"
align="center"
prop="createTime"
width="180"
:formatter="dateFormatter"
/>
<!-- 操作详情 -->
<XTextButton
preIcon="ep:view"
:title="t('action.detail')"
v-hasPermi="['system:error-code:query']"
@click="handleDetail(row.id)"
/>
<!-- 操作删除 -->
<XTextButton
preIcon="ep:delete"
:title="t('action.del')"
v-hasPermi="['system:error-code:delete']"
@click="deleteData(row.id)"
/>
</template>
</XTable>
</ContentWrap>
<!-- 弹窗 -->
<XModal id="errorCodeModel" v-model="dialogVisible" :title="dialogTitle">
<!-- 对话框(添加 / 修改) -->
<Form
v-if="['create', 'update'].includes(actionType)"
:schema="allSchemas.formSchema"
:rules="rules"
ref="formRef"
/>
<!-- 对话框(详情) -->
<Descriptions
v-if="actionType === 'detail'"
:schema="allSchemas.detailSchema"
:data="detailData"
/>
<template #footer>
<!-- 按钮保存 -->
<XButton
v-if="['create', 'update'].includes(actionType)"
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button
link
type="primary"
:title="t('action.save')"
:loading="actionLoading"
@click="submitForm()"
/>
<!-- 按钮关闭 -->
<XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
@click="openModal('update', scope.row.id)"
v-hasPermi="['system:error-code:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['system:error-code:delete']"
>
删除
</el-button>
</template>
</XModal>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</content-wrap>
<!-- 表单弹窗添加/修改 -->
<error-code-form ref="modalRef" @success="getList" />
</template>
<script setup lang="ts" name="ErrorCode">
import type { FormExpose } from '@/components/Form'
// import
import { rules, allSchemas } from './errorCode.data'
import * as ErrorCodeApi from '@/api/system/errorCode'
const { t } = useI18n() //
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import ErrorCodeForm from './form.vue'
import download from '@/utils/download'
const message = useMessage() //
//
const [registerTable, { reload, deleteData }] = useXTable({
allSchemas: allSchemas,
getListApi: ErrorCodeApi.getErrorCodePageApi,
deleteApi: ErrorCodeApi.deleteErrorCodeApi
const { t } = useI18n() //
//
const loading = ref(true)
//
const exportLoading = ref(false)
//
const total = ref(0)
//
const list = ref([])
//
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
type: undefined,
applicationName: undefined,
code: undefined,
message: undefined,
createTime: []
})
//
const dialogVisible = ref(false) //
const dialogTitle = ref('edit') //
const actionType = ref('') //
const actionLoading = ref(false) // Loading
const formRef = ref<FormExpose>() // Ref
const detailData = ref() // Ref
//
const queryFormRef = ref()
//
const setDialogTile = (type: string) => {
dialogTitle.value = t('action.' + type)
actionType.value = type
dialogVisible.value = true
}
//
const handleCreate = () => {
setDialogTile('create')
}
//
const handleUpdate = async (rowId: number) => {
setDialogTile('update')
//
const res = await ErrorCodeApi.getErrorCodeApi(rowId)
unref(formRef)?.setValues(res)
}
//
const handleDetail = async (rowId: number) => {
setDialogTile('detail')
//
const res = await ErrorCodeApi.getErrorCodeApi(rowId)
detailData.value = res
}
// /
const submitForm = async () => {
const elForm = unref(formRef)?.getElFormRef()
if (!elForm) return
elForm.validate(async (valid) => {
if (valid) {
actionLoading.value = true
//
/** 查询列表 */
const getList = async () => {
loading.value = true
//
try {
const data = unref(formRef)?.formModel as ErrorCodeApi.ErrorCodeVO
if (actionType.value === 'create') {
await ErrorCodeApi.createErrorCodeApi(data)
message.success(t('common.createSuccess'))
} else {
await ErrorCodeApi.updateErrorCodeApi(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
const data = await ErrorCodeApi.getErrorCodePageApi(queryParams)
list.value = data.list
total.value = data.total
} finally {
actionLoading.value = false
//
await reload()
loading.value = false
}
}
})
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const modalRef = ref()
const openModal = (type: string, id?: number) => {
modalRef.value.openModal(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
await ErrorCodeApi.deleteErrorCodeApi(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await ErrorCodeApi.excelErrorCodeApi(queryParams)
download.excel(data, '错误码.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -1,17 +1,29 @@
<template>
<content-wrap>
<!-- 搜索工作栏 -->
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true">
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="公告标题" prop="title">
<el-input
v-model="queryParams.title"
placeholder="请输入公告标题"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="公告状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择公告状态" clearable>
<el-select
v-model="queryParams.status"
placeholder="请选择公告状态"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="parseInt(dict.value)"

View File

@ -119,7 +119,7 @@ import { FormExpose } from '@/components/Form'
// import
import { rules, allSchemas } from './template.data'
import * as NotifyTemplateApi from '@/api/system/notify/template'
import { getListSimpleUsersApi, UserVO } from '@/api/system/user'
import { getSimpleUserList, UserVO } from '@/api/system/user'
const { t } = useI18n() //
const message = useMessage() //
@ -244,7 +244,7 @@ const sendTest = async () => {
// ========== ==========
onMounted(() => {
getListSimpleUsersApi().then((data) => {
getSimpleUserList().then((data) => {
userOption.value = data
})
})

View File

@ -1,64 +1,159 @@
<template>
<ContentWrap>
<!-- 列表 -->
<XTable @register="registerTable">
<template #actionbtns_default="{ row }">
<!-- 操作详情 -->
<XTextButton preIcon="ep:view" :title="t('action.detail')" @click="handleDetail(row)" />
<!-- 操作登出 -->
<XTextButton
preIcon="ep:delete"
:title="t('action.logout')"
v-hasPermi="['system:oauth2-token:delete']"
@click="handleForceLogout(row.id)"
<content-wrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="90px"
>
<el-form-item label="用户编号" prop="userId">
<el-input
v-model="queryParams.userId"
placeholder="请输入用户编号"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="用户类型" prop="userType">
<el-select
v-model="queryParams.userType"
placeholder="请选择用户类型"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.USER_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="客户端编号" prop="clientId">
<el-input
v-model="queryParams.clientId"
placeholder="请输入客户端编号"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
</el-form-item>
</el-form>
</content-wrap>
<!-- 列表 -->
<content-wrap>
<el-table v-loading="loading" :data="list">
<el-table-column label="访问令牌" align="center" prop="accessToken" width="300" />
<el-table-column label="刷新令牌" align="center" prop="refreshToken" width="300" />
<el-table-column label="用户编号" align="center" prop="userId" />
<el-table-column label="用户类型" align="center" prop="userType">
<template #default="scope">
<dict-tag :type="DICT_TYPE.USER_TYPE" :value="scope.row.userType" />
</template>
</XTable>
</ContentWrap>
<XModal v-model="dialogVisible" :title="dialogTitle">
<!-- 对话框(详情) -->
<Descriptions :schema="allSchemas.detailSchema" :data="detailData" />
<!-- 操作按钮 -->
<template #footer>
<XButton :title="t('dialog.close')" @click="dialogVisible = false" />
</el-table-column>
<el-table-column
label="过期时间"
align="center"
prop="expiresTime"
:formatter="dateFormatter"
width="180"
/>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180"
/>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="danger"
@click="handleForceLogout(scope.row.id)"
v-hasPermi="['system:oauth2-token:delete']"
>
强退
</el-button>
</template>
</XModal>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</content-wrap>
</template>
<script setup lang="ts" name="Token">
import { allSchemas } from './token.data'
import * as TokenApi from '@/api/system/oauth2/token'
const { t } = useI18n() //
<script setup lang="ts" name="Oauth2AccessToken">
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import * as OAuth2AccessTokenApi from '@/api/system/oauth2/token'
const message = useMessage() //
//
const [registerTable, { reload }] = useXTable({
allSchemas: allSchemas,
topActionSlots: false,
getListApi: TokenApi.getAccessTokenPageApi
const { t } = useI18n() //
const loading = ref(true) //
const total = ref(0) //
const list = ref([]) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
userId: null,
userType: null,
clientId: null
})
const queryFormRef = ref() //
// ========== ==========
const detailData = ref() // Ref
const dialogVisible = ref(false) //
const dialogTitle = ref(t('action.detail')) //
//
const handleDetail = async (row: TokenApi.OAuth2TokenVO) => {
//
detailData.value = row
dialogVisible.value = true
/** 查询参数列表 */
const getList = async () => {
loading.value = true
try {
const data = await OAuth2AccessTokenApi.getAccessTokenPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
// 退
const handleForceLogout = (rowId: number) => {
message
.confirm('是否要强制退出用户')
.then(async () => {
await TokenApi.deleteAccessTokenApi(rowId)
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 强制退出操作 */
const handleForceLogout = async (id: number) => {
try {
//
await message.confirm('是否要强制退出用户')
//
await OAuth2AccessTokenApi.deleteAccessToken(id)
message.success(t('common.success'))
})
.finally(async () => {
//
await reload()
})
await getList()
} catch {}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -1,48 +0,0 @@
import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
const { t } = useI18n() // 国际化
// CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id',
primaryType: null,
action: true,
columns: [
{
title: '用户编号',
field: 'userId',
isSearch: true
},
{
title: '访问令牌',
field: 'accessToken'
},
{
title: '刷新令牌',
field: 'refreshToken'
},
{
title: '客户端编号',
field: 'clientId',
isSearch: true
},
{
title: '用户类型',
field: 'userType',
dictType: DICT_TYPE.USER_TYPE,
dictClass: 'number',
isSearch: true
},
{
title: t('common.createTime'),
field: 'createTime',
formatter: 'formatDate',
isForm: false
},
{
title: '过期时间',
field: 'expiresTime',
formatter: 'formatDate',
isForm: false
}
]
})
export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

View File

@ -1,13 +1,20 @@
<template>
<content-wrap>
<!-- 搜索工作栏 -->
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true">
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="系统模块" prop="module">
<el-input
v-model="queryParams.module"
placeholder="请输入系统模块"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="操作人员" prop="userNickname">
@ -16,10 +23,16 @@
placeholder="请输入操作人员"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="类型" prop="type">
<el-select v-model="queryParams.type" placeholder="操作类型" clearable>
<el-form-item label="操作类型" prop="type">
<el-select
v-model="queryParams.type"
placeholder="请选择操作类型"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_OPERATE_TYPE)"
:key="parseInt(dict.value)"
@ -28,8 +41,13 @@
/>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="success">
<el-select v-model="queryParams.success" placeholder="操作状态" clearable>
<el-form-item label="操作状态" prop="success">
<el-select
v-model="queryParams.success"
placeholder="请选择操作状态"
clearable
class="!w-240px"
>
<el-option :key="true" label="成功" :value="true" />
<el-option :key="false" label="失败" :value="false" />
</el-select>
@ -42,6 +60,7 @@
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item>

View File

@ -0,0 +1,122 @@
<template>
<Dialog :title="modelTitle" v-model="modelVisible" width="800">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="80px"
v-loading="formLoading"
>
<el-form-item label="岗位标题" prop="name">
<el-input v-model="formData.name" placeholder="请输入岗位标题" />
</el-form-item>
<el-form-item label="岗位编码" prop="code">
<el-input :model-value="formData.code" placeholder="请输入岗位编码" height="150px" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="formData.status" placeholder="请选择状态" clearable>
<el-option
v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="parseInt(dict.value)"
:label="dict.label"
:value="parseInt(dict.value)"
/>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" type="textarea" placeholder="请输备注" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="modelVisible = false"> </el-button>
</div>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
import { CommonStatusEnum } from '@/utils/constants'
import * as PostApi from '@/api/system/post'
const { t } = useI18n() //
const message = useMessage() //
const modelVisible = ref(false) //
const modelTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
name: '',
code: '',
sort: undefined,
status: CommonStatusEnum.ENABLE,
remark: ''
})
const formRules = reactive({
name: [{ required: true, message: '岗位标题不能为空', trigger: 'blur' }],
code: [{ required: true, message: '岗位编码不能为空', trigger: 'change' }],
status: [{ required: true, message: '岗位状态不能为空', trigger: 'change' }],
remark: [{ required: false, message: '岗位内容不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
/** 打开弹窗 */
const openModal = async (type: string, id?: number) => {
modelVisible.value = true
modelTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
formData.value = await PostApi.getPost(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ openModal }) // openModal
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
if (!formRef) return
const valid = await formRef.value.validate()
if (!valid) return
//
formLoading.value = true
try {
const data = formData.value as unknown as PostApi.PostVO
if (formType.value === 'create') {
await PostApi.createPost(data)
message.success(t('common.createSuccess'))
} else {
await PostApi.updatePost(data)
message.success(t('common.updateSuccess'))
}
modelVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
name: '',
code: '',
sort: undefined,
status: CommonStatusEnum.ENABLE,
remark: ''
}
formRef.value?.resetFields()
}
</script>

View File

@ -1,91 +0,0 @@
<template>
<!-- 弹窗 -->
<XModal :title="modelTitle" :loading="modelLoading" v-model="modelVisible">
<!-- 表单添加/修改 -->
<Form
ref="formRef"
v-if="['create', 'update'].includes(actionType)"
:schema="allSchemas.formSchema"
:rules="rules"
/>
<!-- 表单详情 -->
<Descriptions
v-if="actionType === 'detail'"
:schema="allSchemas.detailSchema"
:data="detailData"
/>
<template #footer>
<!-- 按钮保存 -->
<XButton
v-if="['create', 'update'].includes(actionType)"
type="primary"
:title="t('action.save')"
:loading="actionLoading"
@click="submitForm()"
/>
<!-- 按钮关闭 -->
<XButton :loading="actionLoading" :title="t('dialog.close')" @click="modelVisible = false" />
</template>
</XModal>
</template>
<script setup lang="ts">
import type { FormExpose } from '@/components/Form'
import * as PostApi from '@/api/system/post'
import { rules, allSchemas } from './post.data'
const { t } = useI18n() //
const message = useMessage() //
//
const modelVisible = ref(false) //
const modelTitle = ref('') //
const modelLoading = ref(false) // loading
const actionType = ref('') //
const actionLoading = ref(false) // Loading
const formRef = ref<FormExpose>() // Ref
const detailData = ref() // Ref
//
const openModal = async (type: string, id?: number) => {
modelVisible.value = true
modelLoading.value = true
modelTitle.value = t('action.' + type)
actionType.value = type
//
if (id) {
const res = await PostApi.getPostApi(id)
if (type === 'update') {
unref(formRef)?.setValues(res)
} else if (type === 'detail') {
detailData.value = res
}
}
modelLoading.value = false
}
defineExpose({ openModal }) // openModal
// /
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
const elForm = unref(formRef)?.getElFormRef()
if (!elForm) return
const valid = await elForm.validate()
if (!valid) return
//
actionLoading.value = true
try {
const data = unref(formRef)?.formModel as PostApi.PostVO
if (actionType.value === 'create') {
await PostApi.createPostApi(data)
message.success(t('common.createSuccess'))
} else {
await PostApi.updatePostApi(data)
message.success(t('common.updateSuccess'))
}
modelVisible.value = false
emit('success')
} finally {
actionLoading.value = false
}
}
</script>

View File

@ -1,71 +1,198 @@
<template>
<ContentWrap>
<!-- 列表 -->
<XTable @register="registerTable">
<template #toolbar_buttons>
<!-- 操作新增 -->
<XButton
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="岗位名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入岗位名称"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="岗位编码" prop="code">
<el-input
v-model="queryParams.code"
placeholder="请输入岗位编码"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button
type="primary"
preIcon="ep:zoom-in"
:title="t('action.add')"
v-hasPermi="['system:post:create']"
@click="openModal('create')"
/>
<!-- 操作导出 -->
<XButton
type="primary"
v-hasPermi="['system:notice:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
preIcon="ep:download"
:title="t('action.export')"
v-hasPermi="['system:post:export']"
@click="exportList('岗位列表.xls')"
/>
</template>
<template #actionbtns_default="{ row }">
<!-- 操作修改 -->
<XTextButton
preIcon="ep:edit"
:title="t('action.edit')"
v-hasPermi="['system:post:update']"
@click="openModal('update', row?.id)"
/>
<!-- 操作详情 -->
<XTextButton
preIcon="ep:view"
:title="t('action.detail')"
v-hasPermi="['system:post:query']"
@click="openModal('detail', row?.id)"
/>
<!-- 操作删除 -->
<XTextButton
preIcon="ep:delete"
:title="t('action.delete')"
v-hasPermi="['system:post:delete']"
@click="deleteData(row?.id)"
/>
</template>
</XTable>
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['infra:config:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 表单弹窗添加/修改/详情 -->
<PostForm ref="modalRef" @success="reload()" />
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" align="center">
<el-table-column label="岗位编号" align="center" prop="id" />
<el-table-column label="岗位名称" align="center" prop="name" />
<el-table-column label="岗位编码" align="center" prop="code" />
<el-table-column label="岗位顺序" align="center" prop="sort" />
<el-table-column label="岗位备注" align="center" prop="remark" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
width="180"
:formatter="dateFormatter"
/>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openModal('update', scope.row.id)"
v-hasPermi="['system:post:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['system:post:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<PostForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts" name="Post">
<script setup lang="tsx">
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import * as PostApi from '@/api/system/post'
import { allSchemas } from './post.data'
import PostForm from './form.vue'
import PostForm from './PostForm.vue'
const message = useMessage() //
const { t } = useI18n() //
//
const [registerTable, { reload, deleteData, exportList }] = useXTable({
allSchemas: allSchemas, //
getListApi: PostApi.getPostPageApi, // API
deleteApi: PostApi.deletePostApi, // API
exportListApi: PostApi.exportPostApi // API
const loading = ref(true) //
const total = ref(0) //
const list = ref([]) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
code: '',
name: '',
status: undefined
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
//
const modalRef = ref()
const openModal = (type: string, id?: number) => {
modalRef.value.openModal(type, id)
/** 查询岗位列表 */
const getList = async () => {
loading.value = true
try {
const data = await PostApi.getPostPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openModal = (type: string, id?: number) => {
formRef.value.openModal(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await PostApi.deletePost(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await PostApi.exportPost(queryParams)
download.excel(data, '岗位列表.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -1,58 +0,0 @@
import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
const { t } = useI18n() // 国际化
// 表单校验
export const rules = reactive({
name: [required],
code: [required],
sort: [required]
})
// 增删改查 CrudSchema 配置
const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id',
primaryType: 'id',
primaryTitle: '岗位编号',
action: true,
columns: [
{
title: '岗位名称',
field: 'name',
isSearch: true
},
{
title: '岗位编码',
field: 'code',
isSearch: true
},
{
title: '岗位顺序',
field: 'sort',
form: {
component: 'InputNumber'
}
},
{
title: t('common.status'),
field: 'status',
dictType: DICT_TYPE.COMMON_STATUS,
dictClass: 'number',
isSearch: true
},
{
title: '备注',
field: 'remark',
isTable: false
},
{
title: t('common.createTime'),
field: 'createTime',
formatter: 'formatDate',
isForm: false,
table: {
width: 180
}
}
]
})
export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

View File

@ -0,0 +1,130 @@
<template>
<Dialog :title="modelTitle" v-model="modelVisible">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="80px"
v-loading="formLoading"
>
<el-form-item label="敏感词" prop="name">
<el-input v-model="formData.name" placeholder="请输入敏感词" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="formData.status">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="description">
<el-input v-model="formData.description" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="标签" prop="tags">
<el-select
v-model="formData.tags"
multiple
filterable
allow-create
placeholder="请选择文章标签"
style="width: 380px"
>
<el-option v-for="tag in tags" :key="tag" :label="tag" :value="tag" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="modelVisible = false"> </el-button>
</div>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import * as SensitiveWordApi from '@/api/system/sensitiveWord'
import { CommonStatusEnum } from '@/utils/constants'
const { t } = useI18n() //
const message = useMessage() //
const modelVisible = ref(false) //
const modelTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
name: '',
status: CommonStatusEnum.ENABLE,
description: '',
tags: []
})
const formRules = reactive({
name: [{ required: true, message: '敏感词不能为空', trigger: 'blur' }],
tags: [{ required: true, message: '标签不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
const tags = ref([]) // todo @blue-syd openModal
/** 打开弹窗 */
const openModal = async (type: string, id?: number) => {
modelVisible.value = true
modelTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
formData.value = await SensitiveWordApi.getSensitiveWordApi(id)
console.log(formData.value)
} finally {
formLoading.value = false
}
}
}
defineExpose({ openModal }) // openModal
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
if (!formRef) return
const valid = await formRef.value.validate()
if (!valid) return
//
formLoading.value = true
try {
const data = formData.value as unknown as SensitiveWordApi.SensitiveWordVO
if (formType.value === 'create') {
await SensitiveWordApi.createSensitiveWordApi(data) // TODO @blue-syd API
message.success(t('common.createSuccess'))
} else {
await SensitiveWordApi.updateSensitiveWordApi(data) // TODO @blue-syd API
message.success(t('common.updateSuccess'))
}
modelVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
name: '',
status: CommonStatusEnum.ENABLE,
description: '',
tags: []
}
formRef.value?.resetFields()
}
</script>

View File

@ -1,191 +1,225 @@
<template>
<ContentWrap>
<!-- 列表 -->
<XTable @register="registerTable">
<template #toolbar_buttons>
<!-- 操作新增 -->
<XButton
type="primary"
preIcon="ep:zoom-in"
:title="t('action.add')"
v-hasPermi="['system:sensitive-word:create']"
@click="handleCreate()"
<!-- 搜索 -->
<content-wrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true">
<el-form-item label="敏感词" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入敏感词"
clearable
@keyup.enter="handleQuery"
/>
<!-- 操作导出 -->
<XButton
type="warning"
preIcon="ep:download"
:title="t('action.export')"
v-hasPermi="['system:sensitive-word:export']"
@click="exportList('敏感词数据.xls')"
/>
</template>
<template #tags_default="{ row }">
<el-tag
:disable-transitions="true"
:key="index"
v-for="(tag, index) in row.tags"
:index="index"
</el-form-item>
<el-form-item label="标签" prop="tag">
<el-select
v-model="queryParams.tag"
placeholder="请选择标签"
clearable
@keyup.enter="handleQuery"
>
{{ tag }}
</el-tag>
</template>
<template #actionbtns_default="{ row }">
<!-- 操作修改 -->
<XTextButton
preIcon="ep:edit"
:title="t('action.edit')"
v-hasPermi="['system:sensitive-word:update']"
@click="handleUpdate(row.id)"
/>
<!-- 操作详情 -->
<XTextButton
preIcon="ep:view"
:title="t('action.detail')"
v-hasPermi="['system:sensitive-word:update']"
@click="handleDetail(row.id)"
/>
<!-- 操作删除 -->
<XTextButton
preIcon="ep:delete"
:title="t('action.del')"
v-hasPermi="['system:sensitive-word:delete']"
@click="deleteData(row.id)"
/>
</template>
</XTable>
</ContentWrap>
<XModal v-model="dialogVisible" :title="dialogTitle">
<!-- 对话框(添加 / 修改) -->
<Form
v-if="['create', 'update'].includes(actionType)"
:schema="allSchemas.formSchema"
:rules="rules"
ref="formRef"
>
<template #tags="form">
<el-select v-model="form['tags']" multiple placeholder="请选择">
<el-option v-for="item in tagsOptions" :key="item" :label="item" :value="item" />
<el-option v-for="tag in tags" :key="tag" :label="tag" :value="tag" />
</el-select>
</template>
</Form>
<!-- 对话框(详情) -->
<Descriptions
v-if="actionType === 'detail'"
:schema="allSchemas.detailSchema"
:data="detailData"
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择启用状态" clearable>
<el-option
v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="parseInt(dict.value)"
:label="dict.label"
:value="parseInt(dict.value)"
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button
type="primary"
@click="openModal('create')"
v-hasPermi="['system:sensitive-word:create']"
>
<template #tags="{ row }">
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['system:sensitive-word:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</content-wrap>
<!-- 列表 -->
<content-wrap>
<el-table v-loading="loading" :data="list">
<el-table-column label="编号" align="center" prop="id" />
<el-table-column label="敏感词" align="center" prop="name" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="描述" align="center" prop="description" />
<el-table-column label="标签" align="center" prop="tags">
<template #default="scope">
<el-tag
:disable-transitions="true"
:key="index"
v-for="(tag, index) in row.tags"
v-for="(tag, index) in scope.row.tags"
:index="index"
class="mr-5px"
>
{{ tag }}
</el-tag>
&nbsp; &nbsp;
</template>
</Descriptions>
<!-- 操作按钮 -->
<template #footer>
<!-- 按钮保存 -->
<XButton
v-if="['create', 'update'].includes(actionType)"
type="primary"
:title="t('action.save')"
:loading="actionLoading"
@click="submitForm()"
</el-table-column>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
width="180"
:formatter="dateFormatter"
/>
<!-- 按钮关闭 -->
<XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openModal('update', scope.row.id)"
v-hasPermi="['infra:config:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['infra:config:delete']"
>
删除
</el-button>
</template>
</XModal>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</content-wrap>
<!-- 表单弹窗添加/修改 -->
<config-form ref="modalRef" @success="getList" />
</template>
<script setup lang="ts" name="SensitiveWord">
import type { FormExpose } from '@/components/Form'
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import * as SensitiveWordApi from '@/api/system/sensitiveWord'
import { rules, allSchemas } from './sensitiveWord.data'
const { t } = useI18n() //
import ConfigForm from './form.vue' // TODO @blue-syd
const message = useMessage() //
//
const [registerTable, { reload, deleteData, exportList }] = useXTable({
allSchemas: allSchemas,
getListApi: SensitiveWordApi.getSensitiveWordPageApi,
deleteApi: SensitiveWordApi.deleteSensitiveWordApi,
exportListApi: SensitiveWordApi.exportSensitiveWordApi
const { t } = useI18n() //
const loading = ref(true) //
const total = ref(0) //
const list = ref([]) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
name: undefined,
tag: undefined,
status: undefined,
createTime: []
})
const actionLoading = ref(false) //
const actionType = ref('') //
const dialogVisible = ref(false) //
const dialogTitle = ref('edit') //
const formRef = ref<FormExpose>() // Ref
const detailData = ref() // Ref
const queryFormRef = ref() //
const exportLoading = ref(false) //
const tags = ref([])
//
const tagsOptions = ref()
const getTags = async () => {
const res = await SensitiveWordApi.getSensitiveWordTagsApi()
tagsOptions.value = res
}
//
const setDialogTile = (type: string) => {
dialogTitle.value = t('action.' + type)
actionType.value = type
dialogVisible.value = true
}
//
const handleCreate = () => {
setDialogTile('create')
}
//
const handleUpdate = async (rowId: number) => {
setDialogTile('update')
//
const res = await SensitiveWordApi.getSensitiveWordApi(rowId)
unref(formRef)?.setValues(res)
}
//
const handleDetail = async (rowId: number) => {
setDialogTile('detail')
const res = await SensitiveWordApi.getSensitiveWordApi(rowId)
detailData.value = res
}
//
const submitForm = async () => {
const elForm = unref(formRef)?.getElFormRef()
if (!elForm) return
elForm.validate(async (valid) => {
if (valid) {
actionLoading.value = true
//
/** 查询参数列表 */
const getList = async () => {
loading.value = true
try {
const data = unref(formRef)?.formModel as SensitiveWordApi.SensitiveWordVO
if (actionType.value === 'create') {
await SensitiveWordApi.createSensitiveWordApi(data)
message.success(t('common.createSuccess'))
} else {
await SensitiveWordApi.updateSensitiveWordApi(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
const data = await SensitiveWordApi.getSensitiveWordPageApi(queryParams) // TODO @blue-syd API
list.value = data.list
total.value = data.total
} finally {
actionLoading.value = false
//
await reload()
loading.value = false
}
}
})
}
// ========== ==========
onMounted(async () => {
await getTags()
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const modalRef = ref()
const openModal = (type: string, id?: number) => {
modalRef.value.openModal(type, id)
}
// TODO @blue-syd http://dashboard.yudao.iocoder.cn/system/sensitive-word
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await SensitiveWordApi.deleteSensitiveWordApi(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await SensitiveWordApi.exportSensitiveWordApi(queryParams) // TODO @blue-syd API
download.excel(data, '敏感词.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 获得 Tag 标签列表 */
const getTags = async () => {
tags.value = await SensitiveWordApi.getSensitiveWordTagsApi() // TODO @blue-syd API
}
/** 初始化 **/
onMounted(() => {
getTags()
getList()
})
</script>

View File

@ -1,74 +0,0 @@
import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
const { t } = useI18n() // 国际化
// 表单校验
export const rules = reactive({
name: [required],
tags: [required]
})
// CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id',
primaryType: 'id',
primaryTitle: '敏感词编号',
action: true,
columns: [
{
title: '敏感词',
field: 'name',
isSearch: true
},
{
title: '标签',
field: 'tag',
isTable: false,
isForm: false,
isDetail: false,
isSearch: true
},
{
title: '标签',
field: 'tags',
table: {
slots: {
default: 'tags_default'
}
}
},
{
title: t('common.status'),
field: 'status',
dictType: DICT_TYPE.COMMON_STATUS,
dictClass: 'number',
isSearch: true
},
{
title: '描述',
field: 'description',
form: {
component: 'Input',
componentProps: {
type: 'textarea',
rows: 4
},
colProps: {
span: 24
}
}
},
{
title: t('common.createTime'),
field: 'createTime',
formatter: 'formatDate',
isForm: false,
search: {
show: true,
itemRender: {
name: 'XDataTimePicker'
}
}
}
]
})
export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

View File

@ -273,7 +273,7 @@ import { rules, allSchemas } from './user.data'
import * as UserApi from '@/api/system/user'
import { listSimpleDeptApi } from '@/api/system/dept'
import { listSimpleRolesApi } from '@/api/system/role'
import { listSimplePostsApi, PostVO } from '@/api/system/post'
import { getSimplePostList, PostVO } from '@/api/system/post'
import {
aassignUserRoleApi,
listUserRolesApi,
@ -329,7 +329,7 @@ const postOptions = ref<PostVO[]>([]) //岗位列表
//
const getPostOptions = async () => {
const res = await listSimplePostsApi()
const res = await getSimplePostList()
postOptions.value.push(...res)
}
const dataFormater = (val) => {