diff --git a/src/api/bpm/userGroup/index.ts b/src/api/bpm/userGroup/index.ts index 88ee9619..c3399f27 100644 --- a/src/api/bpm/userGroup/index.ts +++ b/src/api/bpm/userGroup/index.ts @@ -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' }) } diff --git a/src/api/infra/apiErrorLog/index.ts b/src/api/infra/apiErrorLog/index.ts index 06515c36..779cfd61 100644 --- a/src/api/infra/apiErrorLog/index.ts +++ b/src/api/infra/apiErrorLog/index.ts @@ -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 diff --git a/src/api/system/dict/dict.data.ts b/src/api/system/dict/dict.data.ts index fd97a2dc..6d981326 100644 --- a/src/api/system/dict/dict.data.ts +++ b/src/api/system/dict/dict.data.ts @@ -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 }) } diff --git a/src/api/system/dict/dict.type.ts b/src/api/system/dict/dict.type.ts index 22e6411e..0d9faeb2 100644 --- a/src/api/system/dict/dict.type.ts +++ b/src/api/system/dict/dict.type.ts @@ -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 }) } diff --git a/src/api/system/dict/types.ts b/src/api/system/dict/types.ts deleted file mode 100644 index b630dccb..00000000 --- a/src/api/system/dict/types.ts +++ /dev/null @@ -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 -} diff --git a/src/api/system/errorCode/index.ts b/src/api/system/errorCode/index.ts index 0e000794..65eabd3a 100644 --- a/src/api/system/errorCode/index.ts +++ b/src/api/system/errorCode/index.ts @@ -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 diff --git a/src/api/system/oauth2/token.ts b/src/api/system/oauth2/token.ts index dc7c44f5..8e9dca1e 100644 --- a/src/api/system/oauth2/token.ts +++ b/src/api/system/oauth2/token.ts @@ -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 }) } diff --git a/src/api/system/post/index.ts b/src/api/system/post/index.ts index 9e2540f0..98df227f 100644 --- a/src/api/system/post/index.ts +++ b/src/api/system/post/index.ts @@ -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 }) } diff --git a/src/api/system/user/index.ts b/src/api/system/user/index.ts index e505921d..3cc0a84d 100644 --- a/src/api/system/user/index.ts +++ b/src/api/system/user/index.ts @@ -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' }) } diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index 43375961..d5970267 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -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, diff --git a/src/store/modules/dict.ts b/src/store/modules/dict.ts index 4e9ab39c..2d393e43 100644 --- a/src/store/modules/dict.ts +++ b/src/store/modules/dict.ts @@ -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) => { diff --git a/src/types/auto-components.d.ts b/src/types/auto-components.d.ts index be71517c..6284d4dc 100644 --- a/src/types/auto-components.d.ts +++ b/src/types/auto-components.d.ts @@ -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'] diff --git a/src/views/bpm/group/UserGroupForm.vue b/src/views/bpm/group/UserGroupForm.vue new file mode 100644 index 00000000..05d646d2 --- /dev/null +++ b/src/views/bpm/group/UserGroupForm.vue @@ -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) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +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> diff --git a/src/views/bpm/group/group.data.ts b/src/views/bpm/group/group.data.ts deleted file mode 100644 index 613a7290..00000000 --- a/src/views/bpm/group/group.data.ts +++ /dev/null @@ -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) diff --git a/src/views/bpm/group/index.vue b/src/views/bpm/group/index.vue index b0f08516..5829ebad 100644 --- a/src/views/bpm/group/index.vue +++ b/src/views/bpm/group/index.vue @@ -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) }} - </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) }} - </span> - </template> - </Descriptions> - <!-- 操作按钮 --> - <template #footer> - <!-- 按钮:保存 --> - <XButton - v-if="['create', 'update'].includes(actionType)" - type="primary" - :title="t('action.save')" - :loading="actionLoading" - @click="submitForm" + <!-- 列表 --> + <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> + </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> + </el-table-column> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" /> - <!-- 按钮:关闭 --> - <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" /> - </template> - </XModal> + <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 - } +/** 查询参数列表 */ +const getList = async () => { + loading.value = true + try { + const data = await UserGroupApi.getUserGroupPage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false } - 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 handleQuery = () => { + queryParams.pageNo = 1 + getList() } -// 新增操作 -const handleCreate = () => { - setDialogTile('create') +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() } -// 修改操作 -const handleUpdate = async (rowId: number) => { - setDialogTile('update') - // 设置数据 - const res = await UserGroupApi.getUserGroupApi(rowId) - unref(formRef)?.setValues(res) +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) } -// 详情操作 -const handleDetail = async (rowId: number) => { - setDialogTile('detail') - detailData.value = await UserGroupApi.getUserGroupApi(rowId) +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await UserGroupApi.deleteUserGroup(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} } -// 提交按钮 -const submitForm = async () => { - const elForm = unref(formRef)?.getElFormRef() - if (!elForm) return - elForm.validate(async (valid) => { - if (valid) { - actionLoading.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 - } finally { - actionLoading.value = false - // 刷新列表 - await reload() - } - } - }) -} - -// ========== 初始化 ========== -onMounted(() => { - getListSimpleUsersApi().then((data) => { - users.value = data - }) +/** 初始化 **/ +onMounted(async () => { + await getList() + // 加载用户列表 + userList.value = await UserApi.getSimpleUserList() }) </script> diff --git a/src/views/bpm/processInstance/detail.vue b/src/views/bpm/processInstance/detail.vue index b6d52a4c..7d159673 100644 --- a/src/views/bpm/processInstance/detail.vue +++ b/src/views/bpm/processInstance/detail.vue @@ -378,7 +378,7 @@ onMounted(() => { // 加载详情 getDetail() // 加载用户的列表 - UserApi.getListSimpleUsersApi().then((data) => { + UserApi.getSimpleUserList().then((data) => { userOptions.value.push(...data) }) }) diff --git a/src/views/bpm/taskAssignRule/index.vue b/src/views/bpm/taskAssignRule/index.vue index 012e6f68..8db7b578 100644 --- a/src/views/bpm/taskAssignRule/index.vue +++ b/src/views/bpm/taskAssignRule/index.vue @@ -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) { diff --git a/src/views/infra/apiErrorLog/apiErrorLog.data.ts b/src/views/infra/apiErrorLog/apiErrorLog.data.ts deleted file mode 100644 index a539c167..00000000 --- a/src/views/infra/apiErrorLog/apiErrorLog.data.ts +++ /dev/null @@ -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) diff --git a/src/views/infra/apiErrorLog/detail.vue b/src/views/infra/apiErrorLog/detail.vue new file mode 100644 index 00000000..9ede0f1b --- /dev/null +++ b/src/views/infra/apiErrorLog/detail.vue @@ -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> diff --git a/src/views/infra/apiErrorLog/index.vue b/src/views/infra/apiErrorLog/index.vue index 4193351a..664546cb 100644 --- a/src/views/infra/apiErrorLog/index.vue +++ b/src/views/infra/apiErrorLog/index.vue @@ -1,99 +1,242 @@ <template> - <ContentWrap> - <!-- 列表 --> - <XTable @register="registerTable"> - <!-- 操作:导出 --> - <template #toolbar_buttons> - <XButton - type="warning" - preIcon="ep:download" - :title="t('action.export')" - @click="exportList('错误数据.xls')" + <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" /> - </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')" - v-hasPermi="['infra:api-access-log:query']" - @click="handleDetail(row)" + </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" /> - <XTextButton - preIcon="ep:cpu" - title="已处理" - v-if="row.processStatus === InfraApiErrorLogProcessStatusEnum.INIT" - v-hasPermi="['infra:api-error-log:update-status']" - @click="handleProcessClick(row, InfraApiErrorLogProcessStatusEnum.DONE, '已处理')" + </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" /> - <XTextButton - preIcon="ep:mute-notification" - title="已忽略" - v-if="row.processStatus === InfraApiErrorLogProcessStatusEnum.INIT" - v-hasPermi="['infra:api-error-log:update-status']" - @click="handleProcessClick(row, InfraApiErrorLogProcessStatusEnum.IGNORE, '已忽略')" - /> - </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> + </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> + <!-- 列表 --> + <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> + </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']" + > + 详细 + </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']" + > + 已处理 + </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']" + > + 已忽略 + </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> + + <!-- 表单弹窗:详情 --> + <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 () => { - // 刷新列表 - await reload() - }) - .catch(() => {}) +/** 重置按钮操作 */ +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 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> diff --git a/src/views/infra/codegen/components/CloumInfoForm.vue b/src/views/infra/codegen/components/CloumInfoForm.vue index 0b6ea697..5a60c546 100644 --- a/src/views/infra/codegen/components/CloumInfoForm.vue +++ b/src/views/infra/codegen/components/CloumInfoForm.vue @@ -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 () => { diff --git a/src/views/infra/config/index.vue b/src/views/infra/config/index.vue index 11fc8fe0..fcc3c12c 100644 --- a/src/views/infra/config/index.vue +++ b/src/views/infra/config/index.vue @@ -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> diff --git a/src/views/system/dept/index.vue b/src/views/system/dept/index.vue index d5f54d19..de561a1f 100644 --- a/src/views/system/dept/index.vue +++ b/src/views/system/dept/index.vue @@ -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 } diff --git a/src/views/system/dict/data.form.vue b/src/views/system/dict/data.form.vue new file mode 100644 index 00000000..c0b70b8e --- /dev/null +++ b/src/views/system/dict/data.form.vue @@ -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) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +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> diff --git a/src/views/system/dict/data.vue b/src/views/system/dict/data.vue new file mode 100644 index 00000000..7b159481 --- /dev/null +++ b/src/views/system/dict/data.vue @@ -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> diff --git a/src/views/system/dict/dict.data.ts b/src/views/system/dict/dict.data.ts deleted file mode 100644 index cdfe4538..00000000 --- a/src/views/system/dict/dict.data.ts +++ /dev/null @@ -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) diff --git a/src/views/system/dict/dict.type.ts b/src/views/system/dict/dict.type.ts deleted file mode 100644 index 73b5a021..00000000 --- a/src/views/system/dict/dict.type.ts +++ /dev/null @@ -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) diff --git a/src/views/system/dict/form.vue b/src/views/system/dict/form.vue new file mode 100644 index 00000000..af02c597 --- /dev/null +++ b/src/views/system/dict/form.vue @@ -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) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +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> diff --git a/src/views/system/dict/index.vue b/src/views/system/dict/index.vue index 713fde97..4e304bf5 100644 --- a/src/views/system/dict/index.vue +++ b/src/views/system/dict/index.vue @@ -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()" + <!-- 搜索工作栏 --> + <content-wrap> + <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="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> - <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" - > - <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-table-column> + <el-table-column label="备注" align="center" prop="remark" /> + <el-table-column + label="创建时间" + :formatter="dateFormatter" + align="center" + prop="createTime" + width="180" /> - <!-- 操作按钮 --> - <template #footer> - <XButton - v-if="['typeCreate', 'typeUpdate'].includes(actionType)" - 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" /> - </template> - </XModal> - </div> + <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> + <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> + </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 queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 + +/** 查询字典类型列表 */ +const getList = async () => { + loading.value = true + try { + const data = await DictTypeApi.getDictTypePage(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 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() }) -// ========== 字典分类列表相关 ========== -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 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 -} - -// 同步dictTypeValue到form 否则导致表单验证不通过 -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 - // 提交请求 - 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 - } finally { - actionLoading.value = false - typeGetList() - } - } - }) -} -const submitDataForm = async () => { - const elForm = unref(dataFormRef)?.getElFormRef() - if (!elForm) return - elForm.validate(async (valid) => { - if (valid) { - actionLoading.value = true - // 提交请求 - 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() - } - } - }) -} </script> diff --git a/src/views/system/errorCode/errorCode.data.ts b/src/views/system/errorCode/errorCode.data.ts deleted file mode 100644 index 4736068b..00000000 --- a/src/views/system/errorCode/errorCode.data.ts +++ /dev/null @@ -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) diff --git a/src/views/system/errorCode/form.vue b/src/views/system/errorCode/form.vue new file mode 100644 index 00000000..9544c6ab --- /dev/null +++ b/src/views/system/errorCode/form.vue @@ -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) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +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> diff --git a/src/views/system/errorCode/index.vue b/src/views/system/errorCode/index.vue index 1ff3d103..fc152903 100644 --- a/src/views/system/errorCode/index.vue +++ b/src/views/system/errorCode/index.vue @@ -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()" - /> - </template> - <template #actionbtns_default="{ row }"> - <!-- 操作:修改 --> - <XTextButton - preIcon="ep:edit" - :title="t('action.edit')" - v-hasPermi="['system:error-code:update']" - @click="handleUpdate(row.id)" - /> - <!-- 操作:详情 --> - <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)" - type="primary" - :title="t('action.save')" - :loading="actionLoading" - @click="submitForm()" + > + <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> + </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" /> - <!-- 按钮:关闭 --> - <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" /> - </template> - </XModal> + <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> + <template #default="scope"> + <el-button + link + type="primary" + @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> + </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 getList = async () => { + loading.value = true + // 执行查询 + try { + const data = await ErrorCodeApi.getErrorCodePageApi(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } } -// 新增操作 -const handleCreate = () => { - setDialogTile('create') +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() } -// 修改操作 -const handleUpdate = async (rowId: number) => { - setDialogTile('update') - // 设置数据 - const res = await ErrorCodeApi.getErrorCodeApi(rowId) - unref(formRef)?.setValues(res) +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() } -// 详情操作 -const handleDetail = async (rowId: number) => { - setDialogTile('detail') - // 设置数据 - const res = await ErrorCodeApi.getErrorCodeApi(rowId) - detailData.value = res +/** 添加/修改操作 */ +const modalRef = ref() +const openModal = (type: string, id?: number) => { + modalRef.value.openModal(type, id) } -// 提交新增/修改的表单 -const submitForm = async () => { - const elForm = unref(formRef)?.getElFormRef() - if (!elForm) return - elForm.validate(async (valid) => { - if (valid) { - actionLoading.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 - } finally { - actionLoading.value = false - // 刷新列表 - await reload() - } - } - }) +/** 删除按钮操作 */ +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> diff --git a/src/views/system/notice/index.vue b/src/views/system/notice/index.vue index e36f3aac..65076f9f 100644 --- a/src/views/system/notice/index.vue +++ b/src/views/system/notice/index.vue @@ -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)" diff --git a/src/views/system/notify/template/index.vue b/src/views/system/notify/template/index.vue index 4ec16a0a..c4113924 100644 --- a/src/views/system/notify/template/index.vue +++ b/src/views/system/notify/template/index.vue @@ -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 }) }) diff --git a/src/views/system/oauth2/token/index.vue b/src/views/system/oauth2/token/index.vue index f0dfbd9c..7e8aca22 100644 --- a/src/views/system/oauth2/token/index.vue +++ b/src/views/system/oauth2/token/index.vue @@ -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" /> - </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> + </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> + </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> + </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) - message.success(t('common.success')) - }) - .finally(async () => { - // 刷新列表 - await reload() - }) +/** 搜索按钮操作 */ +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')) + // 刷新列表 + await getList() + } catch {} +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) </script> diff --git a/src/views/system/oauth2/token/token.data.ts b/src/views/system/oauth2/token/token.data.ts deleted file mode 100644 index 8a0e8486..00000000 --- a/src/views/system/oauth2/token/token.data.ts +++ /dev/null @@ -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) diff --git a/src/views/system/operatelog/index.vue b/src/views/system/operatelog/index.vue index f9667912..d7490ba8 100644 --- a/src/views/system/operatelog/index.vue +++ b/src/views/system/operatelog/index.vue @@ -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> diff --git a/src/views/system/post/PostForm.vue b/src/views/system/post/PostForm.vue new file mode 100644 index 00000000..14aa9651 --- /dev/null +++ b/src/views/system/post/PostForm.vue @@ -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) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +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> diff --git a/src/views/system/post/form.vue b/src/views/system/post/form.vue deleted file mode 100644 index 065aecaf..00000000 --- a/src/views/system/post/form.vue +++ /dev/null @@ -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> diff --git a/src/views/system/post/index.vue b/src/views/system/post/index.vue index c5a13e1e..03e491d0 100644 --- a/src/views/system/post/index.vue +++ b/src/views/system/post/index.vue @@ -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> diff --git a/src/views/system/post/post.data.ts b/src/views/system/post/post.data.ts deleted file mode 100644 index 4926bcc6..00000000 --- a/src/views/system/post/post.data.ts +++ /dev/null @@ -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) diff --git a/src/views/system/sensitiveWord/form.vue b/src/views/system/sensitiveWord/form.vue new file mode 100644 index 00000000..1dccd656 --- /dev/null +++ b/src/views/system/sensitiveWord/form.vue @@ -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) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +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> diff --git a/src/views/system/sensitiveWord/index.vue b/src/views/system/sensitiveWord/index.vue index c3de895d..93ea29f1 100644 --- a/src/views/system/sensitiveWord/index.vue +++ b/src/views/system/sensitiveWord/index.vue @@ -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" - > - <template #tags="{ 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="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']" > - {{ tag }} - </el-tag> - </template> - </Descriptions> - <!-- 操作按钮 --> - <template #footer> - <!-- 按钮:保存 --> - <XButton - v-if="['create', 'update'].includes(actionType)" - type="primary" - :title="t('action.save')" - :loading="actionLoading" - @click="submitForm()" + <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 scope.row.tags" + :index="index" + class="mr-5px" + > + {{ tag }} + </el-tag> + + </template> + </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" /> - </template> - </XModal> + <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> + </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 getList = async () => { + loading.value = true + try { + const data = await SensitiveWordApi.getSensitiveWordPageApi(queryParams) // TODO @blue-syd:去掉 API 后缀哈 + 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) +} + +// 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 () => { - const res = await SensitiveWordApi.getSensitiveWordTagsApi() - tagsOptions.value = res + tags.value = await SensitiveWordApi.getSensitiveWordTagsApi() // TODO @blue-syd:去掉 API 后缀哈 } -// 设置标题 -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 - // 提交请求 - 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 - } finally { - actionLoading.value = false - // 刷新列表 - await reload() - } - } - }) -} - -// ========== 初始化 ========== -onMounted(async () => { - await getTags() +/** 初始化 **/ +onMounted(() => { + getTags() + getList() }) </script> diff --git a/src/views/system/sensitiveWord/sensitiveWord.data.ts b/src/views/system/sensitiveWord/sensitiveWord.data.ts deleted file mode 100644 index d21bb94c..00000000 --- a/src/views/system/sensitiveWord/sensitiveWord.data.ts +++ /dev/null @@ -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) diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue index 2f9ba9b0..9bb50930 100644 --- a/src/views/system/user/index.vue +++ b/src/views/system/user/index.vue @@ -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) => {