Browse Source

feat: 同步master

kailong321200875 1 year ago
parent
commit
1af33d8a7e

+ 15 - 15
package.json

@@ -29,7 +29,7 @@
     "@faker-js/faker": "^8.3.1",
     "@iconify/iconify": "^3.1.1",
     "@iconify/vue": "^4.1.1",
-    "@vueuse/core": "^10.7.1",
+    "@vueuse/core": "^10.7.2",
     "@wangeditor/editor": "^5.1.23",
     "@wangeditor/editor-for-vue": "^5.1.10",
     "@zxcvbn-ts/core": "^3.0.4",
@@ -40,7 +40,7 @@
     "driver.js": "^1.3.1",
     "echarts": "^5.4.3",
     "echarts-wordcloud": "^2.1.0",
-    "element-plus": "^2.4.4",
+    "element-plus": "^2.5.1",
     "lodash-es": "^4.17.21",
     "mitt": "^3.0.1",
     "nprogress": "^0.2.0",
@@ -49,8 +49,8 @@
     "qrcode": "^1.5.3",
     "qs": "^6.11.2",
     "url": "^0.11.3",
-    "vue": "3.4.6",
-    "vue-draggable-plus": "^0.3.4",
+    "vue": "3.4.14",
+    "vue-draggable-plus": "^0.3.5",
     "vue-i18n": "9.9.0",
     "vue-json-pretty": "^2.3.0",
     "vue-router": "^4.2.5",
@@ -60,21 +60,21 @@
   "devDependencies": {
     "@commitlint/cli": "^18.4.4",
     "@commitlint/config-conventional": "^18.4.4",
-    "@iconify/json": "^2.2.166",
+    "@iconify/json": "^2.2.169",
     "@intlify/unplugin-vue-i18n": "^2.0.0",
     "@types/fs-extra": "^11.0.4",
     "@types/inquirer": "^9.0.7",
     "@types/lodash-es": "^4.17.12",
-    "@types/node": "^20.10.7",
+    "@types/node": "^20.11.3",
     "@types/nprogress": "^0.2.3",
     "@types/qrcode": "^1.5.5",
     "@types/qs": "^6.9.11",
     "@types/sortablejs": "^1.15.7",
-    "@typescript-eslint/eslint-plugin": "^6.18.1",
-    "@typescript-eslint/parser": "^6.18.1",
+    "@typescript-eslint/eslint-plugin": "^6.19.0",
+    "@typescript-eslint/parser": "^6.19.0",
     "@unocss/transformer-variant-group": "^0.58.3",
     "@vitejs/plugin-legacy": "^5.2.0",
-    "@vitejs/plugin-vue": "^5.0.2",
+    "@vitejs/plugin-vue": "^5.0.3",
     "@vitejs/plugin-vue-jsx": "^3.1.0",
     "autoprefixer": "^10.4.16",
     "chalk": "^5.3.0",
@@ -82,8 +82,8 @@
     "eslint": "^8.56.0",
     "eslint-config-prettier": "^9.1.0",
     "eslint-define-config": "^2.1.0",
-    "eslint-plugin-prettier": "^5.1.2",
-    "eslint-plugin-vue": "^9.19.2",
+    "eslint-plugin-prettier": "^5.1.3",
+    "eslint-plugin-vue": "^9.20.1",
     "esno": "^4.0.0",
     "fs-extra": "^11.2.0",
     "husky": "^8.0.3",
@@ -92,11 +92,11 @@
     "lint-staged": "^15.2.0",
     "plop": "^4.0.1",
     "postcss": "^8.4.33",
-    "postcss-html": "^1.5.0",
+    "postcss-html": "^1.6.0",
     "postcss-less": "^6.0.0",
-    "prettier": "^3.1.1",
+    "prettier": "^3.2.2",
     "rimraf": "^5.0.5",
-    "rollup": "^4.9.4",
+    "rollup": "^4.9.5",
     "rollup-plugin-visualizer": "^5.12.0",
     "stylelint": "^16.1.0",
     "stylelint-config-html": "^1.1.0",
@@ -109,7 +109,7 @@
     "vite": "5.0.11",
     "vite-plugin-ejs": "^1.7.0",
     "vite-plugin-eslint": "^1.8.1",
-    "vite-plugin-mock": "^2.9.6",
+    "vite-plugin-mock": "2.9.6",
     "vite-plugin-progress": "^0.0.7",
     "vite-plugin-purge-icons": "^0.10.0",
     "vite-plugin-style-import": "2.0.0",

+ 1 - 15
src/App.vue

@@ -2,9 +2,7 @@
 import { computed } from 'vue'
 import { useAppStore } from '@/store/modules/app'
 import { ConfigGlobal } from '@/components/ConfigGlobal'
-import { isDark } from '@/utils/is'
 import { useDesign } from '@/hooks/web/useDesign'
-import { useStorage } from '@/hooks/web/useStorage'
 
 const { getPrefixCls } = useDesign()
 
@@ -16,19 +14,7 @@ const currentSize = computed(() => appStore.getCurrentSize)
 
 const greyMode = computed(() => appStore.getGreyMode)
 
-const { getStorage } = useStorage()
-
-// 根据浏览器当前主题设置系统主题色
-const setDefaultTheme = () => {
-  if (getStorage('isDark') !== null) {
-    appStore.setIsDark(getStorage('isDark'))
-    return
-  }
-  const isDarkTheme = isDark()
-  appStore.setIsDark(isDarkTheme)
-}
-
-setDefaultTheme()
+appStore.initTheme()
 </script>
 
 <template>

+ 8 - 1
src/axios/config.ts

@@ -1,8 +1,9 @@
 import { AxiosResponse, InternalAxiosRequestConfig } from './types'
 import { ElMessage } from 'element-plus'
 import qs from 'qs'
-import { SUCCESS_CODE } from '@/constants'
+import { SUCCESS_CODE, TRANSFORM_REQUEST_DATA } from '@/constants'
 import { useUserStoreWithOut } from '@/store/modules/user'
+import { objToFormData } from '@/utils'
 
 const defaultRequestInterceptors = (config: InternalAxiosRequestConfig) => {
   if (
@@ -10,6 +11,12 @@ const defaultRequestInterceptors = (config: InternalAxiosRequestConfig) => {
     config.headers['Content-Type'] === 'application/x-www-form-urlencoded'
   ) {
     config.data = qs.stringify(config.data)
+  } else if (
+    TRANSFORM_REQUEST_DATA &&
+    config.method === 'post' &&
+    config.headers['Content-Type'] === 'multipart/form-data'
+  ) {
+    config.data = objToFormData(config.data)
   }
   if (config.method === 'get' && config.params) {
     let url = config.url as string

+ 1 - 1
src/components/Form/src/Form.vue

@@ -230,7 +230,7 @@ export default defineComponent({
       const { schema = [], isCol } = unref(getProps)
 
       return schema
-        .filter((v) => !v.remove)
+        .filter((v) => !v.remove && !v.hidden)
         .map((item) => {
           // 如果是 Divider 组件,需要自己占用一行
           const isDivider = item.component === 'Divider'

+ 18 - 65
src/components/Setting/src/Setting.vue

@@ -1,9 +1,8 @@
 <script setup lang="ts">
 import { ElDrawer, ElDivider, ElMessage } from 'element-plus'
-import { ref, unref, computed } from 'vue'
+import { ref, unref } from 'vue'
 import { useI18n } from '@/hooks/web/useI18n'
 import { ThemeSwitch } from '@/components/ThemeSwitch'
-import { colorIsDark, lighten, hexToRGB } from '@/utils/color'
 import { useCssVar } from '@vueuse/core'
 import { useAppStore } from '@/store/modules/app'
 import { trim, setCssVar, getCssVar } from '@/utils'
@@ -24,8 +23,6 @@ const appStore = useAppStore()
 
 const { t } = useI18n()
 
-const layout = computed(() => appStore.getLayout)
-
 const drawer = ref(false)
 
 // 主题色相关
@@ -42,56 +39,14 @@ const setSystemTheme = (color: string) => {
 const headerTheme = ref(appStore.getTheme.topHeaderBgColor || '')
 
 const setHeaderTheme = (color: string) => {
-  const isDarkColor = colorIsDark(color)
-  const textColor = isDarkColor ? '#fff' : 'inherit'
-  const textHoverColor = isDarkColor ? lighten(color!, 6) : '#f6f6f6'
-  const topToolBorderColor = isDarkColor ? color : '#eee'
-  setCssVar('--top-header-bg-color', color)
-  setCssVar('--top-header-text-color', textColor)
-  setCssVar('--top-header-hover-color', textHoverColor)
-  appStore.setTheme({
-    topHeaderBgColor: color,
-    topHeaderTextColor: textColor,
-    topHeaderHoverColor: textHoverColor,
-    topToolBorderColor
-  })
-  if (unref(layout) === 'top') {
-    setMenuTheme(color)
-  }
+  appStore.setHeaderTheme(color)
 }
 
 // 菜单主题相关
 const menuTheme = ref(appStore.getTheme.leftMenuBgColor || '')
 
 const setMenuTheme = (color: string) => {
-  const primaryColor = useCssVar('--el-color-primary', document.documentElement)
-  const isDarkColor = colorIsDark(color)
-  const theme: Recordable = {
-    // 左侧菜单边框颜色
-    leftMenuBorderColor: isDarkColor ? 'inherit' : '#eee',
-    // 左侧菜单背景颜色
-    leftMenuBgColor: color,
-    // 左侧菜单浅色背景颜色
-    leftMenuBgLightColor: isDarkColor ? lighten(color!, 6) : color,
-    // 左侧菜单选中背景颜色
-    leftMenuBgActiveColor: isDarkColor
-      ? 'var(--el-color-primary)'
-      : hexToRGB(unref(primaryColor), 0.1),
-    // 左侧菜单收起选中背景颜色
-    leftMenuCollapseBgActiveColor: isDarkColor
-      ? 'var(--el-color-primary)'
-      : hexToRGB(unref(primaryColor), 0.1),
-    // 左侧菜单字体颜色
-    leftMenuTextColor: isDarkColor ? '#bfcbd9' : '#333',
-    // 左侧菜单选中字体颜色
-    leftMenuTextActiveColor: isDarkColor ? '#fff' : 'var(--el-color-primary)',
-    // logo字体颜色
-    logoTitleTextColor: isDarkColor ? '#fff' : 'inherit',
-    // logo边框颜色
-    logoBorderColor: isDarkColor ? color : '#eee'
-  }
-  appStore.setTheme(theme)
-  appStore.setCssVarTheme()
+  appStore.setMenuTheme(color)
 }
 
 // 监听layout变化,重置一些主题色
@@ -258,23 +213,21 @@ const themeChange = () => {
       />
 
       <!-- 菜单主题 -->
-      <template v-if="layout !== 'top'">
-        <ElDivider>{{ t('setting.menuTheme') }}</ElDivider>
-        <ColorRadioPicker
-          v-model="menuTheme"
-          :schema="[
-            '#fff',
-            '#001529',
-            '#212121',
-            '#273352',
-            '#191b24',
-            '#383f45',
-            '#001628',
-            '#344058'
-          ]"
-          @change="setMenuTheme"
-        />
-      </template>
+      <ElDivider>{{ t('setting.menuTheme') }}</ElDivider>
+      <ColorRadioPicker
+        v-model="menuTheme"
+        :schema="[
+          '#fff',
+          '#001529',
+          '#212121',
+          '#273352',
+          '#191b24',
+          '#383f45',
+          '#001628',
+          '#344058'
+        ]"
+        @change="setMenuTheme"
+      />
     </div>
 
     <!-- 界面显示 -->

+ 3 - 2
src/components/Table/src/components/ColumnSetting.vue

@@ -69,7 +69,7 @@ const initColumns = (columns: TableColumn[], isReStore = false) => {
     }
     return (item.type && !DEFAULT_FILTER_COLUMN.includes(item.type)) || !item.type
   })
-  if (!unref(oldColumns)) {
+  if (!unref(oldColumns)?.length) {
     oldColumns.value = cloneDeep(newColumns)
   }
   settingColumns.value = cloneDeep(newColumns)
@@ -96,7 +96,8 @@ watch(
     initColumns(columns)
   },
   {
-    immediate: true
+    immediate: true,
+    deep: true
   }
 )
 </script>

+ 6 - 1
src/constants/index.ts

@@ -6,7 +6,7 @@ export const SUCCESS_CODE = 0
 /**
  * 请求contentType
  */
-export const CONTENT_TYPE = 'application/json'
+export const CONTENT_TYPE: AxiosContentType = 'application/json'
 
 /**
  * 请求超时时间
@@ -27,3 +27,8 @@ export const NO_RESET_WHITE_LIST = ['Redirect', 'Login', 'NoFind', 'Root']
  * 表格默认过滤列设置字段
  */
 export const DEFAULT_FILTER_COLUMN = ['expand', 'selection']
+
+/**
+ * 是否根据headers->content-type自动转换数据格式
+ */
+export const TRANSFORM_REQUEST_DATA = true

+ 14 - 19
src/hooks/web/useCrudSchemas.ts

@@ -78,17 +78,14 @@ const filterSearchSchema = (crudSchema: CrudSchema[]): FormSchema[] => {
 
   for (let i = 0; i < length; i++) {
     const schemaItem = crudSchema[i]
-    // 判断是否隐藏
-    if (!schemaItem?.search?.remove) {
-      const searchSchemaItem = {
-        component: schemaItem?.search?.component || 'Input',
-        ...schemaItem.search,
-        field: schemaItem.field,
-        label: schemaItem.label
-      }
-
-      searchSchema.push(searchSchemaItem)
+    const searchSchemaItem = {
+      component: schemaItem?.search?.component || 'Input',
+      ...schemaItem.search,
+      field: schemaItem.field,
+      label: schemaItem.label
     }
+
+    searchSchema.push(searchSchemaItem)
   }
 
   return searchSchema
@@ -124,16 +121,14 @@ const filterFormSchema = (crudSchema: CrudSchema[]): FormSchema[] => {
   for (let i = 0; i < length; i++) {
     const formItem = crudSchema[i]
     // 判断是否隐藏
-    if (!formItem?.form?.remove) {
-      const formSchemaItem = {
-        component: formItem?.form?.component || 'Input',
-        ...formItem.form,
-        field: formItem.field,
-        label: formItem.label
-      }
-
-      formSchema.push(formSchemaItem)
+    const formSchemaItem = {
+      component: formItem?.form?.component || 'Input',
+      ...formItem.form,
+      field: formItem.field,
+      label: formItem.label
     }
+
+    formSchema.push(formSchemaItem)
   }
 
   return formSchema

+ 59 - 1
src/store/modules/app.ts

@@ -1,8 +1,11 @@
 import { defineStore } from 'pinia'
 import { store } from '../index'
 import { setCssVar, humpToUnderline } from '@/utils'
-import { mix } from '@/utils/color'
 import { ElMessage, ComponentSize } from 'element-plus'
+import { colorIsDark, hexToRGB, lighten, mix } from '@/utils/color'
+import { unref } from 'vue'
+import { useCssVar } from '@vueuse/core'
+import { useDark } from '@vueuse/core'
 
 interface AppState {
   breadcrumb: boolean
@@ -270,6 +273,61 @@ export const useAppStore = defineStore('app', {
         })
         setCssVar(`--el-color-primary-dark-2`, mix(color, elColorPrimary, 0.2))
       }
+    },
+    setMenuTheme(color: string) {
+      const primaryColor = useCssVar('--el-color-primary', document.documentElement)
+      const isDarkColor = colorIsDark(color)
+      const theme: Recordable = {
+        // 左侧菜单边框颜色
+        leftMenuBorderColor: isDarkColor ? 'inherit' : '#eee',
+        // 左侧菜单背景颜色
+        leftMenuBgColor: color,
+        // 左侧菜单浅色背景颜色
+        leftMenuBgLightColor: isDarkColor ? lighten(color!, 6) : color,
+        // 左侧菜单选中背景颜色
+        leftMenuBgActiveColor: isDarkColor
+          ? 'var(--el-color-primary)'
+          : hexToRGB(unref(primaryColor), 0.1),
+        // 左侧菜单收起选中背景颜色
+        leftMenuCollapseBgActiveColor: isDarkColor
+          ? 'var(--el-color-primary)'
+          : hexToRGB(unref(primaryColor), 0.1),
+        // 左侧菜单字体颜色
+        leftMenuTextColor: isDarkColor ? '#bfcbd9' : '#333',
+        // 左侧菜单选中字体颜色
+        leftMenuTextActiveColor: isDarkColor ? '#fff' : 'var(--el-color-primary)',
+        // logo字体颜色
+        logoTitleTextColor: isDarkColor ? '#fff' : 'inherit',
+        // logo边框颜色
+        logoBorderColor: isDarkColor ? color : '#eee'
+      }
+      this.setTheme(theme)
+      this.setCssVarTheme()
+    },
+    setHeaderTheme(color: string) {
+      const isDarkColor = colorIsDark(color)
+      const textColor = isDarkColor ? '#fff' : 'inherit'
+      const textHoverColor = isDarkColor ? lighten(color!, 6) : '#f6f6f6'
+      const topToolBorderColor = isDarkColor ? color : '#eee'
+      setCssVar('--top-header-bg-color', color)
+      setCssVar('--top-header-text-color', textColor)
+      setCssVar('--top-header-hover-color', textHoverColor)
+      this.setTheme({
+        topHeaderBgColor: color,
+        topHeaderTextColor: textColor,
+        topHeaderHoverColor: textHoverColor,
+        topToolBorderColor
+      })
+      if (this.getLayout === 'top') {
+        this.setMenuTheme(color)
+      }
+    },
+    initTheme() {
+      const isDark = useDark({
+        valueDark: 'dark',
+        valueLight: 'light'
+      })
+      isDark.value = this.getIsDark
     }
   },
   persist: true

+ 11 - 0
src/utils/index.ts

@@ -126,3 +126,14 @@ export function toAnyString() {
 export function firstUpperCase(str: string) {
   return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase())
 }
+
+/**
+ * 把对象转为formData
+ */
+export function objToFormData(obj: Recordable) {
+  const formData = new FormData()
+  Object.keys(obj).forEach((key) => {
+    formData.append(key, obj[key])
+  })
+  return formData
+}

+ 8 - 2
src/views/Login/Login.vue

@@ -3,7 +3,7 @@ import { LoginForm, RegisterForm } from './components'
 import { ThemeSwitch } from '@/components/ThemeSwitch'
 import { LocaleDropdown } from '@/components/LocaleDropdown'
 import { useI18n } from '@/hooks/web/useI18n'
-import { underlineToHump } from '@/utils'
+import { getCssVar, underlineToHump } from '@/utils'
 import { useAppStore } from '@/store/modules/app'
 import { useDesign } from '@/hooks/web/useDesign'
 import { ref } from 'vue'
@@ -26,6 +26,12 @@ const toRegister = () => {
 const toLogin = () => {
   isLogin.value = true
 }
+
+const themeChange = () => {
+  const color = getCssVar('--el-bg-color')
+  appStore.setMenuTheme(color)
+  appStore.setHeaderTheme(color)
+}
 </script>
 
 <template>
@@ -66,7 +72,7 @@ const toLogin = () => {
             </div>
 
             <div class="flex justify-end items-center space-x-10px">
-              <ThemeSwitch />
+              <ThemeSwitch @change="themeChange" />
               <LocaleDropdown class="lt-xl:text-white dark:text-white" />
             </div>
           </div>

+ 0 - 4
stylelint.config.js

@@ -20,12 +20,8 @@ module.exports = {
     'function-no-unknown': null,
     'no-empty-source': null,
     'named-grid-areas-no-invalid': null,
-    'unicode-bom': 'never',
     'no-descending-specificity': null,
     'font-family-no-missing-generic-family-keyword': null,
-    'declaration-colon-space-after': 'always-single-line',
-    'declaration-colon-space-before': 'never',
-    'declaration-block-trailing-semicolon': null,
     'rule-empty-line-before': [
       'always',
       {

+ 1 - 0
types/global.d.ts

@@ -30,6 +30,7 @@ declare global {
     | 'application/json'
     | 'application/x-www-form-urlencoded'
     | 'multipart/form-data'
+    | 'text/plain'
 
   declare type AxiosMethod = 'get' | 'post' | 'delete' | 'put'