xingyu4j пре 2 година
родитељ
комит
120417b792

+ 21 - 2
yudao-ui-admin-vue3/src/api/system/menu/index.ts

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

+ 0 - 15
yudao-ui-admin-vue3/src/api/system/menu/types.ts

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

+ 18 - 2
yudao-ui-admin-vue3/src/api/system/notice/index.ts

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

+ 0 - 12
yudao-ui-admin-vue3/src/api/system/notice/types.ts

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

+ 22 - 2
yudao-ui-admin-vue3/src/api/system/post/index.ts

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

+ 0 - 24
yudao-ui-admin-vue3/src/api/system/post/types.ts

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

+ 1 - 1
yudao-ui-admin-vue3/src/components/DictTag/src/DictTag.vue

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

+ 12 - 0
yudao-ui-admin-vue3/src/hooks/web/useMessage.ts

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

+ 20 - 0
yudao-ui-admin-vue3/src/hooks/web/useVxeGrid.ts

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

+ 1 - 1
yudao-ui-admin-vue3/src/store/modules/dict.ts

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

+ 3 - 3
yudao-ui-admin-vue3/src/utils/dict.ts

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

+ 39 - 32
yudao-ui-admin-vue3/src/views/system/menu/index.vue

@@ -42,7 +42,6 @@
       </template>
     </vxe-toolbar>
     <!-- 列表 -->
-    <!-- TODO 星语:是不是也搞成 grid 会好点,后续代码就统一走 grid 风格? -->
     <vxe-table
       show-overflow
       keep-source
@@ -84,14 +83,14 @@
             preIcon="ep:edit"
             :title="t('action.edit')"
             v-hasPermi="['system:menu:update']"
-            @click="handleUpdate(row)"
+            @click="handleUpdate(row.id)"
           />
           <!-- 操作:删除 -->
           <XTextButton
             preIcon="ep:delete"
             :title="t('action.del')"
             v-hasPermi="['system:menu:delete']"
-            @click="handleDelete(row)"
+            @click="handleDelete(row.id)"
           />
         </template>
       </vxe-column>
@@ -102,6 +101,7 @@
     <template #default>
       <!-- 对话框(添加 / 修改) -->
       <el-form
+        ref="formRef"
         :model="menuForm"
         :rules="rules"
         :inline="true"
@@ -254,7 +254,6 @@
 import { onMounted, reactive, ref } from 'vue'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useMessage } from '@/hooks/web/useMessage'
-// TODO @星语:是不是 'element-plus' 和 '@/components/Tooltip' 和 '@/components/Icon' 全局直接引入
 import {
   ElRow,
   ElCol,
@@ -266,14 +265,14 @@ import {
   ElTreeSelect,
   ElOption,
   ElRadioGroup,
-  ElRadioButton
+  ElRadioButton,
+  FormInstance
 } from 'element-plus'
 import { Tooltip } from '@/components/Tooltip'
 import { IconSelect } from '@/components/Icon'
 import { VxeTableInstance } from 'vxe-table'
 // 业务相关的 import
 import * as MenuApi from '@/api/system/menu'
-import { MenuVO } from '@/api/system/menu/types'
 import { required } from '@/utils/formRules.js'
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants'
@@ -291,7 +290,8 @@ const dialogTitle = ref('edit') // 弹出层标题
 const actionType = ref('') // 操作按钮的类型
 const actionLoading = ref(false) // 遮罩层
 // 新增和修改的表单值
-const menuForm = ref<MenuVO>({
+const formRef = ref<FormInstance>()
+const menuForm = ref<MenuApi.MenuVO>({
   id: 0,
   name: '',
   permission: '',
@@ -316,19 +316,12 @@ const rules = reactive({
 
 // ========== 下拉框[上级菜单] ==========
 // 下拉框[上级菜单]的配置项目
-// TODO @星语:menuProps 貌似也可以抽到全局?
 const menuProps = {
   checkStrictly: true,
   children: 'children',
   label: 'name',
   value: 'id'
 }
-// TODO @星语:Tree 可以是全局的
-interface Tree {
-  id: number
-  name: string
-  children?: Tree[] | any[]
-}
 const menuOptions = ref<any[]>([]) // 树形结构
 const getTree = async () => {
   menuOptions.value = []
@@ -339,9 +332,9 @@ const getTree = async () => {
 }
 
 // ========== 查询 ==========
-const queryParams = reactive({
-  name: null,
-  status: null
+const queryParams = reactive<MenuApi.MenuPageReqVO>({
+  name: undefined,
+  status: undefined
 })
 const getList = async () => {
   tableLoading.value = true
@@ -357,31 +350,47 @@ const handleQuery = async () => {
 
 // 重置操作
 const resetQuery = async () => {
-  queryParams.name = null
-  queryParams.status = null
+  queryParams.name = undefined
+  queryParams.status = undefined
   await getList()
 }
 
 // ========== 新增/修改 ==========
 
 // 设置标题
-const setDialogTile = (type: string) => {
+const setDialogTile = async (type: string) => {
+  await getTree()
   dialogTitle.value = t('action.' + type)
   actionType.value = type
   dialogVisible.value = true
 }
 
-// 新操作
+// 新操作
 const handleCreate = () => {
   setDialogTile('create')
-  // TODO @星语:重置表单
+  formRef.value?.resetFields()
+  menuForm.value = {
+    id: 0,
+    name: '',
+    permission: '',
+    type: SystemMenuTypeEnum.DIR,
+    sort: 1,
+    parentId: 0,
+    path: '',
+    icon: '',
+    component: '',
+    status: CommonStatusEnum.ENABLE,
+    visible: true,
+    keepAlive: true,
+    createTime: ''
+  }
 }
 
 // 修改操作
-const handleUpdate = async (row: MenuVO) => {
+const handleUpdate = async (rowId: number) => {
   setDialogTile('update')
   // 设置数据
-  const res = await MenuApi.getMenuApi(row.id)
+  const res = await MenuApi.getMenuApi(rowId)
   menuForm.value = res
 }
 
@@ -411,11 +420,11 @@ const submitForm = async () => {
       await MenuApi.updateMenuApi(menuForm.value)
       message.success(t('common.updateSuccess'))
     }
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-    await getList()
   } finally {
+    dialogVisible.value = false
     actionLoading.value = false
+    // 操作成功,重新加载列表
+    await getList()
   }
 }
 
@@ -426,9 +435,9 @@ const isExternal = (path: string) => {
 
 // ========== 删除 ==========
 // 删除操作
-const handleDelete = async (row: MenuVO) => {
-  message.confirm(t('common.delDataMessage'), t('common.confirmTitle')).then(async () => {
-    await MenuApi.deleteMenuApi(row.id)
+const handleDelete = async (rowId: number) => {
+  message.delConfirm().then(async () => {
+    await MenuApi.deleteMenuApi(rowId)
     message.success(t('common.delSuccess'))
     await getList()
   })
@@ -437,7 +446,5 @@ const handleDelete = async (row: MenuVO) => {
 // ========== 初始化 ==========
 onMounted(async () => {
   await getList()
-  // TODO @星语:这个告警解决下;是不是改成新增和修改点击的时候,去加载下好一点哈?
-  getTree()
 })
 </script>

+ 17 - 14
yudao-ui-admin-vue3/src/views/system/notice/index.vue

@@ -21,7 +21,7 @@
           preIcon="ep:view"
           :title="t('action.detail')"
           v-hasPermi="['system:notice:update']"
-          @click="handleDetail(row)"
+          @click="handleDetail(row.id)"
         />
         <XTextButton
           preIcon="ep:delete"
@@ -36,10 +36,10 @@
     <template #default>
       <!-- 对话框(添加 / 修改) -->
       <Form
+        ref="formRef"
         v-if="['create', 'update'].includes(actionType)"
         :schema="allSchemas.formSchema"
         :rules="rules"
-        ref="formRef"
       />
       <!-- 对话框(详情) -->
       <Descriptions
@@ -63,30 +63,31 @@
 </template>
 <script setup lang="ts">
 import { ref, unref } from 'vue'
-import * as NoticeApi from '@/api/system/notice'
-import { NoticeVO } from '@/api/system/notice/types'
-import { rules, allSchemas } from './notice.data'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useMessage } from '@/hooks/web/useMessage'
 import { useVxeGrid } from '@/hooks/web/useVxeGrid'
 import { VxeGridInstance } from 'vxe-table'
 import { FormExpose } from '@/components/Form'
 
+import * as NoticeApi from '@/api/system/notice'
+import { rules, allSchemas } from './notice.data'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
+
+const xGrid = ref<VxeGridInstance>() // grid Ref
+const { gridOptions } = useVxeGrid<NoticeApi.NoticeVO>({
+  allSchemas: allSchemas,
+  getListApi: NoticeApi.getNoticePageApi
+})
+
 const dialogVisible = ref(false) // 是否显示弹出层
 const dialogTitle = ref('edit') // 弹出层标题
 const actionType = ref('') // 操作按钮的类型
 const actionLoading = ref(false) // 按钮Loading
-const xGrid = ref<VxeGridInstance>() // grid Ref
 const formRef = ref<FormExpose>() // 表单 Ref
 const detailRef = ref() // 详情 Ref
 
-const { gridOptions } = useVxeGrid<NoticeVO>({
-  allSchemas: allSchemas,
-  getListApi: NoticeApi.getNoticePageApi
-})
-
 // 设置标题
 const setDialogTile = (type: string) => {
   dialogTitle.value = t('action.' + type)
@@ -110,9 +111,11 @@ const handleUpdate = async (rowId: number) => {
 }
 
 // 详情操作
-const handleDetail = (row: NoticeVO) => {
+const handleDetail = async (rowId: number) => {
   setDialogTile('detail')
-  detailRef.value = row
+  // 设置数据
+  const res = await NoticeApi.getNoticeApi(rowId)
+  detailRef.value = res
 }
 
 // 删除操作
@@ -137,7 +140,7 @@ const submitForm = async () => {
       actionLoading.value = true
       // 提交请求
       try {
-        const data = unref(formRef)?.formModel as NoticeVO
+        const data = unref(formRef)?.formModel as NoticeApi.NoticeVO
         if (actionType.value === 'create') {
           await NoticeApi.createNoticeApi(data)
           message.success(t('common.createSuccess'))

+ 1 - 2
yudao-ui-admin-vue3/src/views/system/notice/notice.data.ts

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

+ 25 - 9
yudao-ui-admin-vue3/src/views/system/post/index.vue

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

+ 10 - 0
yudao-ui-admin-vue3/types/global.d.ts

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