Sfoglia il codice sorgente

增加主题选择

zhangafei 1 mese fa
parent
commit
31b08dd1a6

+ 4 - 14
build/config/themeConfig.ts

@@ -30,12 +30,7 @@ export function getThemeColors(color?: string) {
   return [...lightColors, ...modeColors];
 }
 
-export function generateColors({
-  color = primaryColor,
-  mixLighten,
-  mixDarken,
-  tinycolor,
-}: GenerateColorsParams) {
+export function generateColors({ color = primaryColor, mixLighten, mixDarken, tinycolor }: GenerateColorsParams) {
   const arr = new Array(19).fill(0);
   const lightens = arr.map((_t, i) => {
     return mixLighten(color, i / 5);
@@ -68,12 +63,7 @@ export function generateColors({
         .toHexString();
     })
     .filter((item) => item !== '#000000');
-  return [
-    ...lightens,
-    ...darkens,
-    ...alphaColors,
-    ...shortAlphaColors,
-    ...tinycolorDarkens,
-    ...tinycolorLightens,
-  ].filter((item) => !item.includes('-'));
+  return [...lightens, ...darkens, ...alphaColors, ...shortAlphaColors, ...tinycolorDarkens, ...tinycolorLightens].filter(
+    (item) => !item.includes('-')
+  );
 }

+ 36 - 0
src/App.vue

@@ -17,6 +17,8 @@
   import { useRootSetting } from '/@/hooks/setting/useRootSetting';
   import { ThemeEnum } from '/@/enums/appEnum';
   import { changeTheme } from '/@/logics/theme/index';
+  import { APP_MODE_LIST } from '/@/settings/designSetting';
+  import { setCssVar } from './logics/theme/util';
 
   const appStore = useAppStore();
   // 解决日期时间国际化问题
@@ -70,6 +72,10 @@
     appStore.getProjectConfig,
     (newValue) => {
       const primary = newValue.themeColor;
+      const newToken = [ThemeEnum.DARK, ThemeEnum.LIGHT].includes(newValue.themeMode as ThemeEnum)
+        ? {}
+        : APP_MODE_LIST.find((item) => item.value === newValue.themeMode);
+
       const result = {
         ...appTheme.value,
         ...{
@@ -87,9 +93,39 @@
             colorError: '#ED6F6F',
             fontFamily:
               '-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol',
+            ...(newToken && newToken.token ? { ...newToken.token, colorTextBase: newToken.token.colorText } : {}),
           },
         },
       };
+
+      if (![ThemeEnum.DARK, ThemeEnum.LIGHT].includes(newValue.themeMode as ThemeEnum) && newToken) {
+        // '@text-color': '#fff',
+        setCssVar('--el-text-color', newToken.token.colorText);
+        // '@primary-1': 'blue',
+        // '@text-color-base': 'green',
+        // '@component-background': 'brown',
+        setCssVar('--el-component-background', newToken.token.colorBgContainer);
+        // // 'heading-color': 'rgb(255 255 255 / 65%)',
+        // // 'text-color-secondary': '#8b949e',
+        // // 'border-color-base': '#303030',
+        // // 'header-light-bottom-border-color': '#303030',
+        // // 'item-active-bg': '#111b26',
+        // // 'app-content-background': '#1e1e1e',
+        // // 'tree-node-selected-bg': '#11263c',
+        // // 'alert-success-border-color': '#274916',
+        // // 'alert-success-bg-color': '#162312',
+        // // 'alert-success-icon-color': '#49aa19',
+        // // 'alert-info-border-color': '#153450',
+        // // 'alert-info-bg-color': '#111b26',
+        // // 'alert-info-icon-color': '#177ddc',
+        // // 'alert-warning-border-color': '#594214',
+        // // 'alert-warning-bg-color': '#2b2111',
+        // // 'alert-warning-icon-color': '#d89614',
+        // // 'alert-error-border-color': '#58181c',
+        // // 'alert-error-bg-color': '#2a1215',
+        // // 'alert-error-icon-color': '#a61d24',
+      }
+
       appTheme.value = result;
       modeAction(result);
     },

+ 94 - 7
src/components/Application/src/AppDarkModeToggle.vue

@@ -1,9 +1,32 @@
 <template>
-  <div v-if="getShowDarkModeToggle" :class="getClass" @click="toggleDarkMode">
-    <div :class="`${prefixCls}-inner`"> </div>
-    <SvgIcon size="14" name="sun" />
-    <SvgIcon size="14" name="moon" />
-  </div>
+  <template v-if="type !== 'setting'">
+    <div v-if="getShowDarkModeToggle" :class="getClass" @click="toggleDarkMode">
+      <div :class="`${prefixCls}-inner`"> </div>
+      <SvgIcon size="14" name="sun" />
+      <SvgIcon size="14" name="moon" />
+    </div>
+  </template>
+  <template v-else>
+    <div class="jeecg-setting-mode-type-picker">
+      <div
+        class="jeecg-setting-mode-type-picker__item"
+        v-for="item in APP_MODE_LIST"
+        :key="item.value"
+        :class="{ active: getDarkMode === item.value }"
+        :style="{
+          backgroundColor: item.bg || item.token.colorBgContainer,
+          backgroundImage: item.bg || item.token.colorBgContainer,
+          borderColor: item.token && item.token.colorBorder ? item.token.colorBorder : '#E0E0E0',
+          boxShadow: item.boxShadow ? item.boxShadow : '0 1px 2.5px 0 rgba(0, 0, 0, 0.18)',
+          color: item.text || item.token.colorText,
+        }"
+        :title="item.desc"
+        @click="selectMode(item)"
+      >
+        {{ item.label }}
+      </div>
+    </div>
+  </template>
 </template>
 <script lang="ts" setup>
   import { computed, unref } from 'vue';
@@ -11,8 +34,18 @@
   import { useDesign } from '/@/hooks/web/useDesign';
   import { useRootSetting } from '/@/hooks/setting/useRootSetting';
   import { updateHeaderBgColor, updateSidebarBgColor } from '/@/logics/theme/updateBackground';
-  import { updateDarkTheme } from '/@/logics/theme/dark';
+  import { updateDarkTheme, updateAppTheme } from '/@/logics/theme/dark';
   import { ThemeEnum } from '/@/enums/appEnum';
+  import { APP_MODE_LIST } from '/@/settings/designSetting';
+  import { HandlerEnum } from '/@/layouts/default/setting/enum';
+  import { baseHandler } from '/@/layouts/default/setting/handler';
+
+  defineProps({
+    type: {
+      type: String,
+      default: '',
+    },
+  });
 
   const { prefixCls } = useDesign('dark-switch');
   const { getDarkMode, setDarkMode, getShowDarkModeToggle } = useRootSetting();
@@ -33,6 +66,28 @@
     updateHeaderBgColor();
     updateSidebarBgColor();
   }
+
+  const selectMode = (mode: any) => {
+    const { value } = mode;
+    setDarkMode(value);
+    console.log('selectMode', [ThemeEnum.DARK, ThemeEnum.LIGHT].includes(value));
+    if ([ThemeEnum.DARK, ThemeEnum.LIGHT].includes(value)) {
+      updateDarkTheme(value);
+      updateHeaderBgColor();
+      updateSidebarBgColor();
+    } else {
+      const { colorBgContainer } = mode.token;
+      updateAppTheme(value, getDarkMode.value);
+
+      // 设置header主题色
+      updateHeaderBgColor(colorBgContainer);
+      baseHandler(HandlerEnum.HEADER_THEME, colorBgContainer);
+
+      // 设置左侧菜单主题色
+      updateSidebarBgColor(colorBgContainer);
+      baseHandler(HandlerEnum.MENU_THEME, colorBgContainer);
+    }
+  };
 </script>
 <style lang="less" scoped>
   @prefix-cls: ~'@{namespace}-dark-switch';
@@ -63,7 +118,9 @@
       height: 18px;
       background-color: #fff;
       border-radius: 50%;
-      transition: transform 0.5s, background-color 0.5s;
+      transition:
+        transform 0.5s,
+        background-color 0.5s;
       will-change: transform;
     }
 
@@ -73,4 +130,34 @@
       }
     }
   }
+
+  .jeecg-setting-mode-type-picker {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 10px;
+
+    .jeecg-setting-mode-type-picker__item {
+      position: relative;
+      line-height: 24px;
+      width: 67px;
+      height: 48px;
+      overflow: hidden;
+      cursor: pointer;
+      border-radius: 4px;
+      box-shadow: 0 1px 2.5px 0 rgba(0, 0, 0, 0.18);
+      border: 1px solid #fff;
+      text-align: center;
+      line-height: 48px;
+
+      &:hover {
+        border-color: @primary-color !important;
+        box-shadow: 0 1px 2.5px 0 @primary-color !important;
+      }
+
+      &.active {
+        border-color: @primary-color !important;
+        box-shadow: 0 1px 2.5px 0 @primary-color !important;
+      }
+    }
+  }
 </style>

+ 3 - 1
src/components/Drawer/src/BasicDrawer.vue

@@ -24,7 +24,7 @@
 <script lang="ts">
   import type { DrawerInstance, DrawerProps } from './typing';
   import type { CSSProperties } from 'vue';
-  import { defineComponent, ref, computed, watch, unref, nextTick, toRaw, getCurrentInstance } from 'vue';
+  import { defineComponent, ref, computed, watch, unref, nextTick, getCurrentInstance } from 'vue';
   import { Drawer } from 'ant-design-vue';
   import { useI18n } from '/@/hooks/web/useI18n';
   import { isFunction, isNumber } from '/@/utils/is';
@@ -211,6 +211,8 @@
       height: calc(100% - @header-height);
       padding: 0;
       background-color: @component-background;
+      background: transparent;
+      color: @text-color;
 
       .scrollbar__wrap {
         padding: 16px !important;

+ 23 - 19
src/components/Table/src/BasicTable.vue

@@ -20,7 +20,14 @@
     <a-form-item-rest>
       <!-- 【TV360X-377】关联记录必填影响到了table的输入框和页码样式 -->
       <a-form-item>
-        <Table ref="tableElRef" v-bind="getBindValues" :rowClassName="getRowClassName" v-show="getEmptyDataIsShowTable" @resizeColumn="handleResizeColumn" @change="handleTableChange">
+        <Table
+          ref="tableElRef"
+          v-bind="getBindValues"
+          :rowClassName="getRowClassName"
+          v-show="getEmptyDataIsShowTable"
+          @resizeColumn="handleResizeColumn"
+          @change="handleTableChange"
+        >
           <!-- antd的原生插槽直接传递 -->
           <template #[item]="data" v-for="item in slotNamesGroup.native" :key="item">
             <!-- update-begin--author:liaozhiyang---date:20240424---for:【issues/1146】BasicTable使用headerCell全选框出不来 -->
@@ -33,7 +40,7 @@
           </template>
           <template #headerCell="{ column }">
             <!-- update-begin--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题 -->
-            <CustomSelectHeader v-if="isCustomSelection(column)" v-bind="selectHeaderProps"/>
+            <CustomSelectHeader v-if="isCustomSelection(column)" v-bind="selectHeaderProps" />
             <HeaderCell v-else :column="column" />
             <!-- update-end--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题 -->
           </template>
@@ -42,7 +49,7 @@
             <!-- update-begin--author:liaozhiyang---date:220230717---for:【issues-179】antd3 一些警告以及报错(针对表格) -->
             <!-- update-begin--author:liusq---date:20230921---for:【issues/770】slotsBak异常报错的问题,增加判断column是否存在 -->
             <template v-if="data.column?.slotsBak?.customRender">
-            <!-- update-end--author:liusq---date:20230921---for:【issues/770】slotsBak异常报错的问题,增加判断column是否存在 -->
+              <!-- update-end--author:liusq---date:20230921---for:【issues/770】slotsBak异常报错的问题,增加判断column是否存在 -->
               <slot :name="data.column.slotsBak.customRender" v-bind="data || {}"></slot>
             </template>
             <template v-else>
@@ -69,7 +76,7 @@
   import { Table } from 'ant-design-vue';
   import { BasicForm, useForm } from '/@/components/Form/index';
   import { PageWrapperFixedHeightKey } from '/@/components/Page/injectionKey';
-  import CustomSelectHeader from './components/CustomSelectHeader.vue'
+  import CustomSelectHeader from './components/CustomSelectHeader.vue';
   import expandIcon from './components/ExpandIcon';
   import HeaderCell from './components/HeaderCell.vue';
   import TableSummary from './components/TableSummary';
@@ -88,7 +95,7 @@
   import { useTableFooter } from './hooks/useTableFooter';
   import { useTableForm } from './hooks/useTableForm';
   import { useDesign } from '/@/hooks/web/useDesign';
-  import { useCustomSelection } from "./hooks/useCustomSelection";
+  import { useCustomSelection } from './hooks/useCustomSelection';
 
   import { omit, pick } from 'lodash-es';
   import { basicProps } from './props';
@@ -168,14 +175,7 @@
         clearSelectedRowKeys,
         deleteSelectRowByKey,
         getExpandIconColumnIndex,
-      } = useCustomSelection(
-        getProps,
-        emit,
-        wrapRef,
-        getPaginationInfo,
-        tableData,
-        childrenColumnName
-      )
+      } = useCustomSelection(getProps, emit, wrapRef, getPaginationInfo, tableData, childrenColumnName);
       // update-end--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
 
       const {
@@ -218,7 +218,7 @@
         getProps,
         getPaginationInfo,
         // update-begin--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
-        handleCustomSelectColumn,
+        handleCustomSelectColumn
         // update-end--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
       );
 
@@ -295,11 +295,11 @@
         /*if (slots.expandedRowRender) {
           propsData = omit(propsData, 'scroll');
         }*/
-        //update-end---author:wangshuai ---date:20230214  for:[QQYUN-4237]代码生成 内嵌子表模式 没有滚动条------------ 
+        //update-end---author:wangshuai ---date:20230214  for:[QQYUN-4237]代码生成 内嵌子表模式 没有滚动条------------
 
         // update-begin--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
         // 自定义选择列,需要去掉原生的
-        delete propsData.rowSelection
+        delete propsData.rowSelection;
         // update-end--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
 
         // update-begin--author:liaozhiyang---date:20230919---for:【QQYUN-6387】展开写法(去掉报错)
@@ -408,7 +408,7 @@
       // update-begin--author:liaozhiyang---date:20231226---for:【issues/945】BasicTable组件设置默认展开不生效
       nextTick(() => {
         getProps.value.defaultExpandAllRows && expandAll();
-      })
+      });
       // update-end--author:sunjianlei---date:20231226---for:【issues/945】BasicTable组件设置默认展开不生效
       // update-begin--author:liaozhiyang---date:20241225---for:【issues/7588】选择后自动刷新表格
       expose({ ...tableAction, handleSearchInfoChange });
@@ -416,7 +416,6 @@
 
       emit('register', tableAction, formActions);
 
-
       return {
         tableElRef,
         getBindValues,
@@ -445,7 +444,7 @@
             setColumns(columns);
           }
           // update-end--author:liaozhiyang---date:20240903---for:【issues/7101】列配置resizable: true时,表尾合计的列宽没有同步改变
-          console.log('col',col);
+          console.log('col', col);
           col.width = w;
         },
         getFormProps: getFormProps as any,
@@ -491,6 +490,11 @@
   .@{prefix-cls} {
     max-width: 100%;
 
+    .ant-table-wrapper .ant-table-thead > tr > th,
+    .ant-table-wrapper .ant-table-thead > tr > td {
+      color: @text-color;
+    }
+
     &-row__striped {
       td {
         background-color: @app-content-background;

+ 24 - 16
src/design/ant/index.less

@@ -97,8 +97,10 @@
   align-items: stretch;
 }
 
-.ant-list .ant-list-item {padding-left: 0;padding-right: 0;}
-
+.ant-list .ant-list-item {
+  padding-left: 0;
+  padding-right: 0;
+}
 
 .ant-list-item {
   display: flex;
@@ -107,27 +109,33 @@
   padding: 12px 0;
   color: #000000d9;
 }
-/** anticon-down跟3.x保持一致*/ 
-.ant-dropdown-trigger>.anticon.anticon-down, .ant-dropdown-link>.anticon.anticon-down, .ant-dropdown-button>.anticon.anticon-down {
+/** anticon-down跟3.x保持一致*/
+.ant-dropdown-trigger > .anticon.anticon-down,
+.ant-dropdown-link > .anticon.anticon-down,
+.ant-dropdown-button > .anticon.anticon-down {
   font-size: 10px;
   vertical-align: baseline;
 }
-/** 表格排序箭头尺寸保持跟3.x一致 */ 
-.ant-table-wrapper .ant-table-column-sorter-up, .ant-table-wrapper .ant-table-column-sorter-down {
+/** 表格排序箭头尺寸保持跟3.x一致 */
+.ant-table-wrapper .ant-table-column-sorter-up,
+.ant-table-wrapper .ant-table-column-sorter-down {
   font-size: 11px;
 }
- /** 表格头部文字颜色跟3.x版本保持一致 */
-.ant-table-wrapper .ant-table-thead >tr>th, .ant-table-wrapper .ant-table-thead >tr>td {
+/** 表格头部文字颜色跟3.x版本保持一致 */
+.ant-table-wrapper .ant-table-thead > tr > th,
+.ant-table-wrapper .ant-table-thead > tr > td {
   color: #000000d9;
   font-weight: 500;
 }
-html[data-theme='dark'] .ant-table-wrapper .ant-table-thead >tr>th, .ant-table-wrapper .ant-table-thead >tr>td {
-  color:rgba(255,255,255,.65);
+html[data-theme='dark'] .ant-table-wrapper .ant-table-thead > tr > th,
+.ant-table-wrapper .ant-table-thead > tr > td {
+  color: rgba(255, 255, 255, 0.65);
 }
- /** 下拉菜单文字和图标折叠了 */
-.ant-dropdown .ant-dropdown-menu .ant-dropdown-menu-title-content, .ant-dropdown-menu-submenu .ant-dropdown-menu .ant-dropdown-menu-title-content{
+/** 下拉菜单文字和图标折叠了 */
+.ant-dropdown .ant-dropdown-menu .ant-dropdown-menu-title-content,
+.ant-dropdown-menu-submenu .ant-dropdown-menu .ant-dropdown-menu-title-content {
   flex: auto;
-  white-space:nowrap;
+  white-space: nowrap;
 }
 // update-end--author:liaozhiyang---date:20231218---for:【QQYUN-6366】升级到antd4.x
 
@@ -167,11 +175,11 @@ html[data-theme='dark'] .ant-input-affix-wrapper-textarea-with-clear-btn {
 // update-end--author:liaozhiyang---date:20230108---for:【QQYUN-7855】table页码同步3.x页面效果
 
 //update-begin--author:wangshuai---date:20240429---for:修改tinymce段落下拉框的字体和样式
-.tox .tox-tbtn__select-label{
+.tox .tox-tbtn__select-label {
   font-size: 14px;
 }
 
-.tox .tox-tbtn--select{
+.tox .tox-tbtn--select {
   width: 80px !important;
 }
 
@@ -204,7 +212,7 @@ html[data-theme='dark'] {
   .ant-form:not(.jeecg-form-detail-effect) {
     .ant-input-number.ant-input-number-disabled {
       .ant-input-number-input {
-        color:rgba(255, 255, 255, 0.25);
+        color: rgba(255, 255, 255, 0.25);
       }
     }
   }

+ 28 - 1
src/design/color.less

@@ -8,7 +8,7 @@ html {
   --sider-dark-bg-color: #273352;
   --sider-dark-darken-bg-color: #273352;
   --sider-dark-lighten-bg-color: #273352;
-  --sider-logo-bg-color:linear-gradient(180deg, #000000, #021d37);
+  --sider-logo-bg-color: linear-gradient(180deg, #000000, #021d37);
 }
 
 @white: #fff;
@@ -22,6 +22,33 @@ html {
 // }
 @iconify-bg-color: #5551;
 
+// =================================
+// ==============基础-变量=======
+// =================================
+@text-color: var(--el-text-color, rgba(0, 0, 0, 0.88));
+// @primary-1: 'blue';
+// @text-color-base: 'green';
+@component-background: var(--el-component-background, #fff);
+// @heading-color: 'rgb(255 255 255 / 65%)';
+// @text-color-secondary: '#8b949e';
+// @border-color-base: '#303030';
+// @header-light-bottom-border-color: '#303030';
+// @item-active-bg: '#111b26';
+// @app-content-background: '#1e1e1e';
+// @tree-node-selected-bg: '#11263c';
+// @alert-success-border-color: '#274916';
+// @alert-success-bg-color: '#162312';
+// @alert-success-icon-color: '#49aa19';
+// @alert-info-border-color: '#153450';
+// @alert-info-bg-color: '#111b26';
+// @alert-info-icon-color: '#177ddc';
+// @alert-warning-border-color: '#594214';
+// @alert-warning-bg-color: '#2b2111';
+// @alert-warning-icon-color: '#d89614';
+// @alert-error-border-color: '#58181c';
+// @alert-error-bg-color: '#2a1215';
+// @alert-error-icon-color: '#a61d24';
+
 // =================================
 // ==============border-color=======
 // =================================

+ 18 - 12
src/layouts/default/header/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <Header :class="getHeaderClass">
+  <ElHeader :class="getHeaderClass">
     <!-- left start -->
     <div :class="`${prefixCls}-left`">
       <!-- logo -->
@@ -11,7 +11,12 @@
       />
       <LayoutBreadcrumb v-if="getShowContent && getShowBread" :theme="getHeaderTheme" />
       <!-- 欢迎语 -->
-      <span v-if="getShowContent && getShowBreadTitle && !getIsMobile" :class="[prefixCls, `${prefixCls}--${getHeaderTheme}`,'headerIntroductionClass']"> {{t('layout.header.welcomeIn')}} {{ title }} </span>
+      <span
+        v-if="getShowContent && getShowBreadTitle && !getIsMobile"
+        :class="[prefixCls, `${prefixCls}--${getHeaderTheme}`, 'headerIntroductionClass']"
+      >
+        {{ t('layout.header.welcomeIn') }} {{ title }}
+      </span>
     </div>
     <!-- left end -->
 
@@ -41,8 +46,8 @@
       <!-- ai助手
       <Aide></Aide> -->
     </div>
-  </Header>
-  <LoginSelect ref="loginSelectRef" @success="loginSelectOk"></LoginSelect>
+  </ElHeader>
+  <LoginSelect ref="loginSelectRef" @success="loginSelectOk" />
 </template>
 <script lang="ts">
   import { defineComponent, unref, computed, ref, onMounted, toRaw } from 'vue';
@@ -74,13 +79,13 @@
   import LoginSelect from '/@/views/sys/login/LoginSelect.vue';
   import { useUserStore } from '/@/store/modules/user';
   import { useI18n } from '/@/hooks/web/useI18n';
-  import Aide from "@/views/dashboard/ai/components/aide/index.vue"
+  // import Aide from '@/views/dashboard/ai/components/aide/index.vue';
   const { t } = useI18n();
 
   export default defineComponent({
     name: 'LayoutHeader',
     components: {
-      Header: Layout.Header,
+      ElHeader: Layout.Header,
       AppLogo,
       LayoutTrigger,
       LayoutBreadcrumb,
@@ -96,7 +101,7 @@
       SettingDrawer: createAsyncComponent(() => import('/@/layouts/default/setting/index.vue'), {
         loading: true,
       }),
-      Aide
+      // Aide,
     },
     props: {
       fixed: propTypes.bool,
@@ -215,7 +220,7 @@
         loginSelectOk,
         loginSelectRef,
         title,
-        t
+        t,
       };
     },
   });
@@ -225,7 +230,7 @@
   //update-begin---author:scott ---date:2022-09-30  for:默认隐藏顶部菜单面包屑-----------
   //顶部欢迎语展示样式
   @prefix-cls: ~'@{namespace}-layout-header';
-  
+
   .ant-layout .@{prefix-cls} {
     display: flex;
     padding: 0 8px;
@@ -233,14 +238,14 @@
     height: @header-height;
     // update-end--author:liaozhiyang---date:20240407---for:【QQYUN-8762】顶栏高度
     align-items: center;
-    
+
     .headerIntroductionClass {
       margin-right: 4px;
       margin-bottom: 2px;
       border-bottom: 0px;
       border-left: 0px;
     }
-    
+
     &--light {
       .headerIntroductionClass {
         color: #000;
@@ -251,7 +256,8 @@
       .headerIntroductionClass {
         color: rgba(255, 255, 255, 1);
       }
-      .anticon, .truncate {
+      .anticon,
+      .truncate {
         color: rgba(255, 255, 255, 1);
       }
     }

+ 1 - 1
src/layouts/default/setting/SettingDrawer.tsx

@@ -341,7 +341,7 @@ export default defineComponent({
     return () => (
       <BasicDrawer {...attrs} title={t('layout.setting.drawerTitle')} width={330} class="setting-drawer">
         {unref(getShowDarkModeToggle) && <Divider>{() => t('layout.setting.darkMode')}</Divider>}
-        {unref(getShowDarkModeToggle) && <AppDarkModeToggle class="mx-auto" />}
+        {unref(getShowDarkModeToggle) && <AppDarkModeToggle class="mx-auto" type="setting" />}
         <Divider>{() => t('layout.setting.navMode')}</Divider>
         {renderSidebar()}
         <Divider>{() => t('layout.setting.sysTheme')}</Divider>

+ 6 - 6
src/layouts/default/setting/components/SelectItem.vue

@@ -1,7 +1,7 @@
 <template>
   <div :class="prefixCls">
     <span> {{ title }}</span>
-    <Select v-bind="getBindValue" :class="`${prefixCls}-select`" @change="handleChange" :disabled="disabled" size="small" :options="options" />
+    <ElSelect v-bind="getBindValue" :class="`${prefixCls}-select`" @change="handleChange" :disabled="disabled" size="small" :options="options" />
   </div>
 </template>
 <script lang="ts">
@@ -14,7 +14,7 @@
 
   export default defineComponent({
     name: 'SelectItem',
-    components: { Select },
+    components: { ElSelect: Select },
     props: {
       event: {
         type: Number as PropType<HandlerEnum>,
@@ -42,7 +42,7 @@
         return props.def ? { value: props.def, defaultValue: props.initValue || props.def } : {};
       });
 
-      function handleChange(e: ChangeEvent) {
+      function handleChange(e) {
         props.event && baseHandler(props.event, e);
       }
       return {
@@ -66,8 +66,8 @@
     }
   }
   html[data-theme='dark'] {
-    .@{prefix-cls} {
-      color: rgba(255, 255, 255, 0.8);
-    }
+    // .@{prefix-cls} {
+    //   color: rgba(255, 255, 255, 0.8);
+    // }
   }
 </style>

+ 3 - 3
src/layouts/default/setting/components/SwitchItem.vue

@@ -1,7 +1,7 @@
 <template>
   <div :class="prefixCls">
     <span> {{ title }}</span>
-    <Switch
+    <ElSwitch
       v-bind="getBindValue"
       @change="handleChange"
       :disabled="disabled"
@@ -21,7 +21,7 @@
 
   export default defineComponent({
     name: 'SwitchItem',
-    components: { Switch },
+    components: { ElSwitch: Switch },
     props: {
       event: {
         type: Number as PropType<HandlerEnum>,
@@ -43,7 +43,7 @@
       const getBindValue = computed(() => {
         return props.def ? { checked: props.def } : {};
       });
-      function handleChange(e: ChangeEvent) {
+      function handleChange(e: boolean | string | number) {
         props.event && baseHandler(props.event, e);
       }
       return {

+ 1 - 1
src/layouts/default/setting/handler.ts

@@ -1,4 +1,4 @@
-import { HandlerEnum, tabsThemeOptions} from './enum';
+import { HandlerEnum, tabsThemeOptions } from './enum';
 import { updateHeaderBgColor, updateSidebarBgColor } from '/@/logics/theme/updateBackground';
 import { updateColorWeak } from '/@/logics/theme/updateColorWeak';
 import { updateGrayMode } from '/@/logics/theme/updateGrayMode';

+ 3 - 3
src/layouts/default/tabs/index.less

@@ -48,7 +48,7 @@ html[data-theme='light'] {
         padding-right: 12px;
         line-height: calc(@multiple-height - 4px);
         color: @text-color-base;
-        background-color: @component-background;
+        // background-color: @component-background;
         transition: none;
 
         .ant-tabs-tab-btn {
@@ -105,8 +105,8 @@ html[data-theme='light'] {
       .ant-tabs-tab-active {
         position: relative;
         padding-left: 18px;
-        color: @white !important;
-        background: @primary-color;
+        // color: @white !important;
+        // background: @primary-color;
         border: 1px solid transparent;
         transition: none;
 

File diff suppressed because it is too large
+ 0 - 3
src/layouts/default/tabs/index.vue


+ 2 - 2
src/layouts/default/tabs/tabs.theme.card.less

@@ -53,7 +53,7 @@ html[data-theme='light'] {
         height: @tabHeight;
         line-height: @tabHeight;
         color: @text-color-base;
-        background-color: @component-background;
+        // background-color: @component-background;
         padding: 0 20px 0 30px;
         margin: 0 10px 0 0 !important;
 
@@ -129,7 +129,7 @@ html[data-theme='light'] {
 
       .ant-tabs-tab-active {
         position: relative;
-        color: @primary-color !important;
+        // color: @primary-color !important;
         border: 1px solid transparent;
         border-bottom: 1px solid @primary-color !important;
         font-weight: inherit;

+ 15 - 1
src/logics/theme/dark.ts

@@ -15,10 +15,24 @@ export async function updateDarkTheme(mode: string | null = 'light') {
     if (!hasDarkClass) {
       addClass(htmlRoot, 'dark');
     }
-  } else {
+  } else if (mode === 'dark') {
     htmlRoot.setAttribute('data-theme', 'light');
     if (hasDarkClass) {
       removeClass(htmlRoot, 'dark');
     }
+  } else {
+    mode && htmlRoot.setAttribute('data-theme', mode);
+  }
+}
+
+export async function updateAppTheme(mode: string = 'light', oldMode?: string) {
+  const htmlRoot = document.getElementById('htmlRoot');
+  if (!htmlRoot) {
+    return;
+  }
+  const hasDarkClass = oldMode ? hasClass(htmlRoot, oldMode) : false;
+  htmlRoot.setAttribute('data-theme', mode);
+  if (oldMode && hasDarkClass) {
+    removeClass(htmlRoot, oldMode);
   }
 }

+ 10 - 3
src/logics/theme/updateBackground.ts

@@ -62,8 +62,15 @@ export function updateSidebarBgColor(color?: string) {
     }
   }
   // update-begin--author:liaozhiyang---date:20230811---for:【QQYUN-5922】logo背景色渐变
-  let findIndex = SIDE_BAR_BG_COLOR_LIST.findIndex((item) => item === color);
-  setCssVar(SIDER_LOGO_BG_COLOR, findIndex == -1 ? 'linear-gradient(180deg, #000000, #282828)' : SIDER_LOGO_BG_COLOR_LIST[findIndex]);
+  const findIndex = SIDE_BAR_BG_COLOR_LIST.findIndex((item) => item === color);
+  setCssVar(
+    SIDER_LOGO_BG_COLOR,
+    findIndex == -1
+      ? ![ThemeEnum.DARK, ThemeEnum.LIGHT].includes(appStore.getDarkMode as ThemeEnum)
+        ? `linear-gradient(180deg, ${color}, ${lighten(color!, 6)})`
+        : 'linear-gradient(180deg, #000000, #282828)'
+      : SIDER_LOGO_BG_COLOR_LIST[findIndex]
+  );
   // update-end--author:liaozhiyang---date:20230811---for:【QQYUN-5922】llogo背景色渐变
   setCssVar(SIDER_DARK_BG_COLOR, color);
   setCssVar(SIDER_DARK_DARKEN_BG_COLOR, darken(color!, 6));
@@ -76,7 +83,7 @@ export function updateSidebarBgColor(color?: string) {
   let isThemeBright = false;
   if (['#fff', '#ffffff'].includes(color!.toLowerCase()) && !darkMode) {
     theme = ThemeEnum.LIGHT;
-  } else if (['#009688', '#e74c3c','#037bd5'].includes(color!.toLowerCase()) && !darkMode) {
+  } else if (['#009688', '#e74c3c', '#037bd5'].includes(color!.toLowerCase()) && !darkMode) {
     theme = ThemeEnum.DARK;
     isThemeBright = true;
   } else {

+ 15 - 15
src/main.ts

@@ -1,4 +1,4 @@
-import type { MainAppProps } from "#/main";
+import type { MainAppProps } from '#/main';
 import 'uno.css';
 import '/@/design/index.less';
 import 'ant-design-vue/dist/reset.css';
@@ -18,9 +18,9 @@ import { registerGlobComp } from '/@/components/registerGlobComp';
 import { registerThirdComp } from '/@/settings/registerThirdComp';
 import { registerSuper } from '/@/views/super/registerSuper';
 import { useSso } from '/@/hooks/web/useSso';
-import { checkIsQiankunMicro } from "/@/qiankun/micro";
-import { autoUseQiankunMicro } from "/@/qiankun/micro/qiankunMicro";
-import { useAppStoreWithOut } from "@/store/modules/app";
+import { checkIsQiankunMicro } from '/@/qiankun/micro';
+import { autoUseQiankunMicro } from '/@/qiankun/micro/qiankunMicro';
+import { useAppStoreWithOut } from '@/store/modules/app';
 
 // 注册online模块lib
 import { registerPackages } from '/@/utils/monorepo/registerPackages';
@@ -30,12 +30,12 @@ async function main() {
   if (checkIsQiankunMicro()) {
     // 【JEECG作为乾坤子应用】以乾坤子应用模式启动
     // await autoUseQiankunMicro(bootstrap)
-    await autoUseQiankunMicro(bootstrap)
+    await autoUseQiankunMicro(bootstrap);
   } else {
     // 获取参数
     const props = getMainAppProps();
     // 普通启动
-    await bootstrap(props)
+    await bootstrap(props);
   }
 }
 
@@ -73,7 +73,7 @@ async function bootstrap(props?: MainAppProps) {
 
   // 注册super应用路由
   await registerSuper(app);
-  
+
   // 配置路由
   setupRouter(app);
 
@@ -95,9 +95,9 @@ async function bootstrap(props?: MainAppProps) {
   // 挂载应用
   app.mount(getMountContainer(props), true);
 
-  console.log(" vue3 app 加载完成!")
+  console.log(' vue3 app 加载完成!');
 
-  return app
+  return app;
 }
 
 // 获取应用挂载容器
@@ -114,23 +114,23 @@ function getMainAppProps(): MainAppProps {
   // 从 queryString 中获取
   const searchParams = new URLSearchParams(window.location.search);
   // 隐藏侧边栏(菜单)
-  let hideSider = searchParams.get('hideSider') === 'true';
+  const hideSider = searchParams.get('hideSider') === 'true';
   // 隐藏顶部
-  let hideHeader = searchParams.get('hideHeader') === 'true';
+  const hideHeader = searchParams.get('hideHeader') === 'true';
   // 隐藏 多Tab 切换
-  let hideMultiTabs = searchParams.get('hideMultiTabs') === 'true';
+  const hideMultiTabs = searchParams.get('hideMultiTabs') === 'true';
 
   return {
     hideSider,
     hideHeader,
-    hideMultiTabs
-  }
+    hideMultiTabs,
+  };
 }
 
 // 配置主应用参数
 function setupProps(props?: MainAppProps) {
   if (!props) {
-    return
+    return;
   }
   const appStore = useAppStoreWithOut();
   appStore.setMainAppProps(props);

+ 329 - 0
src/settings/designSetting.ts

@@ -4,6 +4,335 @@ export const prefixCls = 'jeecg';
 
 export const darkMode = ThemeEnum.LIGHT;
 
+export const APP_MODE_LIST: Record<string, any>[] = [
+  { label: '浅色主题', value: ThemeEnum.LIGHT, bg: '#f5f5f5', text: '#000000' },
+  { label: '深色深色', value: ThemeEnum.DARK, bg: '#000000', text: '#ffffff' },
+  // 深蓝灰系(夜间低蓝光)
+  {
+    label: '深海工业',
+    desc: '深海工业(深色科技主题)',
+    value: 'blue',
+    token: {
+      // 核心色板
+      colorPrimary: '#2D8CF0', // 科技蓝(主交互色)
+      colorInfo: '#4DC4FF', // 信息蓝(辅助科技色)
+      colorSuccess: '#52C41A', // 生态绿(状态色)
+      colorWarning: '#FAAD14', // 琥珀黄(警示色)
+      colorError: '#FF4D4F', // 警报红(错误色)
+
+      // 背景体系
+      colorBgContainer: '#1A2330', // 主容器背景(深蓝灰)
+      colorBgLayout: '#121A24', // 全局背景(更深的基础色)
+      colorBgElevated: '#223040', // 浮层背景(带蓝调的灰)
+
+      // 文字体系
+      colorText: '#E0E0E0', // 主文字(柔白)
+      colorTextSecondary: '#A0AEC0', // 次级文字(科技灰)
+      colorTextHeading: '#FFFFFF', // 标题文字(纯白)
+      colorTextQuaternary: '#A0AEC0',
+      colorTextTertiary: '#A0AEC0b3',
+
+      // 交互状态
+      colorPrimaryHover: '#4DA3FF', // Hover(更明亮的科技蓝)
+      colorPrimaryActive: '#1A6FEB', // 点击(深科技蓝)
+      controlItemBgActive: 'rgba(45, 140, 240, 0.2)', // 选中态(透明蓝)
+
+      // 边框与分割线
+      colorBorder: '#2D8CF055', // 常规边框(半透明科技蓝)
+      colorBorderSecondary: '#2D3748',
+      colorSplit: '#2D374840', // 分割线(深灰)
+
+      // 特殊效果
+      boxShadow: '0 4px 12px rgba(0, 40, 80, 0.3)', // 科技感投影
+      boxShadowSecondary: '0 2px 8px rgba(45,140,240,0.2)', // 辅助投影
+    },
+  },
+  // 极光灰(浅色护眼主题)
+  {
+    label: '极光浅色',
+    desc: '极光浅色(护眼主题)',
+    value: 'gray',
+    token: {
+      // 核心色板
+      colorPrimary: '#2D8CF0', // 保持品牌一致性
+      colorInfo: '#5A7D9C', // 工业金属灰蓝
+      colorSuccess: '#3AA17E', // 矿物绿
+      colorWarning: '#D89614', // 工业黄铜色
+      colorError: '#E84749', // 机械红
+
+      // 背景体系
+      colorBgContainer: '#F0F4F8', // 主背景(护眼浅灰蓝)
+      colorBgLayout: '#E3E9EF', // 全局背景(柔和过渡)
+      colorBgElevated: '#FFFFFF', // 浮层(纯白)
+
+      // 文字体系
+      colorText: '#2D3748', // 主文字(深钢灰)
+      colorTextSecondary: '#718096', // 次级(工业灰)
+      colorTextHeading: '#1A202C', // 标题(深空黑)
+      colorTextQuaternary: '#718096',
+      colorTextTertiary: '#718096b3',
+
+      // 交互状态
+      colorPrimaryHover: '#4DA3FF', // Hover(科技蓝亮色)
+      colorPrimaryActive: '#1A6FEB', // 点击(强化反馈)
+      controlItemBgActive: '#EBF4FF', // 选中态(浅蓝背景)
+
+      // 边框与分割线
+      colorBorder: '#CBD5E0', // 常规边框(浅工业灰)
+      colorBorderSecondary: '#CBD5E0',
+      colorSplit: '#E2E8F0', // 分割线(更浅灰)
+
+      // 特殊效果
+      boxShadow: '0 4px 12px rgba(160,174,192,0.15)', // 柔和投影
+      boxShadowSecondary: '0 2px 6px rgba(45,140,240,0.1)',
+    },
+  },
+  // 工业绿境(深绿护眼主题)
+  {
+    label: '工业绿境',
+    desc: '工业绿境(深绿护眼主题)',
+    value: 'green',
+    token: {
+      // 核心色板
+      colorPrimary: '#2B8C75', // 深科技绿(工业环保主色)
+      colorInfo: '#48A9A6', // 水纹青(数据可视化专用)
+      colorSuccess: '#3AA17E', // 矿物绿(状态标识)
+      colorWarning: '#D4B15F', // 青铜色(警示色)
+      colorError: '#D9534F', // 锈迹红(故障色)
+
+      // 背景体系
+      colorBgContainer: '#1E2A2B', // 主容器(深墨绿)
+      colorBgLayout: '#152021', // 全局背景(夜间森林)
+      colorBgElevated: '#253B3C', // 浮层(带绿调的深灰)
+
+      // 文字体系
+      colorText: '#D1E0DB', // 主文字(青瓷白)
+      colorTextSecondary: '#8C9E9A', // 次级(石灰绿)
+      colorTextHeading: '#FFFFFF', // 标题(纯白)
+      colorTextQuaternary: '#8C9E9A',
+      colorTextTertiary: '#8C9E9Ab3',
+
+      // 交互状态
+      colorPrimaryHover: '#3CA588', // Hover(激活绿)
+      colorPrimaryActive: '#1E6F5C', // 点击(深翡翠)
+      controlItemBgActive: 'rgba(43,140,117,0.25)', // 选中态(透明绿)
+
+      // 边框与分割线
+      colorBorder: '#2B8C7544', // 常规边框(半透明绿)
+      colorBorderSecondary: '#304A4D',
+      colorSplit: '#304A4D', // 分割线(矿石灰)
+
+      // 特殊效果
+      boxShadow: '0 4px 12px rgba(20,60,50,0.4)', // 丛林投影
+      boxShadowSecondary: '0 2px 8px rgba(67,170,139,0.25)',
+    },
+  },
+  // 米白工坊(浅色极简主题)
+  {
+    label: '米白工坊',
+    desc: '米白工坊(浅色极简主题)',
+    value: 'mi-white',
+    token: {
+      // 核心色板
+      colorPrimary: '#5B7C8D', // 蓝图灰(主交互色)
+      colorInfo: '#6D9BBF', // 天空蓝(辅助色)
+      colorSuccess: '#7AA95C', // 橄榄绿(通过色)
+      colorWarning: '#CC9B45', // 琥珀金(注意色)
+      colorError: '#C4554A', // 陶土红(警告色)
+
+      // 背景体系
+      colorBgContainer: '#F5F1E6', // 主背景(羊皮纸米白)
+      colorBgLayout: '#EBE5D8', // 全局背景(浅亚麻)
+      colorBgElevated: '#FFFFFF', // 浮层(纯白)
+
+      // 文字体系
+      colorText: '#3E4C5A', // 主文字(深石板)
+      colorTextSecondary: '#6B7C8D', // 次级(工业灰)
+      colorTextHeading: '#2B3945', // 标题(钢青)
+      colorTextQuaternary: '#6B7C8D',
+      colorTextTertiary: '#6B7C8Db3',
+
+      // 交互状态
+      colorPrimaryHover: '#759CAD', // Hover(雾霾蓝)
+      colorPrimaryActive: '#4A6776', // 点击(深海蓝)
+      controlItemBgActive: '#E8EDF2', // 选中态(极浅蓝)
+
+      // 边框与分割线
+      colorBorder: '#D3CEC4', // 常规边框(砂岩色)
+      colorBorderSecondary: '#D3CEC4',
+      colorSplit: '#E0DCD2', // 分割线(浅麻布)
+
+      // 特殊效果
+      boxShadow: '0 4px 12px rgba(91,124,141,0.1)', // 纸张投影
+      boxShadowSecondary: '0 2px 6px rgba(123,156,189,0.08)',
+    },
+  },
+  // 钢坯熔炉(金属工业主题)
+  {
+    label: '钢坯熔炉',
+    desc: '钢坯熔炉(金属工业主题)',
+    value: 'steel',
+    token: {
+      // 核心色板
+      colorPrimary: '#4A5568', // 冷轧钢灰(主色)
+      colorInfo: '#63B3ED', // 淬火蓝(高光色)
+      colorSuccess: '#68D391', // 电解绿(状态色)
+      colorWarning: '#F6AD55', // 熔炉橙(警示色)
+      colorError: '#FC8181', // 高温红(紧急色)
+
+      // 背景体系
+      colorBgContainer: '#2D3748', // 主容器(钢板灰)
+      colorBgLayout: '#1A202C', // 全局背景(锻造黑)
+      colorBgElevated: '#3C4657', // 浮层(氧化钢)
+
+      // 文字体系
+      colorText: '#CBD5E0', // 主文字(冷轧银)
+      colorTextSecondary: '#8A95A5', // 次级(铸铁灰)
+      colorTextHeading: '#FFFFFF', // 标题(高亮白)
+      colorTextQuaternary: '#8A95A5',
+      colorTextTertiary: '#8A95A5b3',
+
+      // 交互状态
+      colorPrimaryHover: '#5F6B7C', // Hover(高温钢)
+      colorPrimaryActive: '#3B4858', // 点击(锻压态)
+      controlItemBgActive: 'rgba(74,85,104,0.3)', // 选中(金属氧化层)
+
+      // 边框与分割线
+      colorBorder: '#4A556877', // 常规边框(半透明钢灰)
+      colorBorderSecondary: '#4A5568',
+      colorSplit: '#4A556833', // 分割线(金属接缝)
+
+      // 特殊效果
+      boxShadow: '0 4px 12px rgba(12,25,40,0.35)', // 铸造投影
+      boxShadowSecondary: '0 2px 8px rgba(99,179,237,0.2)', // 淬火光效
+    },
+  },
+  // 机械绿光(赛博护眼主题)
+  {
+    label: '机械绿光',
+    desc: '机械绿光(赛博护眼主题)',
+    value: 'mechanism',
+    token: {
+      // 核心色板
+      colorPrimary: '#00C89B', // 赛博荧光绿
+      colorInfo: '#5BC0EB', // 液态冷却蓝
+      colorSuccess: '#4CD964', // 数字生态绿
+      colorWarning: '#FFD700', // 机械警示黄
+      colorError: '#FF3B30', // 故障信号红
+
+      // 背景体系
+      colorBgContainer: '#0D1F2D', // 控制台黑(亮度8%)
+      colorBgLayout: '#08141E', // 全息投影基底
+      colorBgElevated: '#1A2B3C', // 悬浮面板
+
+      // 文字体系
+      colorText: '#C0F0E4', // HUD显示绿
+      colorTextSecondary: '#7D9BA6', // 辅助信息灰
+      colorTextHeading: '#FFFFFF', // 全息投影白
+      colorTextQuaternary: '#7D9BA6',
+      colorTextTertiary: '#7D9BA6b3',
+
+      // 动态交互
+      colorPrimaryHover: 'color-mix(in srgb, #00C89B 80%, white)', // 荧光增强
+      colorPrimaryActive: 'color-mix(in srgb, #00C89B 80%, black)',
+      controlItemBgActive: 'rgba(0,200,155,0.15)', // 矩阵选择态
+
+      // 工业特征
+      colorBorder: 'rgba(0,200,155,0.3)', // 光污染边框
+      colorBorderSecondary: '#00C89B',
+      colorSplit: '#1E3440', // 机械分隔槽
+      wireframeBorder: 2, // 重工业边框厚度
+
+      // 特效系统
+      boxShadow: '0 8px 24px -4px rgba(0,200,155,0.25)', // 能量场投影
+      boxShadowSecondary: '0 0 12px rgba(91,192,235,0.2)', // 冷却液辉光
+    },
+  },
+  // 熔岩锻炉(热力护眼主题)
+  {
+    label: '熔岩锻炉',
+    desc: '熔岩锻炉(热力护眼主题)',
+    value: 'molten',
+    token: {
+      // 核心色板
+      colorPrimary: '#E34A27', // 熔岩橙
+      colorInfo: '#5A7D9C', // 淬火钢蓝
+      colorSuccess: '#3AA17E', // 冷却绿
+      colorWarning: '#FFB347', // 高温黄
+      colorError: '#D32F2F', // 紧急停机红
+
+      // 背景体系
+      colorBgContainer: '#2A1E1A', // 锻造台基底
+      colorBgLayout: '#1A1210', // 熔炉内壁
+      colorBgElevated: '#3D2B26', // 金属工作台
+      colorFillAlter: '#3D2B26', // tabs卡片填充
+
+      // 文字系统
+      colorText: '#EDDDD4', // 锻件反光白
+      colorTextSecondary: '#A8958C', // 氧化层文字
+      colorTextHeading: '#FFD8B1', // 高温警示标题
+      colorTextQuaternary: '#A8958C',
+      colorTextTertiary: '#A8958Cb3',
+
+      // 热力交互
+      colorPrimaryHover: '#FF6B42', // 加热态
+      colorPrimaryActive: '#C23312', // 锻压态
+      controlItemBgActive: 'radial-gradient(circle, rgba(227,74,39,0.2) 0%, transparent 100%)',
+
+      // 物理材质
+      colorBorder: '#5A4D48', // 铸铁边框
+      colorBorderSecondary: '#5A4D48', // 铸铁边框
+      colorSplit: '#814C37', // 锻件接缝
+      motionDurationMid: '0.3s', // 重型机械动画速度
+
+      // 环境特效
+      boxShadow: '0 6px 20px -8px rgba(227,74,39,0.4)', // 热辐射
+      boxShadowSecondary: 'inset 0 0 12px rgba(255,179,71,0.15)', // 内部高温
+    },
+  },
+  // 纳米灰(未来材料主题)
+  {
+    label: '纳米灰',
+    desc: '纳米灰(未来材料主题)',
+    value: 'nano',
+    token: {
+      // 核心色板
+      colorPrimary: '#6B7C8D', // 纳米沉积灰
+      colorInfo: '#94A8B8', // 量子隧穿蓝
+      colorSuccess: '#7BA05B', // 生物涂层绿
+      colorWarning: '#D4A418', // 临界态金黄
+      colorError: '#C4554A', // 分子裂解红
+
+      // 背景体系
+      colorBgContainer: '#F0F3F6', // 纳米材料白(亮度94%)
+      colorBgLayout: '#E1E6EB', // 原子沉积层
+      colorBgElevated: '#FFFFFF', // 纯晶格基底
+
+      // 文字系统
+      colorText: '#3D4A5A', // 分子结构黑
+      colorTextSecondary: '#6B7C8D', // 表面吸附灰
+      colorTextHeading: '#243140', // 量子隧穿标题
+      colorTextQuaternary: '#6B7C8D',
+      colorTextTertiary: '#6B7C8Db3',
+
+      // 纳米交互
+      colorPrimaryHover: '#8C9DAD', // 表面活化
+      colorPrimaryActive: '#4E5D6B', // 原子压缩
+      controlItemBgActive: 'repeating-linear-gradient(45deg, transparent, transparent 3px, rgba(107,124,141,0.1) 3px, rgba(107,124,141,0.1) 6px)',
+
+      // 微观结构
+      colorBorder: '#CAD3DC', // 晶界边框
+      colorBorderSecondary: '#5A4D48',
+      colorSplit: '#D8E1E8', // 原子空位
+      borderRadius: 3, // 分子晶格圆角
+
+      // 量子特效
+      boxShadow: '0 4px 16px -6px rgba(107,124,141,0.2)', // 表面电子云
+      boxShadowSecondary: '0 0 8px rgba(148,168,184,0.1)', // 隧穿效应辉光
+    },
+  },
+];
+
 // app theme preset color
 export const APP_PRESET_COLOR_LIST: string[] = [
   '#0960bd',

+ 5 - 6
src/store/modules/app.ts

@@ -1,4 +1,4 @@
-import type { MainAppProps } from "#/main";
+import type { MainAppProps } from '#/main';
 import type { ProjectConfig, HeaderSetting, MenuSetting, TransitionSetting, MultiTabsSetting } from '/#/config';
 import type { BeforeMiniState } from '/#/store';
 
@@ -23,9 +23,9 @@ interface AppState {
   // When the window shrinks, remember some states, and restore these states when the window is restored
   beforeMiniInfo: BeforeMiniState;
   // 页面跳转临时参数存储
-  messageHrefParams: any,
+  messageHrefParams: any;
   // 应用参数
-  mainAppProps: MainAppProps,
+  mainAppProps: MainAppProps;
 }
 let timeId: TimeoutHandle;
 export const useAppStore = defineStore({
@@ -79,7 +79,7 @@ export const useAppStore = defineStore({
     getMultiTabsSetting(): MultiTabsSetting {
       return this.getProjectConfig.multiTabsSetting;
     },
-    getMessageHrefParams():any{
+    getMessageHrefParams(): any {
       return this.messageHrefParams;
     },
     getMainAppProps(): MainAppProps {
@@ -151,12 +151,11 @@ export const useAppStore = defineStore({
     },
 
     // 设置主应用参数
-    setMainAppProps(args: MainAppProps)  {
+    setMainAppProps(args: MainAppProps) {
       this.mainAppProps.hideHeader = args.hideHeader ?? false;
       this.mainAppProps.hideSider = args.hideSider ?? false;
       this.mainAppProps.hideMultiTabs = args.hideMultiTabs ?? false;
     },
-
   },
 });
 

+ 18 - 16
src/views/dashboard/Analysis/homePage/IndexTask.vue

@@ -385,24 +385,26 @@
 
     :deep(
       .ant-table-small
-      > .ant-table-content
-      > .ant-table-fixed-left
-      > .ant-table-body-outer
-      > .ant-table-body-inner
-      > table
-      > .ant-table-thead
-      > tr
-      > th),
+        > .ant-table-content
+        > .ant-table-fixed-left
+        > .ant-table-body-outer
+        > .ant-table-body-inner
+        > table
+        > .ant-table-thead
+        > tr
+        > th
+    ),
     :deep(
       .ant-table-small
-      > .ant-table-content
-      > .ant-table-fixed-right
-      > .ant-table-body-outer
-      > .ant-table-body-inner
-      > table
-      > .ant-table-thead
-      > tr
-      > th) {
+        > .ant-table-content
+        > .ant-table-fixed-right
+        > .ant-table-body-outer
+        > .ant-table-body-inner
+        > table
+        > .ant-table-thead
+        > tr
+        > th
+    ) {
       border-bottom: 1px solid #90aeff;
     }
 

+ 1 - 1
src/views/equipmentLifecycle/device/tree/tree.vue

@@ -27,7 +27,7 @@
 
       .ant-tabs-content {
         height: 100%;
-        background-color: #fff;
+        background-color: @component-background;
         border: 1px solid rgba(5, 5, 5, 0.06);
         border-top: 0;
         border-radius: 0 0 6px 6px;

+ 141 - 141
src/views/system/usersetting/UserSetting.vue

@@ -5,14 +5,14 @@
         <template v-for="item in componentList" :key="item.key">
           <TabPane>
             <template #tab>
-                <span style="display:flex;align-items: center;cursor: pointer">
-                  <!--<Icon :icon="item.icon" class="icon-font-color"/>-->
-                  <span style="width: 30px">
-                    <img v-if="activeKey === item.key || isDark" :src="item.img2" style="height: 18px"/>
-                    <img v-else :src="item.img1" style="height: 16px"/>
-                  </span>
-                  {{item.name}}
+              <span style="display: flex; align-items: center; cursor: pointer">
+                <!--<Icon :icon="item.icon" class="icon-font-color"/>-->
+                <span style="width: 30px">
+                  <img v-if="activeKey === item.key || isDark" :src="item.img2" style="height: 18px" />
+                  <img v-else :src="item.img1" style="height: 16px" />
                 </span>
+                {{ item.name }}
+              </span>
             </template>
             <component :is="item.component" v-if="activeKey === item.key && !item.isSlot" />
             <slot name="component" v-if="activeKey === item.key && item.isSlot" />
@@ -24,156 +24,156 @@
 </template>
 
 <script lang="ts">
-import { ref, defineComponent, onMounted, provide, computed } from "vue";
-import { Tabs } from "ant-design-vue";
-import { ScrollContainer } from "/@/components/Container";
-import { settingList } from "./UserSetting.data";
-import BaseSetting from "./BaseSetting.vue";
-import AccountSetting from "./AccountSetting.vue";
-import TenantSetting from "./TenantSetting.vue";
-import WeChatDingSetting from './WeChatDingSetting.vue';
-import { useRouter } from "vue-router";
-import { useDesign } from '/@/hooks/web/useDesign';
-import {useRootSetting} from "/@/hooks/setting/useRootSetting";
-import {ThemeEnum} from "/@/enums/appEnum";
-export default defineComponent({
-  components: {
-    ScrollContainer,
-    Tabs,
-    TabPane: Tabs.TabPane,
-    BaseSetting,
-    AccountSetting,
-    TenantSetting,
-    WeChatDingSetting,
-  },
-  props:{
-    componentList:{
-      type:Array,
-      default:settingList
-    }
-  },
-  setup() {
-    const { prefixCls } = useDesign('user-account-setting-container');
-    const { getDarkMode} = useRootSetting();
-    const isDark = computed(() => getDarkMode.value === ThemeEnum.DARK);
-    const activeKey = ref<string>('1');
-    //是否为vip
-    const showVip = ref<boolean>(false);
-    //vip编码
-    const vipCode = ref<string>('');
-    const router = useRouter();
-    const componentList = computed(()=>{
-      if(showVip.value){
-        return settingList;
-      }
-      return settingList.filter((item)=> item.component != 'MyVipSetting');
-    })
+  import { ref, defineComponent, onMounted, provide, computed } from 'vue';
+  import { Tabs } from 'ant-design-vue';
+  import { ScrollContainer } from '/@/components/Container';
+  import { settingList } from './UserSetting.data';
+  import BaseSetting from './BaseSetting.vue';
+  import AccountSetting from './AccountSetting.vue';
+  import TenantSetting from './TenantSetting.vue';
+  import WeChatDingSetting from './WeChatDingSetting.vue';
+  import { useRouter } from 'vue-router';
+  import { useDesign } from '/@/hooks/web/useDesign';
+  import { useRootSetting } from '/@/hooks/setting/useRootSetting';
+  import { ThemeEnum } from '/@/enums/appEnum';
+  export default defineComponent({
+    components: {
+      ScrollContainer,
+      Tabs,
+      TabPane: Tabs.TabPane,
+      BaseSetting,
+      AccountSetting,
+      TenantSetting,
+      WeChatDingSetting,
+    },
+    props: {
+      componentList: {
+        type: Array,
+        default: settingList,
+      },
+    },
+    setup() {
+      const { prefixCls } = useDesign('user-account-setting-container');
+      const { getDarkMode } = useRootSetting();
+      const isDark = computed(() => getDarkMode.value === ThemeEnum.DARK);
+      const activeKey = ref<string>('1');
+      //是否为vip
+      const showVip = ref<boolean>(false);
+      //vip编码
+      const vipCode = ref<string>('');
+      const router = useRouter();
+      const componentList = computed(() => {
+        if (showVip.value) {
+          return settingList;
+        }
+        return settingList.filter((item) => item.component != 'MyVipSetting');
+      });
 
-    /**
-     * 组件标题点击事件,解决第二次不加载数据
-     * @param key
-     */
-    function componentClick(key) {
-      activeKey.value = key;
-    }
+      /**
+       * 组件标题点击事件,解决第二次不加载数据
+       * @param key
+       */
+      function componentClick(key) {
+        activeKey.value = key;
+      }
 
-    function goToMyTeantPage(){
-      //update-begin---author:wangshuai ---date:20230721  for:【QQYUN-5726】邀请加入租户加个按钮直接跳转过去------------
-      //如果请求参数包含我的租户,直接跳转过去
-      let query = router.currentRoute.value.query;
-      if(query && query.page === 'tenantSetting'){
-        activeKey.value = "2";
+      function goToMyTeantPage() {
+        //update-begin---author:wangshuai ---date:20230721  for:【QQYUN-5726】邀请加入租户加个按钮直接跳转过去------------
+        //如果请求参数包含我的租户,直接跳转过去
+        let query = router.currentRoute.value.query;
+        if (query && query.page === 'tenantSetting') {
+          activeKey.value = '2';
+        }
+        //update-end---author:wangshuai ---date:20230721  for:【QQYUN-5726】邀请加入租户加个按钮直接跳转过去------------
       }
-      //update-end---author:wangshuai ---date:20230721  for:【QQYUN-5726】邀请加入租户加个按钮直接跳转过去------------
-    }
-    
-    onMounted(()=>{
-      goToMyTeantPage();
-    })
-    
-    return {
-      prefixCls,
-      settingList,
-      tabBarStyle: {
-        width: "220px",
-        marginBottom: "200px"
-      },
-      componentClick,
-      activeKey,
-      isDark
-    };
-  }
-});
+
+      onMounted(() => {
+        goToMyTeantPage();
+      });
+
+      return {
+        prefixCls,
+        settingList,
+        tabBarStyle: {
+          width: '220px',
+          marginBottom: '200px',
+        },
+        componentClick,
+        activeKey,
+        isDark,
+      };
+    },
+  });
 </script>
 <style lang="less" scoped>
-.user-account-setting {
-  margin: 20px;
+  .user-account-setting {
+    margin: 20px;
 
-  .base-title {
-    padding-left: 0;
-  }
+    .base-title {
+      padding-left: 0;
+    }
 
-  //tabs弹窗左边样式
-  :deep(.ant-tabs-nav){
-    height: 260px;
+    //tabs弹窗左边样式
+    :deep(.ant-tabs-nav) {
+      height: 260px;
+    }
+    //tabs弹窗右边边样式
+    :deep(.ant-tabs-content-holder) {
+      position: relative;
+      left: 12px;
+      height: auto !important;
+    }
   }
-  //tabs弹窗右边边样式
-  :deep(.ant-tabs-content-holder){
-    position: relative;
-    left: 12px;
-    height: auto !important;
+  //tab点击样式
+  :deep(.ant-tabs-tab-active) {
+    border-radius: 0 20px 20px 0;
+    background-color: #1294f7 !important;
+    color: #fff !important;
+    .icon-font-color {
+      color: #fff;
+    }
   }
-}
-//tab点击样式
-:deep(.ant-tabs-tab-active){
-  border-radius: 0 20px 20px 0;
-  background-color: #1294f7!important;
-  color: #fff!important;
-  .icon-font-color{
-    color: #fff;
+  :deep(.ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn) {
+    color: white !important;
   }
-}
-:deep(.ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn){
-  color: white !important;
-}
-:deep(.ant-tabs-ink-bar){
-  visibility: hidden;
-}
-:deep(.ant-tabs-nav-list){
-  padding-top:14px;
-  padding-right:14px;
-}
-
-.vip-height{
-  //tabs弹窗左边样式
-  :deep(.ant-tabs-nav){
-    height: 310px !important;
+  :deep(.ant-tabs-ink-bar) {
+    visibility: hidden;
   }
-}
-.vip-background{
-  :deep(.ant-tabs-content-holder){
-    background: transparent;
+  :deep(.ant-tabs-nav-list) {
+    padding-top: 14px;
+    padding-right: 14px;
   }
-  :deep(.ant-tabs-tabpane){
-    padding-left: 0 !important;
+
+  .vip-height {
+    //tabs弹窗左边样式
+    :deep(.ant-tabs-nav) {
+      height: 310px !important;
+    }
+  }
+  .vip-background {
+    :deep(.ant-tabs-content-holder) {
+      background: transparent;
+    }
+    :deep(.ant-tabs-tabpane) {
+      padding-left: 0 !important;
+    }
   }
-}
 </style>
 
 <style lang="less">
-@prefix-cls: ~'@{namespace}-user-account-setting-container';
+  @prefix-cls: ~'@{namespace}-user-account-setting-container';
 
-.@{prefix-cls} {
-  .ant-tabs-tab-active {
-    background-color: @item-active-bg;
-  }
-  //tabs弹窗左边样式
- .ant-tabs-nav{
-    background-color: @component-background;
-  }
-  //tabs弹窗右边边样式
-  .ant-tabs-content-holder{
-    background: @component-background;
+  .@{prefix-cls} {
+    .ant-tabs-tab-active {
+      background-color: @item-active-bg;
+    }
+    //tabs弹窗左边样式
+    .ant-tabs-nav {
+      background-color: @component-background;
+    }
+    //tabs弹窗右边边样式
+    .ant-tabs-content-holder {
+      background: @component-background;
+    }
   }
-}
 </style>

+ 209 - 192
src/views/system/usersetting/commponents/UserPhoneModal.vue

@@ -1,192 +1,204 @@
 <template>
-<BasicModal v-bind="$attrs" @register="registerModal" width="500px"  :title="title" :showCancelBtn="false" :showOkBtn="false">
-  <a-form v-if="type==='updatePhone'" class="antd-modal-form" ref="updateFormRef" :model="updateFormState"
-          :rules="updateValidatorRules">
-    <div v-if="current === 0">
-      <a-form-item name="phoneText">
-        <span class="black font-size-13">原手机号</span>
-        <div class="phone-padding">
-          <span>{{ updateFormState.phoneText }}</span>
-        </div>
-      </a-form-item>
-      <a-form-item name="smscode">
-        <span class="black font-size-13">验证码</span>
-        <CountdownInput class="phone-padding" size="large" v-model:value="updateFormState.smscode" placeholder="输入6位验证码"
-                        :sendCodeApi="()=>updateSendCodeApi('verifyOriginalPhone')"/>
-      </a-form-item>
-      <a-form-item>
-        <a-button size="large" type="primary" block @click="nextStepClick">
-          下一步
-        </a-button>
-      </a-form-item>
-    </div>
-    <div v-else-if="current === 1">
-      <a-form-item name="newPhone">
-        <span class="black font-size-13">新手机号</span>
-        <div class="phone-padding">
-          <a-input v-model:value="updateFormState.newPhone" placeholder="请输入新手机号"/>
-        </div>
+  <BasicModal v-bind="$attrs" @register="registerModal" width="500px" :title="title" :showCancelBtn="false" :showOkBtn="false">
+    <a-form v-if="type === 'updatePhone'" class="antd-modal-form" ref="updateFormRef" :model="updateFormState" :rules="updateValidatorRules">
+      <div v-if="current === 0">
+        <a-form-item name="phoneText">
+          <span class="black font-size-13">原手机号</span>
+          <div class="phone-padding">
+            <span>{{ updateFormState.phoneText }}</span>
+          </div>
+        </a-form-item>
+        <a-form-item name="smscode">
+          <span class="black font-size-13">验证码</span>
+          <CountdownInput
+            class="phone-padding"
+            size="large"
+            v-model:value="updateFormState.smscode"
+            placeholder="输入6位验证码"
+            :sendCodeApi="() => updateSendCodeApi('verifyOriginalPhone')"
+          />
+        </a-form-item>
+        <a-form-item>
+          <a-button size="large" type="primary" block @click="nextStepClick"> 下一步 </a-button>
+        </a-form-item>
+      </div>
+      <div v-else-if="current === 1">
+        <a-form-item name="newPhone">
+          <span class="black font-size-13">新手机号</span>
+          <div class="phone-padding">
+            <a-input v-model:value="updateFormState.newPhone" placeholder="请输入新手机号" />
+          </div>
+        </a-form-item>
+        <a-form-item name="smscode">
+          <span class="black font-size-13">验证码</span>
+          <CountdownInput
+            class="phone-padding"
+            size="large"
+            v-model:value="updateFormState.smscode"
+            placeholder="输入6位验证码"
+            :sendCodeApi="() => updateSendCodeApi('updatePhone')"
+          />
+        </a-form-item>
+        <a-form-item>
+          <a-button size="large" type="primary" block @click="finishedClick"> 完成 </a-button>
+        </a-form-item>
+      </div>
+    </a-form>
+
+    <a-form v-else-if="type === 'bindPhone'" class="antd-modal-form" ref="formRef" :model="formState" :rules="validatorRules">
+      <a-form-item name="phone">
+        <a-input size="large" v-model:value="formState.phone" placeholder="请输入手机号" />
       </a-form-item>
       <a-form-item name="smscode">
-        <span class="black font-size-13">验证码</span>
-        <CountdownInput class="phone-padding" size="large" v-model:value="updateFormState.smscode" placeholder="输入6位验证码"
-                        :sendCodeApi="()=>updateSendCodeApi('updatePhone')"/>
+        <CountdownInput size="large" v-model:value="formState.smscode" placeholder="输入6位验证码" :sendCodeApi="sendCodeApi" />
       </a-form-item>
       <a-form-item>
-        <a-button size="large" type="primary" block @click="finishedClick">
-          完成
-        </a-button>
+        <a-button size="large" type="primary" block @click="updatePhone"> 确认 </a-button>
       </a-form-item>
-    </div>
-  </a-form>
-
-  <a-form v-else-if="type==='bindPhone'" class="antd-modal-form" ref="formRef" :model="formState" :rules="validatorRules">
-    <a-form-item  name="phone">
-      <a-input size="large" v-model:value="formState.phone" placeholder="请输入手机号" />
-    </a-form-item>
-    <a-form-item name="smscode">
-      <CountdownInput size="large" v-model:value="formState.smscode" placeholder="输入6位验证码" :sendCodeApi="sendCodeApi" />
-    </a-form-item>
-    <a-form-item>
-      <a-button size="large" type="primary" block @click="updatePhone">
-        确认
-      </a-button>
-    </a-form-item>
-  </a-form>
-</BasicModal>
+    </a-form>
+  </BasicModal>
 </template>
 
 <script lang="ts" setup name="user-replace-phone-modal">
-import BasicModal from "/@/components/Modal/src/BasicModal.vue";
-import { CountdownInput } from '/@/components/CountDown';
-import { useUserStore } from "/@/store/modules/user";
-import { useMessage } from "/@/hooks/web/useMessage";
-import { defineEmits, ref, reactive, toRaw } from "vue";
-import { useModalInner } from "/@/components/Modal";
-import { getCaptcha } from "/@/api/sys/user";
-import { SmsEnum } from "/@/views/sys/login/useLogin";
-import { Rule } from "/@/components/Form";
-import { rules } from "/@/utils/helper/validator";
-import { Form } from "ant-design-vue";
-import { updateMobile, changePhone } from "../UserSetting.api";
-import { duplicateCheck } from "/@/views/system/user/user.api";
-import {defHttp} from "@/utils/http/axios";
-import { ExceptionEnum } from "@/enums/exceptionEnum";
+  import BasicModal from '/@/components/Modal/src/BasicModal.vue';
+  import { CountdownInput } from '/@/components/CountDown';
+  import { useUserStore } from '/@/store/modules/user';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { defineEmits, ref, reactive, toRaw } from 'vue';
+  import { useModalInner } from '/@/components/Modal';
+  import { getCaptcha } from '/@/api/sys/user';
+  import { SmsEnum } from '/@/views/sys/login/useLogin';
+  import { Rule } from '/@/components/Form';
+  import { rules } from '/@/utils/helper/validator';
+  import { Form } from 'ant-design-vue';
+  import { updateMobile, changePhone } from '../UserSetting.api';
+  import { duplicateCheck } from '/@/views/system/user/user.api';
+  import { defHttp } from '@/utils/http/axios';
+  import { ExceptionEnum } from '@/enums/exceptionEnum';
 
-const userStore = useUserStore();
-const { createMessage } = useMessage();
-const formState = reactive<Record<string, any>>({
-  phone:'',
-  smscode:''
-});
+  const userStore = useUserStore();
+  const { createMessage } = useMessage();
+  const formState = reactive<Record<string, any>>({
+    phone: '',
+    smscode: '',
+  });
 
-//修改手机号
-const updateFormState = reactive<Record<string, any>>({
-  phone:'',
-  smscode:'',
-  newPhone:'',
-  phoneText:'',
-  newSmsCode:''
-});
+  //修改手机号
+  const updateFormState = reactive<Record<string, any>>({
+    phone: '',
+    smscode: '',
+    newPhone: '',
+    phoneText: '',
+    newSmsCode: '',
+  });
 
-const formRef = ref();
-const userData = ref<any>({})
+  const formRef = ref();
+  const userData = ref<any>({});
 
-const validatorRules: Record<string, Rule[]> = {
-  phone: [{...rules.duplicateCheckRule("sys_user",'phone',formState,{ label:'手机号' })[0]},{ pattern: /^1[3456789]\d{9}$/, message: '手机号码格式有误' }],
-  smscode: [{ required: true,message:'请输入验证码' }],
-};
+  const validatorRules: Record<string, Rule[]> = {
+    phone: [
+      { ...rules.duplicateCheckRule('sys_user', 'phone', formState, { label: '手机号' })[0] },
+      { pattern: /^1[3456789]\d{9}$/, message: '手机号码格式有误' },
+    ],
+    smscode: [{ required: true, message: '请输入验证码' }],
+  };
 
-//修改手机号验证规则
-const updateValidatorRules: Record<string, Rule[]> = {
-  newPhone: [{...rules.duplicateCheckRule("sys_user",'phone',formState,{ label:'手机号' })[0]},{ pattern: /^1[3456789]\d{9}$/, message: '手机号码格式有误' }],
-  smscode: [{ required: true,message:'请输入验证码' }],
-  newSmsCode: [{ required: true,message:'请输入验证码' }],
-};
-const useForm = Form.useForm;
-const title = ref<string>('');
-const emit = defineEmits(['register','success']);
-//修改手机号还是绑定手机号
-const type = ref<string>('updatePhone');
-const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
-  setModalProps({ confirmLoading: false });
-  if(data.record.phone){
-    updateFormState.phone = "";
-    updateFormState.smscode = "";
-    current.value = 0;
-    title.value = '修改手机号';
-    type.value = "updatePhone";
-    Object.assign(updateFormState, data.record);
-  }else{
-    title.value = '绑定手机号';
-    type.value = "bindPhone"
-    //赋值
-    data.record.smscode = '';
-    Object.assign(formState, data.record);
-    setTimeout(()=>{
-      formRef.value.resetFields();
-      formRef.value.clearValidate();
-    },300)
-  }
-  userData.value = data.record;
-});
+  //修改手机号验证规则
+  const updateValidatorRules: Record<string, Rule[]> = {
+    newPhone: [
+      { ...rules.duplicateCheckRule('sys_user', 'phone', formState, { label: '手机号' })[0] },
+      { pattern: /^1[3456789]\d{9}$/, message: '手机号码格式有误' },
+    ],
+    smscode: [{ required: true, message: '请输入验证码' }],
+    newSmsCode: [{ required: true, message: '请输入验证码' }],
+  };
+  const useForm = Form.useForm;
+  const title = ref<string>('');
+  const emit = defineEmits(['register', 'success']);
+  //修改手机号还是绑定手机号
+  const type = ref<string>('updatePhone');
+  const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
+    setModalProps({ confirmLoading: false });
+    if (data.record.phone) {
+      updateFormState.phone = '';
+      updateFormState.smscode = '';
+      current.value = 0;
+      title.value = '修改手机号';
+      type.value = 'updatePhone';
+      Object.assign(updateFormState, data.record);
+    } else {
+      title.value = '绑定手机号';
+      type.value = 'bindPhone';
+      //赋值
+      data.record.smscode = '';
+      Object.assign(formState, data.record);
+      setTimeout(() => {
+        formRef.value.resetFields();
+        formRef.value.clearValidate();
+      }, 300);
+    }
+    userData.value = data.record;
+  });
 
-/**
- * 倒计时执行前的函数
- */
-function sendCodeApi() {
-  return getCaptcha({ mobile: formState.phone, smsmode: SmsEnum.REGISTER });
-}
+  /**
+   * 倒计时执行前的函数
+   */
+  function sendCodeApi() {
+    return getCaptcha({ mobile: formState.phone, smsmode: SmsEnum.REGISTER });
+  }
 
-/**
- * 倒计时执行前的函数
- * 
- * @param type 类型 verifyOriginalPhone 验证员手机号 updatePhone 修改手机号
- */
-function updateSendCodeApi(type) {
-  let phone = ""
-  if(current.value === 0){
-    phone = updateFormState.phone;
-  }else{
-    phone = updateFormState.newPhone;
+  /**
+   * 倒计时执行前的函数
+   *
+   * @param type 类型 verifyOriginalPhone 验证员手机号 updatePhone 修改手机号
+   */
+  function updateSendCodeApi(type) {
+    let phone = '';
+    if (current.value === 0) {
+      phone = updateFormState.phone;
+    } else {
+      phone = updateFormState.newPhone;
+    }
+    let params = { phone: phone, type: type };
+    return new Promise((resolve, reject) => {
+      defHttp
+        .post({ url: '/sys/user/sendChangePhoneSms', params }, { isTransformResponse: false })
+        .then((res) => {
+          console.log(res);
+          if (res.success) {
+            resolve(true);
+          } else {
+            //update-begin---author:wangshuai---date:2024-04-18---for:【QQYUN-9005】同一个IP,1分钟超过5次短信,则提示需要验证码---
+            if (res.code != ExceptionEnum.PHONE_SMS_FAIL_CODE) {
+              createMessage.error(res.message || '未知问题');
+              reject();
+            }
+            reject(res);
+            //update-end---author:wangshuai---date:2024-04-18---for:【QQYUN-9005】同一个IP,1分钟超过5次短信,则提示需要验证码---
+          }
+        })
+        .catch((res) => {
+          createMessage.error(res.message || '未知问题');
+          reject();
+        });
+    });
   }
-  let params = { phone: phone,  type: type };
-  return new Promise((resolve, reject) => {
-    defHttp.post({ url: "/sys/user/sendChangePhoneSms", params }, { isTransformResponse: false }).then((res) => {
-      console.log(res);
+
+  /**
+   * 更新手机号
+   */
+  async function updatePhone() {
+    await formRef.value.validateFields();
+    updateMobile(formState).then((res) => {
       if (res.success) {
-        resolve(true);
+        createMessage.success(type.value === 'updatePhone' ? '修改手机号成功' : '绑定手机号成功');
+        emit('success');
+        closeModal();
       } else {
-        //update-begin---author:wangshuai---date:2024-04-18---for:【QQYUN-9005】同一个IP,1分钟超过5次短信,则提示需要验证码---
-        if(res.code != ExceptionEnum.PHONE_SMS_FAIL_CODE){
-          createMessage.error(res.message || '未知问题');
-          reject();
-        }
-        reject(res);
-        //update-end---author:wangshuai---date:2024-04-18---for:【QQYUN-9005】同一个IP,1分钟超过5次短信,则提示需要验证码---
+        createMessage.warning(res.message);
       }
-    }).catch((res)=>{
-      createMessage.error(res.message || '未知问题');
-      reject();
     });
-  });
-}
-
-/**
- * 更新手机号
- */
-async function updatePhone() {
-  await formRef.value.validateFields();
-  updateMobile(formState).then((res) =>{
-    if(res.success){
-      createMessage.success(type.value === "updatePhone"?"修改手机号成功":"绑定手机号成功")
-      emit("success")
-      closeModal();
-    }else{
-      createMessage.warning(res.message)
-    }
-  })
-}
+  }
   //走到第几步
   const current = ref<number>(0);
   const updateFormRef = ref();
@@ -196,14 +208,17 @@ async function updatePhone() {
    */
   async function nextStepClick() {
     let params = { phone: updateFormState.phone, smscode: updateFormState.smscode, type: 'verifyOriginalPhone' };
-    changeAndVerifyPhone(params,1)
+    changeAndVerifyPhone(params, 1);
   }
 
   /**
    * 完成
    */
   function finishedClick() {
-    changeAndVerifyPhone({ phone: updateFormState.phone, newPhone: updateFormState.newPhone, smscode: updateFormState.smscode, type: 'updatePhone' },0);
+    changeAndVerifyPhone(
+      { phone: updateFormState.phone, newPhone: updateFormState.newPhone, smscode: updateFormState.smscode, type: 'updatePhone' },
+      0
+    );
   }
 
   /**
@@ -213,39 +228,41 @@ async function updatePhone() {
    */
   async function changeAndVerifyPhone(params, index) {
     await updateFormRef.value.validateFields();
-    changePhone(params).then((res)=>{
-      if(res.success){
-        current.value = index;
-        if(index == 0){
-          createMessage.success(res.message);
-          emit("success");
-          closeModal();
+    changePhone(params)
+      .then((res) => {
+        if (res.success) {
+          current.value = index;
+          if (index == 0) {
+            createMessage.success(res.message);
+            emit('success');
+            closeModal();
+          }
+          updateFormState.smscode = '';
+        } else {
+          createMessage.warn(res.message);
         }
-        updateFormState.smscode = "";
-      }else{
+      })
+      .catch((res) => {
         createMessage.warn(res.message);
-      }
-    }).catch((res) =>{
-      createMessage.warn(res.message);
-    })
+      });
   }
 </script>
 <style lang="less" scoped>
   .antd-modal-form {
     padding: 10px 24px 10px 24px;
   }
- .black {
-   color: #000000;
- }
- .font-size-13 {
-   font-size: 13px;
-   line-height: 15px;
- }
+  .black {
+    color: #000000;
+  }
+  .font-size-13 {
+    font-size: 13px;
+    line-height: 15px;
+  }
   .phone-padding {
     padding-top: 10px;
     padding-bottom: 10px;
   }
-  :deep(.ant-form-item){
+  :deep(.ant-form-item) {
     margin-bottom: 10px;
   }
-</style>
+</style>

+ 5 - 5
vite.config.ts

@@ -31,10 +31,10 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
 
   const isBuild = command === 'build';
 
-  const serverOptions: Recordable = {}
+  const serverOptions: Recordable = {};
 
   // ----- [begin] 【JEECG作为乾坤子应用】 -----
-  const {VITE_GLOB_QIANKUN_MICRO_APP_NAME, VITE_GLOB_QIANKUN_MICRO_APP_ENTRY} = viteEnv;
+  const { VITE_GLOB_QIANKUN_MICRO_APP_NAME, VITE_GLOB_QIANKUN_MICRO_APP_ENTRY } = viteEnv;
   const isQiankunMicro = VITE_GLOB_QIANKUN_MICRO_APP_NAME != null && VITE_GLOB_QIANKUN_MICRO_APP_NAME !== '';
   if (isQiankunMicro && !isBuild) {
     serverOptions.cors = true;
@@ -98,10 +98,10 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
           manualChunks: {
             // vue vue-router合并打包
             'vue-vendor': ['vue', 'vue-router'],
-            'antd-vue-vendor': ['ant-design-vue','@ant-design/icons-vue','@ant-design/colors'],
-            'vxe-table-vendor': ['vxe-table','vxe-table-plugin-antd','xe-utils'],
+            'antd-vue-vendor': ['ant-design-vue', '@ant-design/icons-vue', '@ant-design/colors'],
+            'vxe-table-vendor': ['vxe-table', 'vxe-table-plugin-antd', 'xe-utils'],
             'emoji-mart-vue-fast': ['emoji-mart-vue-fast'],
-            'china-area-data-vendor': ['china-area-data']
+            'china-area-data-vendor': ['china-area-data'],
           },
         },
       },

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