23 Commits 6376fe6e1f ... 15f86c553d

Author SHA1 Message Date
  jzy 15f86c553d Merge branch 'master' into jzy 3 months ago
  tongshangming 66f5cd04a6 更新core版本 3 months ago
  tongshangming f09e2815d8 合并分支 3 months ago
  lzt 15eb5e887a 调整form标题显示 3 months ago
  lzt ab39a7c819 Merge branch 'master' into lzt 3 months ago
  lzt e561badc9c 新增表单标题组件 3 months ago
  tongshangming ab1ccc0e66 更新版本号 4 months ago
  tongshangming b3091310c5 修改工具栏默认配置 4 months ago
  tongshangming 9c93993213 core 升级 4 months ago
  tongshangming 9c152589fb 更新版本号 4 months ago
  tongshangming 47d40bc4d0 注释修改 4 months ago
  tongshangming 34617bb9a7 动态配置菜单搜索显示 4 months ago
  tongshangming 5a7f1e2209 细节优化 4 months ago
  tongshangming 2dfa692789 细节优化 4 months ago
  tongshangming 48411dd105 升级vxeTable至4.7 4 months ago
  tongshangming 8a5bd41fd9 优化globalTabs组件 4 months ago
  tongshangming 88c92a4aeb 更改路由模式为hash模式 4 months ago
  tongshangming 62d13210e7 更新字典页面 4 months ago
  tongshangming 68ddc8cb5b @fskj-admin/core升级至1.3.9 4 months ago
  tongshangming c1a80baf17 修改全局配置 5 months ago
  tongshangming c9eca99ff5 删除oss相关文件 5 months ago
  tongshangming db351b794b 更新@fskj-admin/core 5 months ago
  tongshangming fe3ef12493 basicFormItem增加formItemProps属性 5 months ago

+ 30 - 28
package.json

@@ -1,6 +1,6 @@
 {
   "name": "fs-admin",
-  "version": "2.4.0",
+  "version": "2.5.1",
   "type": "module",
   "scripts": {
     "dev": "vite --host",
@@ -16,57 +16,59 @@
   "dependencies": {
     "@amap/amap-jsapi-loader": "^1.0.1",
     "@element-plus/icons-vue": "^2.3.1",
-    "@fskj-admin/core": "^1.3.4",
+    "@fskj-admin/core": "^1.4.13",
     "@fskj-admin/micro": "^0.1.0",
     "@icon-park/vue-next": "^1.4.2",
-    "@sentry/vue": "^8.9.2",
-    "@vueuse/core": "^10.11.0",
+    "@vueuse/core": "^10.11.1",
+    "@vxe-ui/plugin-render-element": "^4.0.5",
     "@wangeditor/editor": "^5.1.23",
     "@wangeditor/editor-for-vue": "^5.1.12",
-    "axios": "^1.7.2",
-    "dayjs": "^1.11.11",
-    "element-plus": "^2.7.6",
+    "axios": "^1.7.4",
+    "dayjs": "^1.11.12",
+    "element-plus": "^2.8.0",
     "exceljs": "^4.4.0",
     "html2canvas": "^1.4.1",
     "nprogress": "^0.2.0",
-    "pinia": "^2.1.7",
+    "pinia": "^2.2.1",
     "splitpanes": "^3.1.5",
-    "vue": "^3.4.29",
-    "vue-cropper": "^1.1.3",
-    "vue-router": "^4.3.3",
-    "vxe-table": "~4.6.17",
+    "vue": "^3.4.38",
+    "vue-cropper": "^1.1.4",
+    "vue-router": "^4.4.3",
+    "vxe-pc-ui": "^4.0.95",
+    "vxe-table": "^4.7.65",
     "wujie-vue3": "^1.0.22",
-    "xe-utils": "^3.5.27"
+    "xe-utils": "^3.5.30"
   },
   "devDependencies": {
-    "@iconify-json/ep": "^1.1.15",
-    "@rushstack/eslint-patch": "^1.10.3",
-    "@sentry/vite-plugin": "^2.18.0",
+    "@iconify-json/ep": "^1.1.16",
+    "@rushstack/eslint-patch": "^1.10.4",
+    "@sentry/vite-plugin": "^2.22.2",
     "@tsconfig/node20": "^20.1.4",
-    "@types/node": "^20.14.5",
+    "@types/node": "^20.14.15",
     "@types/nprogress": "^0.2.3",
     "@types/qs": "^6.9.15",
-    "@vitejs/plugin-vue": "^5.0.5",
+    "@vitejs/plugin-vue": "^5.1.2",
     "@vitejs/plugin-vue-jsx": "^3.1.0",
     "@vue/eslint-config-prettier": "^9.0.0",
     "@vue/eslint-config-typescript": "^12.0.0",
     "@vue/tsconfig": "^0.5.1",
     "eslint": "^8.57.0",
-    "eslint-plugin-vue": "^9.26.0",
+    "eslint-plugin-vue": "^9.27.0",
     "npm-run-all": "^4.1.5",
     "plop": "^4.0.1",
-    "prettier": "^3.3.2",
-    "sass": "^1.77.6",
+    "prettier": "^3.3.3",
+    "sass": "^1.77.8",
     "typescript": "~5.3.3",
-    "unocss": "^0.61.0",
-    "unplugin-auto-import": "^0.17.6",
-    "unplugin-icons": "^0.19.0",
+    "unocss": "^0.61.9",
+    "unplugin-auto-import": "^0.17.8",
+    "unplugin-icons": "^0.19.2",
     "unplugin-vue-components": "^0.26.0",
-    "unplugin-vue-define-options": "^1.4.5",
-    "vite": "^5.3.1",
+    "unplugin-vue-define-options": "^1.4.9",
+    "vite": "^5.4.0",
+    "vite-plugin-lazy-import": "^1.0.7",
     "vite-plugin-style-import": "^2.0.0",
     "vite-plugin-svg-icons": "^2.0.1",
-    "vite-plugin-vue-devtools": "^7.3.1",
-    "vue-tsc": "^2.0.21"
+    "vite-plugin-vue-devtools": "^7.3.8",
+    "vue-tsc": "^2.0.29"
   }
 }

File diff suppressed because it is too large
+ 4305 - 228
pnpm-lock.yaml


+ 0 - 5
src/api/oss.ts

@@ -1,5 +0,0 @@
-import request from '@/utils/request'
-
-export function ossPolicy() {
-  return request.post('v1/oss/policy')
-}

+ 1 - 0
src/components.d.ts

@@ -21,6 +21,7 @@ declare module 'vue' {
     ElEmployees: (typeof import('./components/form/ElEmployees.vue'))['default']
     Employees: typeof import('./components/form/Employees.vue')['default']
     Exception: typeof import('./components/Exception.vue')['default']
+    FormTitle: typeof import('./components/form/FormTitle.vue')['default']
     FsCheckCard: typeof import('./components/FsCheckCard/index.vue')['default']
     FsCity: (typeof import('./components/FsCity/index.vue'))['default']
     FsCitySelect: (typeof import('./components/FsCitySelect/index.vue'))['default']

+ 7 - 4
src/components/core/GlobalHeader.vue

@@ -150,7 +150,7 @@ const handleSelect = (menu: any) => {
         </div>
       </div>
       <div class="flex items-center">
-        <el-button link @click="searchVisible = true">
+        <el-button link @click="searchVisible = true" v-if="config.showMenuSearch">
           <el-icon :size="iconSize" :fill="headerStyle.color">
             <Search />
           </el-icon>
@@ -214,7 +214,7 @@ const handleSelect = (menu: any) => {
     <GlobalSetting v-model="settingVisible"></GlobalSetting>
     <GlobalNews v-model="newsVisible"></GlobalNews>
 
-    <el-dialog v-model="searchVisible" width="600px">
+    <el-dialog title="菜单搜索" v-model="searchVisible" width="600px" class="menu-dialog" v-if="config.showMenuSearch">
       <el-autocomplete
         class="w-full"
         v-model="searchValue"
@@ -249,8 +249,8 @@ const handleSelect = (menu: any) => {
   --el-menu-bg-color: #fff;
   --el-menu-text-color: #303133;
 }
-.el-menu--horizontal {
-  border-bottom: none;
+:deep(.el-menu--horizontal) {
+  border-bottom: none !important;
 }
 .hidden {
   display: none;
@@ -261,4 +261,7 @@ const handleSelect = (menu: any) => {
   align-items: center;
   outline: none;
 }
+:deep(.el-dialog__body) {
+  height: 350px;
+}
 </style>

+ 1 - 1
src/components/core/GlobalMenu.vue

@@ -49,7 +49,7 @@ watch(
   </el-menu>
 </template>
 
-<style lang="scss">
+<style lang="scss" scoped>
 .menu-normal {
   width: var(--menu-width);
 }

+ 3 - 3
src/components/core/GlobalSetting.vue

@@ -97,15 +97,15 @@ const themeNav = computed(() => themeStore.themeNav)
 
     <el-divider>界面显示</el-divider>
     <div class="flex justify-between items-center mb-4">
-      <div>显示标签页</div>
+      <el-text>显示标签页</el-text>
       <el-switch v-model="themeStore.showTabs"></el-switch>
     </div>
     <div class="flex justify-between items-center mb-4">
-      <div>标签页持久化</div>
+      <el-text>标签页持久化</el-text>
       <el-switch v-model="themeStore.keepAliveTabs"></el-switch>
     </div>
     <div class="flex justify-between items-center">
-      <div>LOGO置于顶部</div>
+      <el-text>LOGO置于顶部</el-text>
       <el-switch v-model="themeStore.logoInHeader"></el-switch>
     </div>
   </el-drawer>

+ 6 - 7
src/components/core/GlobalTabs.vue

@@ -38,10 +38,7 @@ const findActiveIndex = (fullPath: string | number) => {
 }
 
 const setTab = (tab: Tab) => {
-  activeValue.value = tab.fullPath
-  activeIndex.value = findActiveIndex(tab.fullPath)
-
-  if (tab.name === 'login' || tabs.value.find(item => item.fullPath === tab.fullPath)) {
+  if (tab.name === 'login' || tabs.value.find(item => item.name === tab.name)) {
     return
   }
   tabs.value.push(tab)
@@ -92,9 +89,11 @@ const removeTab = (name: TabPaneName) => {
 }
 
 watch(
-  () => route.name,
+  () => route,
   to => {
-    setTab(routeToTab(router.getRoutes()?.find(item => item.name === to)))
+    setTab(routeToTab(to))
+    activeValue.value = to.fullPath
+    activeIndex.value = findActiveIndex(to.fullPath)
   },
   {
     deep: true
@@ -113,7 +112,7 @@ const findContextMenuItemIndex = (fullPath: string) => tabs.value.findIndex(item
 const openContextMenu = (e: any) => {
   const id = e.target?.offsetParent?.id || e.target?.id
   if (id) {
-    const fullPath = id.split('-')[1]
+    const fullPath = id.split('tab-')[1]
     contextMenuIndex.value = findContextMenuItemIndex(fullPath)
     left.value = e.clientX + 1
     top.value = e.clientY + 1

+ 54 - 0
src/components/form/FormTitle.vue

@@ -0,0 +1,54 @@
+<script lang="ts" setup>
+// 颜色  插槽
+import colorUtil from '@/utils/color'
+
+const props: any = withDefaults(
+  defineProps<{
+    title: string
+    type?: string
+    color?: string
+  }>(),
+  {
+    title: '标题',
+    type: 'primary'
+  }
+)
+
+const bgColor = computed(() => {
+  return props.color ? colorUtil.lighten(props.color, 0.6) : `var(--el-color-${props.type}-light-9)`
+})
+
+const titleColor = computed(() => {
+  return props.color ?? `var(--el-color-${props.type})`
+})
+</script>
+
+<template>
+  <div
+    class="w-full rounded-md py-[2px] px-[10px] font-bold"
+    :style="{
+      backgroundColor: bgColor,
+      color: titleColor
+    }"
+  >
+    <slot>
+      <span class="title pl-25px relative">{{ title }}</span>
+    </slot>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.title {
+  &::after {
+    content: '';
+    position: absolute;
+    top: 50%;
+    left: 5px;
+    transform: translate(0, -50%);
+    width: 10px;
+    height: 10px;
+    background-color: v-bind(titleColor);
+    border-radius: 50%;
+  }
+}
+</style>

+ 128 - 7
src/components/index.ts

@@ -1,21 +1,142 @@
 import type { App } from 'vue'
+// import { install } from '@icon-park/vue-next/es/all'
+import { System, Check, MenuFoldOne, MenuUnfoldOne, Logout, SettingTwo } from '@icon-park/vue-next'
+
+import ElementPlus from 'element-plus'
+import 'element-plus/dist/index.css'
+import * as ElementPlusIconsVue from '@element-plus/icons-vue'
+
+import 'xe-utils'
+import {
+  VxeIcon,
+  VxeLoading,
+  // VxeGrid,
+  VxeTooltip,
+  // VxeToolbar,
+  // VxePager,
+  // VxeForm,
+  // VxeFormItem,
+  // VxeFormGather,
+  // VxeCheckbox,
+  // VxeCheckboxGroup,
+  // VxeRadio,
+  // VxeRadioGroup,
+  // VxeRadioButton,
+  // VxeSwitch,
+  // VxeInput,
+  // VxeSelect,
+  // VxeOptgroup,
+  // VxeOption,
+  // VxeTextarea,
+  VxeButton,
+  // VxeButtonGroup,
+  VxeModal
+  // VxeDrawer,
+  // VxeList,
+  // VxePulldown
+} from 'vxe-pc-ui'
+import {
+  VxeUI,
+  VXETable,
+  VxeTable,
+  VxeColumn,
+  VxeColgroup,
+  // VxeGrid,
+  VxeToolbar
+} from 'vxe-table'
+import VxeUIPluginRenderElement from '@vxe-ui/plugin-render-element'
+import '@vxe-ui/plugin-render-element/dist/style.css'
+import 'vxe-table/styles/cssvar.scss'
+import 'vxe-pc-ui/styles/cssvar.scss'
+// 导入默认的语言
+import zhCN from 'vxe-pc-ui/lib/language/zh-CN'
+import '@/utils/tableFormat'
+
+// import WujieVue from 'wujie-vue3'
+// import * as Sentry from '@sentry/vue'
 
 const modules = import.meta.glob('./form/*.vue', { eager: true })
-import { System, Check, MenuFoldOne, MenuUnfoldOne, Logout, SettingTwo } from '@icon-park/vue-next'
 
-function registerComponent(app: App): void {
-  for (const key in modules) {
-    const name = key.replace(/^\.\/form\/|\.vue/g, '')
-    const component = (modules[key] as any).default
-    app.component('El' + name, component)
-  }
+function LazyVxeUI(app: any) {
+  app.use(VxeIcon)
+  app.use(VxeLoading)
+  // app.use(VxeVxeGrid)
+  app.use(VxeTooltip)
+  // app.use(VxeToolbar)
+  // app.use(VxePager)
+  // app.use(VxeForm)
+  // app.use(VxeFormItem)
+  // app.use(VxeFormGather)
+  // app.use(VxeCheckbox)
+  // app.use(VxeCheckboxGroup)
+  // app.use(VxeRadio)
+  // app.use(VxeRadioGroup)
+  // app.use(VxeRadioButton)
+  // app.use(VxeSwitch)
+  // app.use(VxeInput)
+  // app.use(VxeSelect)
+  // app.use(VxeOptgroup)
+  // app.use(VxeOption)
+  // app.use(VxeTextarea)
+  app.use(VxeButton)
+  // app.use(VxeButtonGroup)
+  app.use(VxeModal)
+  // app.use(VxeDrawer)
+  // app.use(VxeList)
+  // app.use(VxePulldown)
+}
+function LazyVxeTable(app: any) {
+  app.use(VxeTable)
+  app.use(VxeColumn)
+  app.use(VxeColgroup)
+  // app.use(VxeGrid)
+  app.use(VxeToolbar)
+}
 
+function registerComponent(app: App): void {
+  // icon-park
   app.component('icon-system', System)
   app.component('icon-check', Check)
   app.component('icon-menu-fold-one', MenuFoldOne)
   app.component('icon-menu-unfold-one', MenuUnfoldOne)
   app.component('icon-logout', Logout)
   app.component('icon-setting-two', SettingTwo)
+  // install(app)
+
+  // element-plus
+  app.use(ElementPlus)
+  for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
+    app.component(key, component)
+  }
+
+  // vxe-table
+  VXETable.setI18n('zh-CN', zhCN)
+  VXETable.setLanguage('zh-CN')
+  VxeUI.use(VxeUIPluginRenderElement)
+  app.use(LazyVxeUI)
+  app.use(LazyVxeTable)
+
+  // 动态注册form文件夹下的组件
+  for (const key in modules) {
+    const name = key.replace(/^\.\/form\/|\.vue/g, '')
+    const component = (modules[key] as any).default
+    app.component('El' + name, component)
+  }
+
+  // 微服务 wujie
+  // app.use(WujieVue)
+
+  // 监控 sentry
+  // import.meta.env.VITE_SENTRY_DSN &&
+  // Sentry.init({
+  //   app,
+  //   dsn: import.meta.env.VITE_SENTRY_DSN,
+  //   integrations: [Sentry.browserTracingIntegration(), Sentry.replayIntegration()],
+  //   tracesSampleRate: 1.0,
+  //   tracePropagationTargets: [],
+  //   replaysSessionSampleRate: 0.1,
+  //   replaysOnErrorSampleRate: 1.0
+  // })
 }
 
 export default registerComponent

+ 2 - 5
src/config/defaultSetting.ts

@@ -4,13 +4,10 @@ export default {
   themeColor: '#1890ff', // 主题颜色
   themeStyle: 'nav-light', // 主题样式 nav-dark  nav-light  header-dark
   themeNav: 'left', // left | top
-  uploadApi: '/file/upload', // 文件上传接口
   showTabs: true, // 显示标签页
+  showMenuSearch: true, // 显示菜单搜索
   keepAliveTabs: true, // 标签页持久化
-  logoInHeader: true, // 头部logo
-  oss: true, // 开启oss上传
-  ossHost: 'https://fskj-res.oss-cn-zhangjiakou.aliyuncs.com/', // oss域名
-  uploadSuccessCb: (res: any) => import.meta.env.VITE_BASE_PATH + res.data, // 文件上传成功回调
+  logoInHeader: true, // logo及title是否显示在头部,false时显示在左侧
   multiTenant: false, // 开启多租户
   isDynamicRouter: false // 开启动态路由即通过接口获取菜单
 }

+ 1 - 1
src/hooks/useExcel.ts

@@ -186,5 +186,5 @@ export const useExcel = () => {
     URL.revokeObjectURL(url)
   }
 
-  return { importExcel, toTwoArray, exportExcel }
+  return { importExcel, toTwoArray, exportExcel, download }
 }

+ 7 - 121
src/main.ts

@@ -1,145 +1,31 @@
 import { createApp } from 'vue'
 import { createPinia } from 'pinia'
-import * as Sentry from '@sentry/vue'
-
-import 'uno.css'
-
-import ElementPlus from 'element-plus'
-import 'element-plus/dist/index.css'
-import * as ElementPlusIconsVue from '@element-plus/icons-vue'
-// import { install } from '@icon-park/vue-next/es/all'
 
 import registerComponent from '@/components/index'
 import directives from '@/directive'
 
-import 'xe-utils'
-import {
-  // VXETable,
-  Filter,
-  Edit,
-  Menu,
-  Export,
-  Keyboard,
-  Validator,
-
-  // 可选组件
-  Icon,
-  Column,
-  Colgroup,
-  // Grid,
-  Tooltip,
-  Toolbar,
-  Pager,
-  // Form,
-  // FormItem,
-  // FormGather,
-  Checkbox,
-  CheckboxGroup,
-  Radio,
-  RadioGroup,
-  RadioButton,
-  Switch,
-  Input,
-  Select,
-  Optgroup,
-  Option,
-  // Textarea,
-  Button,
-  Modal,
-  // List,
-  // Pulldown,
-
-  // 表格
-  Table
-} from 'vxe-table'
-import 'vxe-table/styles/cssvar.scss'
-import '@/utils/tableFormat'
-
 import FsAdminCore from '@fskj-admin/core'
 import '@fskj-admin/core/lib/style.css'
+import uploadConfig from './config/uploadConfig'
 
 import App from './App.vue'
 import router from './router'
 
+import 'uno.css'
 import './assets/main.css'
 import 'virtual:svg-icons-register'
 
-import uploadConfig from './config/uploadConfig'
-
-// import { ossUpload } from '@/utils/utils'
-
-// import WujieVue from 'wujie-vue3'
-
-function useTable(app: any) {
-  // 表格功能
-  app.use(Filter).use(Edit).use(Menu).use(Export).use(Keyboard).use(Validator)
-
-  // 可选组件
-  app
-    .use(Icon)
-    .use(Column)
-    .use(Colgroup)
-    // .use(Grid)
-    .use(Tooltip)
-    .use(Toolbar)
-    .use(Pager)
-    // .use(Form)
-    // .use(FormItem)
-    // .use(FormGather)
-    .use(Checkbox)
-    .use(CheckboxGroup)
-    .use(Radio)
-    .use(RadioGroup)
-    .use(RadioButton)
-    .use(Switch)
-    .use(Input)
-    .use(Select)
-    .use(Optgroup)
-    .use(Option)
-    // .use(Textarea)
-    .use(Button)
-    .use(Modal)
-    // .use(List)
-    // .use(Pulldown)
-
-    // 安装表格
-    .use(Table)
-
-  // 给 vue 实例挂载内部对象,例如:
-  // app.config.globalProperties.$XModal = VXETable.modal
-  // app.config.globalProperties.$XPrint = VXETable.print
-  // app.config.globalProperties.$XSaveFile = VXETable.saveFile
-  // app.config.globalProperties.$XReadFile = VXETable.readFile
-}
-
 const app = createApp(App)
 
 app.use(createPinia())
 app.use(router)
-app.use(ElementPlus)
-app.use(useTable)
 app.use(FsAdminCore, {
-  upload: uploadConfig
+  upload: uploadConfig,
+  toolbarConfig: {
+    custom: true
+  }
 })
-// app.use(WujieVue)
+app.use(registerComponent)
 app.use(directives)
-registerComponent(app)
-
-for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
-  app.component(key, component)
-}
-
-// install(app)
-
-import.meta.env.VITE_SENTRY_DSN &&
-  Sentry.init({
-    app,
-    dsn: import.meta.env.VITE_SENTRY_DSN,
-    integrations: [Sentry.browserTracingIntegration(), Sentry.replayIntegration()],
-    tracesSampleRate: 1.0,
-    tracePropagationTargets: [],
-    replaysSessionSampleRate: 0.1,
-    replaysOnErrorSampleRate: 1.0
-  })
 
 app.mount('#app')

+ 2 - 2
src/router/index.ts

@@ -1,10 +1,10 @@
-import { createRouter, createWebHistory } from 'vue-router'
+import { createRouter, createWebHashHistory } from 'vue-router'
 import constantRouter from './constantRouter'
 import createRouterGuard from './guard'
 export { default as asyncRouter } from './asyncRouter'
 
 const router = createRouter({
-  history: createWebHistory(import.meta.env.BASE_URL),
+  history: createWebHashHistory(import.meta.env.BASE_URL),
   routes: [...constantRouter]
 })
 

+ 1 - 0
src/types/form.ts

@@ -25,6 +25,7 @@ export type BasicFormItem = {
   notFormItem?: boolean
   hidden?: boolean
   extra?: any
+  formItemProps?: object
 }
 
 export type AdvancedFormItem = {

+ 2 - 2
src/utils/request.ts

@@ -11,8 +11,8 @@ const request = axios.create({
 
 // 异常拦截处理器
 const errorHandler = (error: any) => {
-  const status = error.response.status
-  const data = error.response.data
+  const status = error.response?.status
+  const data = error.response?.data
 
   if (status === 400) {
     ElMessage.error(data.msg)

+ 0 - 45
src/utils/utils.ts

@@ -1,5 +1,4 @@
 import dayjs from 'dayjs'
-import { ossPolicy } from '@/api/oss'
 
 export const formatDate = (date: any, format = 'YYYY-MM-DD HH:mm') => {
   return dayjs(date).format(format)
@@ -32,47 +31,3 @@ export const uuid = (len = 16) => {
 
   return uuid.join('')
 }
-
-// oss上传
-export const ossUpload = (param: any) => {
-  const { file } = param
-
-  return ossPolicy()
-    .then(async (res: any) => {
-      const id = file.uid
-      const type = file.type.split('/')[1]
-      const ossKey = res.dir + id + '.' + type
-
-      const formData = new FormData()
-      formData.append('OSSAccessKeyId', res.accessKeyId)
-      formData.append('policy', res.policy)
-      formData.append('Signature', res.signature)
-      formData.append('success_action_status', '200')
-      formData.append('key', ossKey)
-      formData.append('name', id + '.' + type)
-      formData.append('file', file)
-
-      const data = await fetch(res.host, {
-        method: 'post',
-        body: formData
-      })
-      if (data.status == 200) {
-        return {
-          success: true,
-          file: file,
-          url: ossKey
-        }
-      } else {
-        return {
-          success: false,
-          msg: '上传失败'
-        }
-      }
-    })
-    .catch((err: any) => {
-      return {
-        success: false,
-        msg: err.message
-      }
-    })
-}

+ 31 - 0
src/views/form/Basic.vue

@@ -27,6 +27,21 @@ const formConfig = reactive<BasicForm>({
     labelPosition: 'right'
   },
   formItems: [
+    {
+      label: '',
+      value: '',
+      name: '',
+      type: 'form-title',
+      span: 24,
+      notFormItem: true,
+      props: {
+        title: '基础表单',
+        type: 'success'
+      },
+      formItemProps: {
+        labelWidth: '0px'
+      }
+    },
     {
       label: '用户名',
       value: '',
@@ -100,6 +115,19 @@ const formConfig = reactive<BasicForm>({
         // }
       ]
     },
+    {
+      label: '',
+      value: '',
+      name: '',
+      type: 'divider',
+      span: 24,
+      props: {
+        dividerName: '分割线'
+      },
+      formItemProps: {
+        labelWidth: '0px'
+      }
+    },
     {
       label: '开关',
       value: true,
@@ -373,6 +401,9 @@ const handleInputConfirm = () => {
 
 <template>
   <div class="h-full bg-white p-16px pt-20px overflow-auto">
+    <form-title type="primary" class="py-10px mb-4 w-50%">
+      <template #default>基础表单</template>
+    </form-title>
     <pro-form :formConfig="formConfig" :formData="formData" :create="create" :update="update" ref="proFormRef">
       <template #prepend1> test1 </template>
       <template #append1> test1 </template>

+ 2 - 2
src/views/system/Configure.vue

@@ -121,8 +121,8 @@ const handleSaveEmail = () => {
             </div>
             <div>
               <el-radio-group v-model="singleLoginType" :disabled="!isSingleLogin">
-                <el-radio label="1" size="large">后登录踢出先登录</el-radio>
-                <el-radio label="2" size="large">已登录禁止再登录</el-radio>
+                <el-radio value="1" size="large">后登录踢出先登录</el-radio>
+                <el-radio value="2" size="large">已登录禁止再登录</el-radio>
               </el-radio-group>
             </div>
             <div class="btn">

+ 7 - 1
src/views/system/Dict.vue

@@ -121,7 +121,13 @@ const dictItemFormConfig = reactive<BasicForm>({
 <template>
   <el-row :gutter="16" class="h-full">
     <el-col :span="12" class="h-full">
-      <pro-table :crud="CRUD" :formConfig="dictFormConfig" :row-class-name="rowClassName" @cell-click="handleRowClick">
+      <pro-table
+        :crud="CRUD"
+        :formConfig="dictFormConfig"
+        :row-class-name="rowClassName"
+        @cell-click="handleRowClick"
+        :queryConfig="{ fold: false }"
+      >
         <vxe-column field="description" title="字典名称"></vxe-column>
         <vxe-column field="type" title="字典值"></vxe-column>
       </pro-table>

+ 12 - 1
vite.config.ts

@@ -11,6 +11,7 @@ import { createStyleImportPlugin, VxeTableResolve } from 'vite-plugin-style-impo
 import Unocss from 'unocss/vite'
 import VueDevTools from 'vite-plugin-vue-devtools'
 import { sentryVitePlugin } from '@sentry/vite-plugin'
+import { lazyImport, VxeResolver } from 'vite-plugin-lazy-import'
 
 export default defineConfig(({ mode }) => {
   const env = loadEnv(mode, process.cwd(), '')
@@ -51,7 +52,17 @@ export default defineConfig(({ mode }) => {
               ignore: ['node_modules']
             }
           })
-        : null
+        : null,
+      lazyImport({
+        resolvers: [
+          VxeResolver({
+            libraryName: 'vxe-table'
+          }),
+          VxeResolver({
+            libraryName: 'vxe-pc-ui'
+          })
+        ]
+      })
     ],
     resolve: {
       alias: {

Some files were not shown because too many files changed in this diff