干燥机配套车间生产管理系统/云平台服务端
baoshiwei
2023-05-24 beca65f4d01ca07c358102a35b949c2a4f277afe
增加车间监控界面
已添加18个文件
已修改44个文件
33662 ■■■■■ 文件已修改
.eslintrc.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LICENSE 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
commitlint.config.js 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
npm 补丁 | 查看 | 原始文档 | blame | 历史
package.json 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pnpm-lock.yaml 16838 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
prettier.config.js 补丁 | 查看 | 原始文档 | blame | 历史
src/App.vue 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/sys/menu.ts 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/sys/model/menuModel.ts 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/dry/ganzaoji-x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/dry/ganzaoji-z.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/dry/ganzaoji.gif 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/dry/ganzaoji.png 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Button/src/BasicButton.vue 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/enums/pageEnum.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/default/header/components/user-dropdown/index.vue 126 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/lang/en/layout.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/lang/zh-CN/layout.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.ts 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/constant.ts 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.ts 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/menus/index.ts 132 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/routes/basic.ts 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/routes/index.ts 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/routes/mainOut.ts 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/routes/modules/dashboard.ts 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/types.ts 61 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/permission.ts 261 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/aes.js 505 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/http/axios/index.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/libgif/libgif.js 990 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/public.js 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/demo/form/index.vue 100 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/demo/page/list/basic/index.vue 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/DryEquipmentList.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/DryHerbFormulaList.vue 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/DryHerbList.vue 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/DryHerbTypeList.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/DryOrderList.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/DryOrderTrendList.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/api/DryEquipment.api.ts 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/api/DryHerbFormula.api.ts 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/components/DryEquipmentForm.vue 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/components/DryEquipmentModal.vue 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/components/DryHerbForm.vue 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/components/DryHerbFormulaForm.vue 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/components/DryHerbFormulaModal.vue 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/components/DryHerbModal.vue 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/components/DryOrderForm.vue 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/components/DryOrderModal.vue 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/dataDefine/DryEquipment.data.ts 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/dataDefine/DryHerbFormula.data.ts 226 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/dataDefine/DryOrder.data.ts 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/monitor/WorkShop.vue 513 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dry/sql/DryHerbFormula_menu_insert.sql 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/departUser/components/DepartRoleAuthDrawer.vue 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/loginmini/MiniLogin.vue 212 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
stylelint.config.js 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.ts 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
windi.config.ts 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yarn.lock 12304 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.eslintrc.js
@@ -1,5 +1,5 @@
// @ts-check
const { defineConfig } = require('eslint-define-config');
const { defineConfig } = require('eslint-define-config')
module.exports = defineConfig({
  root: true,
  env: {
@@ -75,4 +75,4 @@
      },
    ],
  },
});
})
LICENSE
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
MIT License
Copyright (c) 2020-present, Jeecg
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
<developers>
  <developer>
    <name>北京敲敲云科技有限公司</name>
    <email>jeecgos@163.com</email>
  </developer>
</developers>
<scm>
  <connection>http://www.jeecg.com</connection>
  <developerConnection>https://qiaoqiaoyun.com</developerConnection>
  <url>http://www.jeecg.com/vip</url>
</scm>
commitlint.config.js
@@ -10,23 +10,7 @@
    'type-enum': [
      2,
      'always',
      [
        'feat',
        'fix',
        'perf',
        'style',
        'docs',
        'test',
        'refactor',
        'build',
        'ci',
        'chore',
        'revert',
        'wip',
        'workflow',
        'types',
        'release',
      ],
            ['feat', 'fix', 'perf', 'style', 'docs', 'test', 'refactor', 'build', 'ci', 'chore', 'revert', 'wip', 'workflow', 'types', 'release'],
    ],
  },
};
}
npm
package.json
@@ -34,16 +34,16 @@
    "gen:icon": "esno ./build/generate/icon/index.ts"
  },
  "dependencies": {
    "@jeecg/online": "3.4.4-RC",
    "@iconify/iconify": "^2.2.1",
    "@ant-design/colors": "^6.0.0",
    "@ant-design/icons-vue": "^6.1.0",
    "@iconify/iconify": "^2.2.1",
    "@jeecg/online": "3.4.4-RC",
    "@logicflow/core": "^1.1.13",
    "@logicflow/extension": "^1.1.13",
    "@vue/shared": "^3.2.33",
    "@vue/runtime-core": "^3.2.33",
    "@vueuse/shared": "^8.3.0",
    "@vue/shared": "^3.2.33",
    "@vueuse/core": "^8.3.0",
    "@vueuse/shared": "^8.3.0",
    "@zxcvbn-ts/core": "^2.0.1",
    "ant-design-vue": "^3.2.12",
    "axios": "^0.26.1",
@@ -56,6 +56,7 @@
    "dayjs": "^1.11.1",
    "dom-align": "^1.12.2",
    "echarts": "^5.3.2",
    "echarts-liquidfill": "^3.1.0",
    "emoji-mart-vue-fast": "^11.1.1",
    "enquire.js": "^2.1.6",
    "intro.js": "^5.1.0",
@@ -66,11 +67,11 @@
    "nprogress": "^0.2.0",
    "path-to-regexp": "^6.2.0",
    "pinia": "2.0.12",
    "print-js": "^1.6.0",
    "pinyin-pro": "^3.11.0",
    "qs": "^6.10.3",
    "print-js": "^1.6.0",
    "qrcode": "^1.5.0",
    "qrcodejs2": "0.0.2",
    "qs": "^6.10.3",
    "resize-observer-polyfill": "^1.5.1",
    "showdown": "^2.1.0",
    "sortablejs": "^1.15.0",
@@ -81,6 +82,7 @@
    "vue-cropperjs": "^5.0.0",
    "vue-i18n": "^9.1.9",
    "vue-infinite-scroll": "^2.0.2",
    "vue-json-pretty": "^2.0.6",
    "vue-print-nb-jeecg": "^1.0.10",
    "vue-router": "^4.0.14",
    "vue-types": "^4.1.1",
@@ -88,7 +90,6 @@
    "vxe-table": "4.1.0",
    "vxe-table-plugin-antd": "3.0.5",
    "xe-utils": "^3.3.1",
    "vue-json-pretty": "^2.0.6",
    "xss": "^1.0.13"
  },
  "devDependencies": {
pnpm-lock.yaml
¶Ô±ÈÐÂÎļþ
ÎļþÌ«´ó
prettier.config.js
src/App.vue
@@ -7,15 +7,15 @@
</template>
<script lang="ts" setup>
  import { ConfigProvider } from 'ant-design-vue';
  import { AppProvider } from '/@/components/Application';
  import { useTitle } from '/@/hooks/web/useTitle';
  import { useLocale } from '/@/locales/useLocale';
    import { ConfigProvider } from 'ant-design-vue'
    import { AppProvider } from '/@/components/Application'
    import { useTitle } from '/@/hooks/web/useTitle'
    import { useLocale } from '/@/locales/useLocale'
  // è§£å†³æ—¥æœŸæ—¶é—´å›½é™…化问题
  import 'dayjs/locale/zh-cn';
    import 'dayjs/locale/zh-cn'
  // support Multi-language
  const { getAntdLocale } = useLocale();
    const { getAntdLocale } = useLocale()
  useTitle();
    useTitle()
</script>
src/api/sys/menu.ts
@@ -1,5 +1,5 @@
import { defHttp } from '/@/utils/http/axios';
import { getMenuListResultModel } from './model/menuModel';
import { getMenuListResultModel } from './model/menuModel'
import { defHttp } from '/@/utils/http/axios'
enum Api {
  GetMenuList = '/sys/permission/getUserPermissionByToken',
@@ -15,19 +15,19 @@
    //为了兼容mock和接口数据
    defHttp.get<getMenuListResultModel>({ url: Api.GetMenuList }).then((res) => {
      if (Array.isArray(res)) {
        resolve(res);
                resolve(res)
      } else {
        resolve(res['menu']);
                resolve(res['menu'])
      }
    });
  });
};
        })
    })
}
/**
 * åˆ‡æ¢æˆvue3菜单
 */
export const switchVue3Menu = () => {
  return new Promise((resolve) => {
    defHttp.get({ url: Api.SwitchVue3Menu });
  });
};
        defHttp.get({ url: Api.SwitchVue3Menu })
    })
}
src/api/sys/model/menuModel.ts
@@ -1,16 +1,16 @@
import type { RouteMeta } from 'vue-router';
import type { RouteMeta } from 'vue-router'
export interface RouteItem {
  path: string;
  component: any;
  meta: RouteMeta;
  name?: string;
  alias?: string | string[];
  redirect?: string;
  caseSensitive?: boolean;
  children?: RouteItem[];
    path: string
    component: any
    meta: RouteMeta
    name?: string
    alias?: string | string[]
    redirect?: string
    caseSensitive?: boolean
    children?: RouteItem[]
}
/**
 * @description: Get menu return value
 */
export type getMenuListResultModel = RouteItem[];
export type getMenuListResultModel = RouteItem[]
src/assets/images/dry/ganzaoji-x.png
src/assets/images/dry/ganzaoji-z.png
src/assets/images/dry/ganzaoji.gif
src/assets/images/dry/ganzaoji.png
src/components/Button/src/BasicButton.vue
@@ -11,31 +11,31 @@
</template>
<script lang="ts">
  import { defineComponent } from 'vue';
    import { defineComponent } from 'vue'
  export default defineComponent({
    name: 'AButton',
    inheritAttrs: false,
  });
    })
</script>
<script lang="ts" setup>
  import { computed, unref } from 'vue';
  import { Button } from 'ant-design-vue';
  import Icon from '/@/components/Icon/src/Icon.vue';
  import { buttonProps } from './props';
  import { useAttrs } from '/@/hooks/core/useAttrs';
  const props = defineProps(buttonProps);
    import { computed, unref } from 'vue'
    import { Button } from 'ant-design-vue'
    import Icon from '/@/components/Icon/src/Icon.vue'
    import { buttonProps } from './props'
    import { useAttrs } from '/@/hooks/core/useAttrs'
    const props = defineProps(buttonProps)
  // get component class
  const attrs = useAttrs({ excludeDefaultKeys: false });
    const attrs = useAttrs({ excludeDefaultKeys: false })
  const getButtonClass = computed(() => {
    const { color, disabled } = props;
        const { color, disabled } = props
    return [
      {
        [`ant-btn-${color}`]: !!color,
        [`is-disabled`]: disabled,
      },
    ];
  });
        ]
    })
  // get inherit binding value
  const getBindValue = computed(() => ({ ...unref(attrs), ...props }));
    const getBindValue = computed(() => ({ ...unref(attrs), ...props }))
</script>
src/enums/pageEnum.ts
@@ -2,7 +2,7 @@
  // basic login path
  BASE_LOGIN = '/login',
  // basic home path
  BASE_HOME = '/dashboard/analysis',
    BASE_HOME = '/dashboard/workshop',
  // error page path
  ERROR_PAGE = '/exception',
  // error log page path
src/layouts/default/header/components/user-dropdown/index.vue
@@ -11,7 +11,7 @@
    <template #overlay>
      <Menu @click="handleMenuClick">
        <MenuItem key="doc" :text="t('layout.header.dropdownItemDoc')" icon="ion:document-text-outline" v-if="getShowDoc" />
                <!-- <MenuItem key="doc" :text="t('layout.header.dropdownItemDoc')" icon="ion:document-text-outline" v-if="getShowDoc" /> -->
        <MenuDivider v-if="getShowDoc" />
        <MenuItem key="account" :text="t('layout.header.dropdownItemSwitchAccount')" icon="ant-design:setting-outlined" />
        <MenuItem key="password" :text="t('layout.header.dropdownItemSwitchPassword')" icon="ant-design:edit-outlined" />
@@ -33,32 +33,32 @@
</template>
<script lang="ts">
  // components
  import { Dropdown, Menu } from 'ant-design-vue';
    import { Dropdown, Menu } from 'ant-design-vue'
  import { defineComponent, computed, ref } from 'vue';
    import { defineComponent, computed, ref } from 'vue'
  import { SITE_URL } from '/@/settings/siteSetting';
    import { SITE_URL } from '/@/settings/siteSetting'
  import { useUserStore } from '/@/store/modules/user';
  import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
  import { useI18n } from '/@/hooks/web/useI18n';
  import { useDesign } from '/@/hooks/web/useDesign';
  import { useModal } from '/@/components/Modal';
  import { useMessage } from '/src/hooks/web/useMessage';
  import { useGo } from '/@/hooks/web/usePage';
  import headerImg from '/@/assets/images/header.jpg';
  import { propTypes } from '/@/utils/propTypes';
  import { openWindow } from '/@/utils';
    import { useUserStore } from '/@/store/modules/user'
    import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'
    import { useI18n } from '/@/hooks/web/useI18n'
    import { useDesign } from '/@/hooks/web/useDesign'
    import { useModal } from '/@/components/Modal'
    import { useMessage } from '/src/hooks/web/useMessage'
    import { useGo } from '/@/hooks/web/usePage'
    import headerImg from '/@/assets/images/header.jpg'
    import { propTypes } from '/@/utils/propTypes'
    import { openWindow } from '/@/utils'
  import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
    import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'
  import { refreshCache, queryAllDictItems } from '/@/views/system/dict/dict.api';
  import { DB_DICT_DATA_KEY } from '/src/enums/cacheEnum';
  import { removeAuthCache, setAuthCache } from '/src/utils/auth';
  import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
    import { refreshCache, queryAllDictItems } from '/@/views/system/dict/dict.api'
    import { DB_DICT_DATA_KEY } from '/src/enums/cacheEnum'
    import { removeAuthCache, setAuthCache } from '/src/utils/auth'
    import { getFileAccessHttpUrl } from '/@/utils/common/compUtils'
  type MenuEvent = 'logout' | 'doc' | 'lock' | 'cache' | 'depart';
  const { createMessage } = useMessage();
    type MenuEvent = 'logout' | 'doc' | 'lock' | 'cache' | 'depart'
    const { createMessage } = useMessage()
  export default defineComponent({
    name: 'UserDropdown',
    components: {
@@ -74,92 +74,92 @@
      theme: propTypes.oneOf(['dark', 'light']),
    },
    setup() {
      const { prefixCls } = useDesign('header-user-dropdown');
      const { t } = useI18n();
      const { getShowDoc, getUseLockPage } = useHeaderSetting();
      const userStore = useUserStore();
      const go = useGo();
            const { prefixCls } = useDesign('header-user-dropdown')
            const { t } = useI18n()
            const { getShowDoc, getUseLockPage } = useHeaderSetting()
            const userStore = useUserStore()
            const go = useGo()
      const getUserInfo = computed(() => {
        const { realname = '', avatar, desc } = userStore.getUserInfo || {};
        return { realname, avatar: avatar || headerImg, desc };
      });
                const { realname = '', avatar, desc } = userStore.getUserInfo || {}
                return { realname, avatar: avatar || headerImg, desc }
            })
      const getAvatarUrl = computed(() => {
        let { avatar } = getUserInfo.value;
                let { avatar } = getUserInfo.value
        if (avatar == headerImg) {
          return avatar;
                    return avatar
        } else {
          return getFileAccessHttpUrl(avatar);
                    return getFileAccessHttpUrl(avatar)
        }
      });
            })
      const [register, { openModal }] = useModal();
            const [register, { openModal }] = useModal()
      /**
       * å¤šéƒ¨é—¨å¼¹çª—逻辑
       */
      const loginSelectRef = ref();
            const loginSelectRef = ref()
      function handleLock() {
        openModal(true);
                openModal(true)
      }
      //  login out
      function handleLoginOut() {
        userStore.confirmLoginOut();
                userStore.confirmLoginOut()
      }
      // open doc
      function openDoc() {
        openWindow(SITE_URL);
                openWindow(SITE_URL)
      }
      // æ¸…除缓存
      async function clearCache() {
        const result = await refreshCache();
                const result = await refreshCache()
        if (result.success) {
          const res = await queryAllDictItems();
          removeAuthCache(DB_DICT_DATA_KEY);
          setAuthCache(DB_DICT_DATA_KEY, res.result);
          createMessage.success('刷新缓存完成!');
                    const res = await queryAllDictItems()
                    removeAuthCache(DB_DICT_DATA_KEY)
                    setAuthCache(DB_DICT_DATA_KEY, res.result)
                    createMessage.success('刷新缓存完成!')
        } else {
          createMessage.error('刷新缓存失败!');
                    createMessage.error('刷新缓存失败!')
        }
      }
      // åˆ‡æ¢éƒ¨é—¨
      function updateCurrentDepart() {
        loginSelectRef.value.show();
                loginSelectRef.value.show()
      }
      // ä¿®æ”¹å¯†ç 
      const updatePasswordRef = ref();
            const updatePasswordRef = ref()
      function updatePassword() {
        updatePasswordRef.value.show(userStore.getUserInfo.username);
                updatePasswordRef.value.show(userStore.getUserInfo.username)
      }
      function handleMenuClick(e: { key: MenuEvent }) {
        switch (e.key) {
          case 'logout':
            handleLoginOut();
            break;
                        handleLoginOut()
                        break
          case 'doc':
            openDoc();
            break;
                        openDoc()
                        break
          case 'lock':
            handleLock();
            break;
                        handleLock()
                        break
          case 'cache':
            clearCache();
            break;
                        clearCache()
                        break
          case 'depart':
            updateCurrentDepart();
            break;
                        updateCurrentDepart()
                        break
          case 'password':
            updatePassword();
            break;
                        updatePassword()
                        break
          case 'account':
            //update-begin---author:wangshuai ---date:20221125  for:进入用户设置页面------------
            go(`/system/usersetting`);
                        go(`/system/usersetting`)
            //update-end---author:wangshuai ---date:20221125  for:进入用户设置页面--------------
            break;
                        break
        }
      }
@@ -174,9 +174,9 @@
        getUseLockPage,
        loginSelectRef,
        updatePasswordRef,
      };
            }
    },
  });
    })
</script>
<style lang="less">
  @prefix-cls: ~'@{namespace}-header-user-dropdown';
src/locales/lang/en/layout.ts
@@ -119,4 +119,4 @@
    mixSidebarFixed: 'Fixed expanded menu',
  },
};
}
src/locales/lang/zh-CN/layout.ts
@@ -120,4 +120,4 @@
    mixSidebarFixed: '固定展开菜单',
  },
};
}
src/main.ts
@@ -1,72 +1,72 @@
import '/@/design/index.less';
import '/@/design/index.less'
// æ³¨å†Œ windi
import 'virtual:windi-base.css';
import 'virtual:windi-components.css';
import 'virtual:windi-utilities.css';
import 'virtual:windi-devtools';
import 'virtual:windi-base.css'
import 'virtual:windi-components.css'
import 'virtual:windi-devtools'
import 'virtual:windi-utilities.css'
// æ³¨å†Œå›¾æ ‡
import 'virtual:svg-icons-register';
import App from './App.vue';
import { createApp } from 'vue';
import { initAppConfigStore } from '/@/logics/initAppConfig';
import { setupErrorHandle } from '/@/logics/error-handle';
import { router, setupRouter } from '/@/router';
import { setupRouterGuard } from '/@/router/guard';
import { setupStore } from '/@/store';
import { setupGlobDirectives } from '/@/directives';
import { setupI18n } from '/@/locales/setupI18n';
import { registerGlobComp } from '/@/components/registerGlobComp';
import { registerThirdComp } from '/@/settings/registerThirdComp';
import { useSso } from '/@/hooks/web/useSso';
import 'virtual:svg-icons-register'
import { createApp } from 'vue'
import App from './App.vue'
import { registerGlobComp } from '/@/components/registerGlobComp'
import { setupGlobDirectives } from '/@/directives'
import { useSso } from '/@/hooks/web/useSso'
import { setupI18n } from '/@/locales/setupI18n'
import { setupErrorHandle } from '/@/logics/error-handle'
import { initAppConfigStore } from '/@/logics/initAppConfig'
import { router, setupRouter } from '/@/router'
import { setupRouterGuard } from '/@/router/guard'
import { registerThirdComp } from '/@/settings/registerThirdComp'
import { setupStore } from '/@/store'
// æ³¨å†Œonline模块lib
import { registerPackages } from '/@/utils/monorepo/registerPackages';
import { registerPackages } from '/@/utils/monorepo/registerPackages'
// åœ¨æœ¬åœ°å¼€å‘中引入的,以提高浏览器响应速度
if (import.meta.env.DEV) {
  import('ant-design-vue/dist/antd.less');
    import('ant-design-vue/dist/antd.less')
}
async function bootstrap() {
  // åˆ›å»ºåº”用实例
  const app = createApp(App);
    const app = createApp(App)
  // å¤šè¯­è¨€é…ç½®,异步情况:语言文件可以从服务器端获得
  await setupI18n(app);
    await setupI18n(app)
  // é…ç½®å­˜å‚¨
  setupStore(app);
    setupStore(app)
  // åˆå§‹åŒ–内部系统配置
  initAppConfigStore();
    initAppConfigStore()
  // æ³¨å†Œå¤–部模块路由(注册online模块lib)
  registerPackages(app);
    registerPackages(app)
  // æ³¨å†Œå…¨å±€ç»„ä»¶
  registerGlobComp(app);
    registerGlobComp(app)
  //CAS单点登录
  await useSso().ssoLogin();
    await useSso().ssoLogin()
  // é…ç½®è·¯ç”±
  setupRouter(app);
    setupRouter(app)
  // è·¯ç”±ä¿æŠ¤
  setupRouterGuard(router);
    setupRouterGuard(router)
  // æ³¨å†Œå…¨å±€æŒ‡ä»¤
  setupGlobDirectives(app);
    setupGlobDirectives(app)
  // é…ç½®å…¨å±€é”™è¯¯å¤„理
  setupErrorHandle(app);
    setupErrorHandle(app)
  // æ³¨å†Œç¬¬ä¸‰æ–¹ç»„ä»¶
  await registerThirdComp(app);
    await registerThirdComp(app)
  // å½“路由准备好时再执行挂载( https://next.router.vuejs.org/api/#isready)
  await router.isReady();
    await router.isReady()
  // æŒ‚载应用
  app.mount('#app', true);
    app.mount('#app', true)
}
bootstrap();
bootstrap()
src/router/constant.ts
@@ -1,15 +1,15 @@
export const REDIRECT_NAME = 'Redirect';
export const REDIRECT_NAME = 'Redirect'
export const PARENT_LAYOUT_NAME = 'ParentLayout';
export const PARENT_LAYOUT_NAME = 'ParentLayout'
export const PAGE_NOT_FOUND_NAME = 'PageNotFound';
export const PAGE_NOT_FOUND_NAME = 'PageNotFound'
export const EXCEPTION_COMPONENT = () => import('/@/views/sys/exception/Exception.vue');
export const EXCEPTION_COMPONENT = () => import('/@/views/sys/exception/Exception.vue')
/**
 * @description: default layout
 */
export const LAYOUT = () => import('/@/layouts/default/index.vue');
export const LAYOUT = () => import('/@/layouts/default/index.vue')
/**
 * @description: parent-layout
@@ -19,6 +19,6 @@
    new Promise((resolve) => {
      resolve({
        name: PARENT_LAYOUT_NAME,
      });
    });
};
            })
        })
}
src/router/index.ts
@@ -1,17 +1,17 @@
import type { RouteRecordRaw } from 'vue-router';
import type { App } from 'vue';
import type { App } from 'vue'
import type { RouteRecordRaw } from 'vue-router'
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router';
import { basicRoutes } from './routes';
import { createRouter, createWebHistory } from 'vue-router'
import { basicRoutes } from './routes'
// ç™½åå•应该包含基本静态路由
const WHITE_NAME_LIST: string[] = [];
const WHITE_NAME_LIST: string[] = []
const getRouteNames = (array: any[]) =>
  array.forEach((item) => {
    WHITE_NAME_LIST.push(item.name);
    getRouteNames(item.children || []);
  });
getRouteNames(basicRoutes);
        WHITE_NAME_LIST.push(item.name)
        getRouteNames(item.children || [])
    })
getRouteNames(basicRoutes)
// app router
export const router = createRouter({
@@ -19,19 +19,19 @@
  routes: basicRoutes as unknown as RouteRecordRaw[],
  strict: true,
  scrollBehavior: () => ({ left: 0, top: 0 }),
});
})
// reset router
export function resetRouter() {
  router.getRoutes().forEach((route) => {
    const { name } = route;
        const { name } = route
    if (name && !WHITE_NAME_LIST.includes(name as string)) {
      router.hasRoute(name) && router.removeRoute(name);
            router.hasRoute(name) && router.removeRoute(name)
    }
  });
    })
}
// config router
export function setupRouter(app: App<Element>) {
  app.use(router);
    app.use(router)
}
src/router/menus/index.ts
@@ -1,126 +1,126 @@
import type { Menu, MenuModule } from '/@/router/types';
import type { RouteRecordNormalized } from 'vue-router';
import type { RouteRecordNormalized } from 'vue-router'
import type { Menu, MenuModule } from '/@/router/types'
import { useAppStoreWithOut } from '/@/store/modules/app';
import { usePermissionStore } from '/@/store/modules/permission';
import { transformMenuModule, getAllParentPath } from '/@/router/helper/menuHelper';
import { filter } from '/@/utils/helper/treeHelper';
import { isUrl } from '/@/utils/is';
import { router } from '/@/router';
import { PermissionModeEnum } from '/@/enums/appEnum';
import { pathToRegexp } from 'path-to-regexp';
import { pathToRegexp } from 'path-to-regexp'
import { PermissionModeEnum } from '/@/enums/appEnum'
import { router } from '/@/router'
import { getAllParentPath, transformMenuModule } from '/@/router/helper/menuHelper'
import { useAppStoreWithOut } from '/@/store/modules/app'
import { usePermissionStore } from '/@/store/modules/permission'
import { filter } from '/@/utils/helper/treeHelper'
import { isUrl } from '/@/utils/is'
const modules = import.meta.glob('./modules/**/*.ts', { eager: true });
const modules = import.meta.glob('./modules/**/*.ts', { eager: true })
const menuModules: MenuModule[] = [];
const menuModules: MenuModule[] = []
Object.keys(modules).forEach((key) => {
  const mod = (modules as Recordable)[key].default || {};
  const modList = Array.isArray(mod) ? [...mod] : [mod];
  menuModules.push(...modList);
});
    const mod = (modules as Recordable)[key].default || {}
    const modList = Array.isArray(mod) ? [...mod] : [mod]
    menuModules.push(...modList)
})
// ===========================
// ==========Helper===========
// ===========================
const getPermissionMode = () => {
  const appStore = useAppStoreWithOut();
  return appStore.getProjectConfig.permissionMode;
};
    const appStore = useAppStoreWithOut()
    return appStore.getProjectConfig.permissionMode
}
const isBackMode = () => {
  return getPermissionMode() === PermissionModeEnum.BACK;
};
    return getPermissionMode() === PermissionModeEnum.BACK
}
const isRouteMappingMode = () => {
  return getPermissionMode() === PermissionModeEnum.ROUTE_MAPPING;
};
    return getPermissionMode() === PermissionModeEnum.ROUTE_MAPPING
}
const isRoleMode = () => {
  return getPermissionMode() === PermissionModeEnum.ROLE;
};
    return getPermissionMode() === PermissionModeEnum.ROLE
}
const staticMenus: Menu[] = [];
(() => {
const staticMenus: Menu[] = []
;(() => {
  menuModules.sort((a, b) => {
    return (a.orderNo || 0) - (b.orderNo || 0);
  });
        return (a.orderNo || 0) - (b.orderNo || 0)
    })
  for (const menu of menuModules) {
    staticMenus.push(transformMenuModule(menu));
        staticMenus.push(transformMenuModule(menu))
  }
})();
})()
async function getAsyncMenus() {
  const permissionStore = usePermissionStore();
    const permissionStore = usePermissionStore()
  if (isBackMode()) {
    return permissionStore.getBackMenuList.filter((item) => !item.meta?.hideMenu && !item.hideMenu);
        return permissionStore.getBackMenuList.filter((item) => !item.meta?.hideMenu && !item.hideMenu)
  }
  if (isRouteMappingMode()) {
    return permissionStore.getFrontMenuList.filter((item) => !item.hideMenu);
        return permissionStore.getFrontMenuList.filter((item) => !item.hideMenu)
  }
  return staticMenus;
    return staticMenus
}
export const getMenus = async (): Promise<Menu[]> => {
  const menus = await getAsyncMenus();
    const menus = await getAsyncMenus()
  if (isRoleMode()) {
    const routes = router.getRoutes();
    return filter(menus, basicFilter(routes));
        const routes = router.getRoutes()
        return filter(menus, basicFilter(routes))
  }
  return menus;
};
    return menus
}
export async function getCurrentParentPath(currentPath: string) {
  const menus = await getAsyncMenus();
  const allParentPath = await getAllParentPath(menus, currentPath);
  return allParentPath?.[0];
    const menus = await getAsyncMenus()
    const allParentPath = await getAllParentPath(menus, currentPath)
    return allParentPath?.[0]
}
// Get the level 1 menu, delete children
export async function getShallowMenus(): Promise<Menu[]> {
  const menus = await getAsyncMenus();
  const shallowMenuList = menus.map((item) => ({ ...item, children: undefined }));
    const menus = await getAsyncMenus()
    const shallowMenuList = menus.map((item) => ({ ...item, children: undefined }))
  if (isRoleMode()) {
    const routes = router.getRoutes();
    return shallowMenuList.filter(basicFilter(routes));
        const routes = router.getRoutes()
        return shallowMenuList.filter(basicFilter(routes))
  }
  return shallowMenuList;
    return shallowMenuList
}
// Get the children of the menu
export async function getChildrenMenus(parentPath: string) {
  const menus = await getMenus();
  const parent = menus.find((item) => item.path === parentPath);
    const menus = await getMenus()
    const parent = menus.find((item) => item.path === parentPath)
  if (!parent || !parent.children || !!parent?.meta?.hideChildrenInMenu) {
    return [] as Menu[];
        return [] as Menu[]
  }
  if (isRoleMode()) {
    const routes = router.getRoutes();
    return filter(parent.children, basicFilter(routes));
        const routes = router.getRoutes()
        return filter(parent.children, basicFilter(routes))
  }
  return parent.children;
    return parent.children
}
function basicFilter(routes: RouteRecordNormalized[]) {
  return (menu: Menu) => {
    const matchRoute = routes.find((route) => {
      if (isUrl(menu.path)) return true;
            if (isUrl(menu.path)) return true
      if (route.meta?.carryParam) {
        return pathToRegexp(route.path).test(menu.path);
                return pathToRegexp(route.path).test(menu.path)
      }
      const isSame = route.path === menu.path;
      if (!isSame) return false;
            const isSame = route.path === menu.path
            if (!isSame) return false
      if (route.meta?.ignoreAuth) return true;
            if (route.meta?.ignoreAuth) return true
      return isSame || pathToRegexp(route.path).test(menu.path);
    });
            return isSame || pathToRegexp(route.path).test(menu.path)
        })
    if (!matchRoute) return false;
    menu.icon = (menu.icon || matchRoute.meta.icon) as string;
    menu.meta = matchRoute.meta;
    return true;
  };
        if (!matchRoute) return false
        menu.icon = (menu.icon || matchRoute.meta.icon) as string
        menu.meta = matchRoute.meta
        return true
    }
}
src/router/routes/basic.ts
@@ -1,6 +1,6 @@
import type { AppRouteRecordRaw } from '/@/router/types';
import { t } from '/@/hooks/web/useI18n';
import { REDIRECT_NAME, LAYOUT, EXCEPTION_COMPONENT, PAGE_NOT_FOUND_NAME } from '/@/router/constant';
import { t } from '/@/hooks/web/useI18n'
import { EXCEPTION_COMPONENT, LAYOUT, PAGE_NOT_FOUND_NAME, REDIRECT_NAME } from '/@/router/constant'
import type { AppRouteRecordRaw } from '/@/router/types'
// 404 on a page
export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {
@@ -24,7 +24,7 @@
      },
    },
  ],
};
}
export const REDIRECT_ROUTE: AppRouteRecordRaw = {
  path: '/redirect',
@@ -46,7 +46,7 @@
      },
    },
  ],
};
}
export const ERROR_LOG_ROUTE: AppRouteRecordRaw = {
  path: '/error-log',
@@ -70,4 +70,4 @@
      },
    },
  ],
};
}
src/router/routes/index.ts
@@ -1,23 +1,23 @@
import type { AppRouteRecordRaw, AppRouteModule } from '/@/router/types';
import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types'
import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/routes/basic';
import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/routes/basic'
import { mainOutRoutes } from './mainOut';
import { PageEnum } from '/@/enums/pageEnum';
import { t } from '/@/hooks/web/useI18n';
import { mainOutRoutes } from './mainOut'
import { PageEnum } from '/@/enums/pageEnum'
import { t } from '/@/hooks/web/useI18n'
const modules = import.meta.glob('./modules/**/*.ts', { eager: true });
const modules = import.meta.glob('./modules/**/*.ts', { eager: true })
const routeModuleList: AppRouteModule[] = [];
const routeModuleList: AppRouteModule[] = []
// åŠ å…¥åˆ°è·¯ç”±é›†åˆä¸­
Object.keys(modules).forEach((key) => {
  const mod = (modules as Recordable)[key].default || {};
  const modList = Array.isArray(mod) ? [...mod] : [mod];
  routeModuleList.push(...modList);
});
    const mod = (modules as Recordable)[key].default || {}
    const modList = Array.isArray(mod) ? [...mod] : [mod]
    routeModuleList.push(...modList)
})
export const asyncRoutes = [PAGE_NOT_FOUND_ROUTE, ...routeModuleList];
export const asyncRoutes = [PAGE_NOT_FOUND_ROUTE, ...routeModuleList]
export const RootRoute: AppRouteRecordRaw = {
  path: '/',
@@ -26,7 +26,7 @@
  meta: {
    title: 'Root',
  },
};
}
export const LoginRoute: AppRouteRecordRaw = {
  path: '/login',
@@ -37,7 +37,7 @@
  meta: {
    title: t('routes.basic.login'),
  },
};
}
//update-begin---author:wangshuai ---date:20220629  for:auth2登录页面路由------------
export const Oauth2LoginRoute: AppRouteRecordRaw = {
@@ -49,7 +49,7 @@
  meta: {
    title: t('routes.oauth2.login'),
  },
};
}
//update-end---author:wangshuai ---date:20220629  for:auth2登录页面路由------------
/**
@@ -63,7 +63,7 @@
    title: '带token登录页面',
    ignoreAuth: true,
  },
};
}
// Basic routing without permission
export const basicRoutes = [LoginRoute, RootRoute, ...mainOutRoutes, REDIRECT_ROUTE, PAGE_NOT_FOUND_ROUTE, TokenLoginRoute, Oauth2LoginRoute];
export const basicRoutes = [LoginRoute, RootRoute, ...mainOutRoutes, REDIRECT_ROUTE, PAGE_NOT_FOUND_ROUTE, TokenLoginRoute, Oauth2LoginRoute]
src/router/routes/mainOut.ts
@@ -3,7 +3,7 @@
It is an independent new page.
the contents of the file still need to log in to access
 */
import type { AppRouteModule } from '/@/router/types';
import type { AppRouteModule } from '/@/router/types'
// test
// http:ip:port/main-out
@@ -17,6 +17,6 @@
      ignoreAuth: true,
    },
  },
];
]
export const mainOutRouteNames = mainOutRoutes.map((item) => item.name);
export const mainOutRouteNames = mainOutRoutes.map((item) => item.name)
src/router/routes/modules/dashboard.ts
@@ -1,7 +1,7 @@
import type { AppRouteModule } from '/@/router/types';
import type { AppRouteModule } from '/@/router/types'
import { LAYOUT } from '/@/router/constant';
import { t } from '/@/hooks/web/useI18n';
import { t } from '/@/hooks/web/useI18n'
import { LAYOUT } from '/@/router/constant'
const dashboard: AppRouteModule = {
  path: '/dashboard',
@@ -32,6 +32,6 @@
      },
    },
  ],
};
}
export default dashboard;
export default dashboard
src/router/types.ts
@@ -1,59 +1,58 @@
import type { RouteRecordRaw, RouteMeta } from 'vue-router';
import { RoleEnum } from '/@/enums/roleEnum';
import { defineComponent } from 'vue';
import { defineComponent } from 'vue'
import type { RouteMeta, RouteRecordRaw } from 'vue-router'
import { RoleEnum } from '/@/enums/roleEnum'
export type Component<T extends any = any> = ReturnType<typeof defineComponent> | (() => Promise<typeof import('*.vue')>) | (() => Promise<T>);
export type Component<T extends any = any> = ReturnType<typeof defineComponent> | (() => Promise<typeof import('*.vue')>) | (() => Promise<T>)
// @ts-ignore
export interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
  name: string;
  meta: RouteMeta;
  component?: Component | string;
  components?: Component;
  children?: AppRouteRecordRaw[];
  props?: Recordable;
  fullPath?: string;
  alwaysShow?: boolean;
    name: string
    meta: RouteMeta
    component?: Component | string
    components?: Component
    children?: AppRouteRecordRaw[]
    props?: Recordable
    fullPath?: string
    alwaysShow?: boolean
}
export interface MenuTag {
  type?: 'primary' | 'error' | 'warn' | 'success';
  content?: string;
  dot?: boolean;
    type?: 'primary' | 'error' | 'warn' | 'success'
    content?: string
    dot?: boolean
}
export interface Menu {
  name: string;
    name: string
  icon?: string;
    icon?: string
  path: string;
    path: string
  // path contains param, auto assignment.
  paramPath?: string;
    paramPath?: string
  disabled?: boolean;
    disabled?: boolean
  children?: Menu[];
    children?: Menu[]
  orderNo?: number;
    orderNo?: number
  roles?: RoleEnum[];
    roles?: RoleEnum[]
  meta?: Partial<RouteMeta>;
    meta?: Partial<RouteMeta>
  tag?: MenuTag;
    tag?: MenuTag
  hideMenu?: boolean;
    hideMenu?: boolean
  
  alwaysShow?: boolean;
    alwaysShow?: boolean
}
export interface MenuModule {
  orderNo?: number;
  menu: Menu;
    orderNo?: number
    menu: Menu
}
// export type AppRouteModule = RouteModule | AppRouteRecordRaw;
export type AppRouteModule = AppRouteRecordRaw;
export type AppRouteModule = AppRouteRecordRaw
src/store/modules/permission.ts
@@ -1,60 +1,60 @@
import type { AppRouteRecordRaw, Menu } from '/@/router/types';
import type { AppRouteRecordRaw, Menu } from '/@/router/types'
import { defineStore } from 'pinia';
import { store } from '/@/store';
import { useI18n } from '/@/hooks/web/useI18n';
import { useUserStore } from './user';
import { useAppStoreWithOut } from './app';
import { toRaw } from 'vue';
import { transformObjToRoute, flatMultiLevelRoutes, addSlashToRouteComponent } from '/@/router/helper/routeHelper';
import { transformRouteToMenu } from '/@/router/helper/menuHelper';
import { defineStore } from 'pinia'
import { toRaw } from 'vue'
import { useAppStoreWithOut } from './app'
import { useUserStore } from './user'
import { useI18n } from '/@/hooks/web/useI18n'
import { transformRouteToMenu } from '/@/router/helper/menuHelper'
import { addSlashToRouteComponent, flatMultiLevelRoutes, transformObjToRoute } from '/@/router/helper/routeHelper'
import { store } from '/@/store'
import projectSetting from '/@/settings/projectSetting';
import projectSetting from '/@/settings/projectSetting'
import { PermissionModeEnum } from '/@/enums/appEnum';
import { PermissionModeEnum } from '/@/enums/appEnum'
import { asyncRoutes } from '/@/router/routes';
import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
import { asyncRoutes } from '/@/router/routes'
import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'
import { filter } from '/@/utils/helper/treeHelper';
import { filter } from '/@/utils/helper/treeHelper'
import { getMenuList,switchVue3Menu } from '/@/api/sys/menu';
import { getPermCode } from '/@/api/sys/user';
import { getMenuList, switchVue3Menu } from '/@/api/sys/menu'
import { getPermCode } from '/@/api/sys/user'
import { useMessage } from '/@/hooks/web/useMessage';
import { PageEnum } from '/@/enums/pageEnum';
import { PageEnum } from '/@/enums/pageEnum'
import { useMessage } from '/@/hooks/web/useMessage'
// ç³»ç»Ÿæƒé™
interface AuthItem {
  // èœå•权限编码,例如:“sys:schedule:list,sys:schedule:info”,多个逗号隔开
  action: string;
    action: string
  // æƒé™ç­–ç•¥1显示2禁用
  type: string | number;
    type: string | number
  // æƒé™çŠ¶æ€(0无效1有效)
  status: string | number;
    status: string | number
  // æƒé™åç§°
  describe?: string;
  isAuth?: boolean;
    describe?: string
    isAuth?: boolean
}
interface PermissionState {
  // Permission code list
  permCodeList: string[] | number[];
    permCodeList: string[] | number[]
  // Whether the route has been dynamically added
  isDynamicAddedRoute: boolean;
    isDynamicAddedRoute: boolean
  // To trigger a menu update
  lastBuildMenuTime: number;
    lastBuildMenuTime: number
  // Backstage menu list
  backMenuList: Menu[];
  frontMenuList: Menu[];
    backMenuList: Menu[]
    frontMenuList: Menu[]
  // ç”¨æˆ·æ‰€æ‹¥æœ‰çš„æƒé™
  authList: AuthItem[];
    authList: AuthItem[]
  // å…¨éƒ¨æƒé™é…ç½®
  allAuthList: AuthItem[];
    allAuthList: AuthItem[]
  // ç³»ç»Ÿå®‰å…¨æ¨¡å¼
  sysSafeMode: boolean;
    sysSafeMode: boolean
  // online子表按钮权限
  onlineSubTableAuthMap: object;
    onlineSubTableAuthMap: object
}
export const usePermissionStore = defineStore({
  id: 'app-permission',
@@ -75,138 +75,138 @@
  }),
  getters: {
    getPermCodeList(): string[] | number[] {
      return this.permCodeList;
            return this.permCodeList
    },
    getBackMenuList(): Menu[] {
      return this.backMenuList;
            return this.backMenuList
    },
    getFrontMenuList(): Menu[] {
      return this.frontMenuList;
            return this.frontMenuList
    },
    getLastBuildMenuTime(): number {
      return this.lastBuildMenuTime;
            return this.lastBuildMenuTime
    },
    getIsDynamicAddedRoute(): boolean {
      return this.isDynamicAddedRoute;
            return this.isDynamicAddedRoute
    },
    //update-begin-author:taoyan date:2022-6-1 for: VUEN-1162 å­è¡¨æŒ‰é’®æ²¡æŽ§åˆ¶
    getOnlineSubTableAuth: (state) => {
      return (code) => state.onlineSubTableAuthMap[code];
            return (code) => state.onlineSubTableAuthMap[code]
    },
    //update-end-author:taoyan date:2022-6-1 for: VUEN-1162 å­è¡¨æŒ‰é’®æ²¡æŽ§åˆ¶
  },
  actions: {
    setPermCodeList(codeList: string[]) {
      this.permCodeList = codeList;
            this.permCodeList = codeList
    },
    setBackMenuList(list: Menu[]) {
      this.backMenuList = list;
      list?.length > 0 && this.setLastBuildMenuTime();
            this.backMenuList = list
            list?.length > 0 && this.setLastBuildMenuTime()
    },
    setFrontMenuList(list: Menu[]) {
      this.frontMenuList = list;
            this.frontMenuList = list
    },
    setLastBuildMenuTime() {
      this.lastBuildMenuTime = new Date().getTime();
            this.lastBuildMenuTime = new Date().getTime()
    },
    setDynamicAddedRoute(added: boolean) {
      this.isDynamicAddedRoute = added;
            this.isDynamicAddedRoute = added
    },
    resetState(): void {
      this.isDynamicAddedRoute = false;
      this.permCodeList = [];
      this.backMenuList = [];
      this.lastBuildMenuTime = 0;
            this.isDynamicAddedRoute = false
            this.permCodeList = []
            this.backMenuList = []
            this.lastBuildMenuTime = 0
    },
    async changePermissionCode() {
      const systemPermission = await getPermCode();
      const codeList = systemPermission.codeList;
      this.setPermCodeList(codeList);
      this.setAuthData(systemPermission);
            const systemPermission = await getPermCode()
            const codeList = systemPermission.codeList
            this.setPermCodeList(codeList)
            this.setAuthData(systemPermission)
    },
    async buildRoutesAction(): Promise<AppRouteRecordRaw[]> {
      const { t } = useI18n();
      const userStore = useUserStore();
      const appStore = useAppStoreWithOut();
            const { t } = useI18n()
            const userStore = useUserStore()
            const appStore = useAppStoreWithOut()
      let routes: AppRouteRecordRaw[] = [];
      const roleList = toRaw(userStore.getRoleList) || [];
      const { permissionMode = projectSetting.permissionMode } = appStore.getProjectConfig;
            let routes: AppRouteRecordRaw[] = []
            const roleList = toRaw(userStore.getRoleList) || []
            const { permissionMode = projectSetting.permissionMode } = appStore.getProjectConfig
      const routeFilter = (route: AppRouteRecordRaw) => {
        const { meta } = route;
        const { roles } = meta || {};
        if (!roles) return true;
        return roleList.some((role) => roles.includes(role));
      };
                const { meta } = route
                const { roles } = meta || {}
                if (!roles) return true
                return roleList.some((role) => roles.includes(role))
            }
      const routeRemoveIgnoreFilter = (route: AppRouteRecordRaw) => {
        const { meta } = route;
        const { ignoreRoute } = meta || {};
        return !ignoreRoute;
      };
                const { meta } = route
                const { ignoreRoute } = meta || {}
                return !ignoreRoute
            }
      /**
       * @description æ ¹æ®è®¾ç½®çš„首页path,修正routes中的affix标记(固定首页)
       * */
      const patchHomeAffix = (routes: AppRouteRecordRaw[]) => {
        if (!routes || routes.length === 0) return;
        let homePath: string = userStore.getUserInfo.homePath || PageEnum.BASE_HOME;
                if (!routes || routes.length === 0) return
                let homePath: string = userStore.getUserInfo.homePath || PageEnum.BASE_HOME
        function patcher(routes: AppRouteRecordRaw[], parentPath = '') {
          if (parentPath) parentPath = parentPath + '/';
                    if (parentPath) parentPath = parentPath + '/'
          routes.forEach((route: AppRouteRecordRaw) => {
            const { path, children, redirect } = route;
            const currentPath = path.startsWith('/') ? path : parentPath + path;
                        const { path, children, redirect } = route
                        const currentPath = path.startsWith('/') ? path : parentPath + path
            if (currentPath === homePath) {
              if (redirect) {
                homePath = route.redirect! as string;
                                homePath = route.redirect! as string
              } else {
                route.meta = Object.assign({}, route.meta, { affix: true });
                throw new Error('end');
                                route.meta = Object.assign({}, route.meta, { affix: true })
                                throw new Error('end')
              }
            }
            children && children.length > 0 && patcher(children, currentPath);
          });
                        children && children.length > 0 && patcher(children, currentPath)
                    })
        }
        try {
          patcher(routes);
                    patcher(routes)
        } catch (e) {
          // å·²å¤„理完毕跳出循环
        }
        return;
      };
                return
            }
      switch (permissionMode) {
        case PermissionModeEnum.ROLE:
          routes = filter(asyncRoutes, routeFilter);
          routes = routes.filter(routeFilter);
                    routes = filter(asyncRoutes, routeFilter)
                    routes = routes.filter(routeFilter)
          //  å°†å¤šçº§è·¯ç”±è½¬æ¢ä¸ºäºŒçº§
          routes = flatMultiLevelRoutes(routes);
          break;
                    routes = flatMultiLevelRoutes(routes)
                    break
        case PermissionModeEnum.ROUTE_MAPPING:
          routes = filter(asyncRoutes, routeFilter);
          routes = routes.filter(routeFilter);
          const menuList = transformRouteToMenu(routes, true);
          routes = filter(routes, routeRemoveIgnoreFilter);
          routes = routes.filter(routeRemoveIgnoreFilter);
                    routes = filter(asyncRoutes, routeFilter)
                    routes = routes.filter(routeFilter)
                    const menuList = transformRouteToMenu(routes, true)
                    routes = filter(routes, routeRemoveIgnoreFilter)
                    routes = routes.filter(routeRemoveIgnoreFilter)
          menuList.sort((a, b) => {
            return (a.meta?.orderNo || 0) - (b.meta?.orderNo || 0);
          });
                        return (a.meta?.orderNo || 0) - (b.meta?.orderNo || 0)
                    })
          this.setFrontMenuList(menuList);
                    this.setFrontMenuList(menuList)
          // å°†å¤šçº§è·¯ç”±è½¬æ¢ä¸ºäºŒçº§
          routes = flatMultiLevelRoutes(routes);
          break;
                    routes = flatMultiLevelRoutes(routes)
                    break
        // åŽå°èœå•构建
        case PermissionModeEnum.BACK:
          const { createMessage, createWarningModal } = useMessage();
                    const { createMessage, createWarningModal } = useMessage()
          // èœå•加载提示
          // createMessage.loading({
          //   content: t('sys.app.menuLoading'),
@@ -215,25 +215,25 @@
          // ä»ŽåŽå°èŽ·å–æƒé™ç ï¼Œ
          // è¿™ä¸ªå‡½æ•°å¯èƒ½åªéœ€è¦æ‰§è¡Œä¸€æ¬¡ï¼Œå¹¶ä¸”实际的项目可以在正确的时间被放置
          let routeList: AppRouteRecordRaw[] = [];
                    let routeList: AppRouteRecordRaw[] = []
          try {
            this.changePermissionCode();
            routeList = (await getMenuList()) as AppRouteRecordRaw[];
                        this.changePermissionCode()
                        routeList = (await getMenuList()) as AppRouteRecordRaw[]
            // update-begin----author:sunjianlei---date:20220315------for: åˆ¤æ–­æ˜¯å¦æ˜¯ vue3 ç‰ˆæœ¬çš„菜单 ---
            let hasIndex: boolean = false;
            let hasIcon: boolean = false;
            for (let menuItem of routeList) {
                        let hasIndex = false
                        let hasIcon = false
                        for (const menuItem of routeList) {
              // æ¡ä»¶1:判断组件是否是 layouts/default/index
              if (!hasIndex) {
                hasIndex = menuItem.component === 'layouts/default/index';
                                hasIndex = menuItem.component === 'layouts/default/index'
              }
              // æ¡ä»¶2:判断图标是否带有 å†’号
              if (!hasIcon) {
                hasIcon = !!menuItem.meta?.icon?.includes(':');
                                hasIcon = !!menuItem.meta?.icon?.includes(':')
              }
              // æ»¡è¶³ä»»ä½•一个条件都直接跳出循环
              if (hasIcon || hasIndex) {
                break;
                                break
              }
            }
            // ä¸¤ä¸ªæ¡ä»¶éƒ½ä¸æ»¡è¶³ï¼Œå°±å¼¹å‡ºæç¤ºæ¡†
@@ -243,63 +243,62 @@
                () =>
                  createWarningModal({
                    title: '检测提示',
                    content:
                      '当前菜单表是 <b>Vue2版本</b>,导致菜单加载异常!<br>点击确认,切换到Vue3版菜单!',
                                        content: '当前菜单表是 <b>Vue2版本</b>,导致菜单加载异常!<br>点击确认,切换到Vue3版菜单!',
                    onOk:function () {
                      switchVue3Menu();
                      location.reload();
                    }
                                            switchVue3Menu()
                                            location.reload()
                                        },
                  }),
                100
              );
                            )
            }
            // update-end----author:sunjianlei---date:20220315------for: åˆ¤æ–­æ˜¯å¦æ˜¯ vue3 ç‰ˆæœ¬çš„菜单 ---
          } catch (error) {
            console.error(error);
                        console.error(error)
          }
          // ç»„件地址前加斜杠处理  author: lsq date:2021-09-08
          routeList = addSlashToRouteComponent(routeList);
                    routeList = addSlashToRouteComponent(routeList)
          // åŠ¨æ€å¼•å…¥ç»„ä»¶
          routeList = transformObjToRoute(routeList);
                    routeList = transformObjToRoute(routeList)
          // æž„建后台路由菜单
          const backMenuList = transformRouteToMenu(routeList);
          this.setBackMenuList(backMenuList);
                    const backMenuList = transformRouteToMenu(routeList)
                    this.setBackMenuList(backMenuList)
          // åˆ é™¤meta.ignoreRoute项
          routeList = filter(routeList, routeRemoveIgnoreFilter);
          routeList = routeList.filter(routeRemoveIgnoreFilter);
                    routeList = filter(routeList, routeRemoveIgnoreFilter)
                    routeList = routeList.filter(routeRemoveIgnoreFilter)
          routeList = flatMultiLevelRoutes(routeList);
          routes = [PAGE_NOT_FOUND_ROUTE, ...routeList];
          break;
                    routeList = flatMultiLevelRoutes(routeList)
                    routes = [PAGE_NOT_FOUND_ROUTE, ...routeList]
                    break
      }
      routes.push(ERROR_LOG_ROUTE);
      patchHomeAffix(routes);
      return routes;
            routes.push(ERROR_LOG_ROUTE)
            patchHomeAffix(routes)
            return routes
    },
    setAuthData(systemPermission) {
      this.authList = systemPermission.auth;
      this.allAuthList = systemPermission.allAuth;
      this.sysSafeMode = systemPermission.sysSafeMode;
            this.authList = systemPermission.auth
            this.allAuthList = systemPermission.allAuth
            this.sysSafeMode = systemPermission.sysSafeMode
    },
    setAuthList(authList: AuthItem[]) {
      this.authList = authList;
            this.authList = authList
    },
    setAllAuthList(authList: AuthItem[]) {
      this.allAuthList = authList;
            this.allAuthList = authList
    },
    //update-begin-author:taoyan date:2022-6-1 for: VUEN-1162 å­è¡¨æŒ‰é’®æ²¡æŽ§åˆ¶
    setOnlineSubTableAuth(code, hideBtnList) {
      this.onlineSubTableAuthMap[code] = hideBtnList;
            this.onlineSubTableAuthMap[code] = hideBtnList
    },
    //update-end-author:taoyan date:2022-6-1 for: VUEN-1162 å­è¡¨æŒ‰é’®æ²¡æŽ§åˆ¶
  },
});
})
// éœ€è¦åœ¨è®¾ç½®ä¹‹å¤–使用
export function usePermissionStoreWithOut() {
  return usePermissionStore(store);
    return usePermissionStore(store)
}
src/utils/aes.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,505 @@
var t = t || function(t, e) {
  var r = {}, i = r.lib = {}, n = function() {}, o = i.Base = {
    extend: function(t) {
      n.prototype = this;
      var e = new n();
      return t && e.mixIn(t), e.hasOwnProperty("init") || (e.init = function() {
        e.$super.init.apply(this, arguments);
      }), e.init.prototype = e, e.$super = this, e;
    },
    create: function() {
      var t = this.extend();
      return t.init.apply(t, arguments), t;
    },
    init: function() {},
    mixIn: function(t) {
      for (var e in t) t.hasOwnProperty(e) && (this[e] = t[e]);
      t.hasOwnProperty("toString") && (this.toString = t.toString);
    },
    clone: function() {
      return this.init.prototype.extend(this);
    }
  }, s = i.WordArray = o.extend({
    init: function(t, e) {
      t = this.words = t || [], this.sigBytes = void 0 != e ? e : 4 * t.length;
    },
    toString: function(t) {
      return (t || a).stringify(this);
    },
    concat: function(t) {
      var e = this.words, r = t.words, i = this.sigBytes;
      if (t = t.sigBytes, this.clamp(), i % 4) for (var n = 0; n < t; n++) e[i + n >>> 2] |= (r[n >>> 2] >>> 24 - n % 4 * 8 & 255) << 24 - (i + n) % 4 * 8; else if (65535 < r.length) for (n = 0; n < t; n += 4) e[i + n >>> 2] = r[n >>> 2]; else e.push.apply(e, r);
      return this.sigBytes += t, this;
    },
    clamp: function() {
      var e = this.words, r = this.sigBytes;
      e[r >>> 2] &= 4294967295 << 32 - r % 4 * 8, e.length = t.ceil(r / 4);
    },
    clone: function() {
      var t = o.clone.call(this);
      return t.words = this.words.slice(0), t;
    },
    random: function(e) {
      for (var r = [], i = 0; i < e; i += 4) r.push(4294967296 * t.random() | 0);
      return new s.init(r, e);
    }
  }), c = r.enc = {}, a = c.Hex = {
    stringify: function(t) {
      var e = t.words;
      t = t.sigBytes;
      for (var r = [], i = 0; i < t; i++) {
        var n = e[i >>> 2] >>> 24 - i % 4 * 8 & 255;
        r.push((n >>> 4).toString(16)), r.push((15 & n).toString(16));
      }
      return r.join("");
    },
    parse: function(t) {
      for (var e = t.length, r = [], i = 0; i < e; i += 2) r[i >>> 3] |= parseInt(t.substr(i, 2), 16) << 24 - i % 8 * 4;
      return new s.init(r, e / 2);
    }
  }, f = c.Latin1 = {
    stringify: function(t) {
      var e = t.words;
      t = t.sigBytes;
      for (var r = [], i = 0; i < t; i++) r.push(String.fromCharCode(e[i >>> 2] >>> 24 - i % 4 * 8 & 255));
      return r.join("");
    },
    parse: function(t) {
      for (var e = t.length, r = [], i = 0; i < e; i++) r[i >>> 2] |= (255 & t.charCodeAt(i)) << 24 - i % 4 * 8;
      return new s.init(r, e);
    }
  }, h = c.Utf8 = {
    stringify: function(t) {
      try {
        return decodeURIComponent(escape(f.stringify(t)));
      } catch (t) {
        throw Error("Malformed UTF-8 data");
      }
    },
    parse: function(t) {
      return f.parse(unescape(encodeURIComponent(t)));
    }
  }, u = i.BufferedBlockAlgorithm = o.extend({
    reset: function() {
      this._data = new s.init(), this._nDataBytes = 0;
    },
    _append: function(t) {
      "string" == typeof t && (t = h.parse(t)), this._data.concat(t), this._nDataBytes += t.sigBytes;
    },
    _process: function(e) {
      var r = this._data, i = r.words, n = r.sigBytes, o = this.blockSize, c = n / (4 * o);
      if (e = (c = e ? t.ceil(c) : t.max((0 | c) - this._minBufferSize, 0)) * o, n = t.min(4 * e, n),
        e) {
        for (var a = 0; a < e; a += o) this._doProcessBlock(i, a);
        a = i.splice(0, e), r.sigBytes -= n;
      }
      return new s.init(a, n);
    },
    clone: function() {
      var t = o.clone.call(this);
      return t._data = this._data.clone(), t;
    },
    _minBufferSize: 0
  });
  i.Hasher = u.extend({
    cfg: o.extend(),
    init: function(t) {
      this.cfg = this.cfg.extend(t), this.reset();
    },
    reset: function() {
      u.reset.call(this), this._doReset();
    },
    update: function(t) {
      return this._append(t), this._process(), this;
    },
    finalize: function(t) {
      return t && this._append(t), this._doFinalize();
    },
    blockSize: 16,
    _createHelper: function(t) {
      return function(e, r) {
        return new t.init(r).finalize(e);
      };
    },
    _createHmacHelper: function(t) {
      return function(e, r) {
        return new p.HMAC.init(t, r).finalize(e);
      };
    }
  });
  var p = r.algo = {};
  return r;
}(Math);
!function() {
  var e = t, r = e.lib.WordArray;
  e.enc.Base64 = {
    stringify: function(t) {
      var e = t.words, r = t.sigBytes, i = this._map;
      t.clamp(), t = [];
      for (var n = 0; n < r; n += 3) for (var o = (e[n >>> 2] >>> 24 - n % 4 * 8 & 255) << 16 | (e[n + 1 >>> 2] >>> 24 - (n + 1) % 4 * 8 & 255) << 8 | e[n + 2 >>> 2] >>> 24 - (n + 2) % 4 * 8 & 255, s = 0; 4 > s && n + .75 * s < r; s++) t.push(i.charAt(o >>> 6 * (3 - s) & 63));
      if (e = i.charAt(64)) for (;t.length % 4; ) t.push(e);
      return t.join("");
    },
    parse: function(t) {
      var e = t.length, i = this._map;
      (n = i.charAt(64)) && -1 != (n = t.indexOf(n)) && (e = n);
      for (var n = [], o = 0, s = 0; s < e; s++) if (s % 4) {
        var c = i.indexOf(t.charAt(s - 1)) << s % 4 * 2, a = i.indexOf(t.charAt(s)) >>> 6 - s % 4 * 2;
        n[o >>> 2] |= (c | a) << 24 - o % 4 * 8, o++;
      }
      return r.create(n, o);
    },
    _map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
  };
}(), function(e) {
  function r(t, e, r, i, n, o, s) {
    return ((t = t + (e & r | ~e & i) + n + s) << o | t >>> 32 - o) + e;
  }
  function i(t, e, r, i, n, o, s) {
    return ((t = t + (e & i | r & ~i) + n + s) << o | t >>> 32 - o) + e;
  }
  function n(t, e, r, i, n, o, s) {
    return ((t = t + (e ^ r ^ i) + n + s) << o | t >>> 32 - o) + e;
  }
  function o(t, e, r, i, n, o, s) {
    return ((t = t + (r ^ (e | ~i)) + n + s) << o | t >>> 32 - o) + e;
  }
  for (var s = t, c = (f = s.lib).WordArray, a = f.Hasher, f = s.algo, h = [], u = 0; 64 > u; u++) h[u] = 4294967296 * e.abs(e.sin(u + 1)) | 0;
  f = f.MD5 = a.extend({
    _doReset: function() {
      this._hash = new c.init([ 1732584193, 4023233417, 2562383102, 271733878 ]);
    },
    _doProcessBlock: function(t, e) {
      for (s = 0; 16 > s; s++) {
        a = t[c = e + s];
        t[c] = 16711935 & (a << 8 | a >>> 24) | 4278255360 & (a << 24 | a >>> 8);
      }
      var s = this._hash.words, c = t[e + 0], a = t[e + 1], f = t[e + 2], u = t[e + 3], p = t[e + 4], d = t[e + 5], l = t[e + 6], y = t[e + 7], v = t[e + 8], _ = t[e + 9], g = t[e + 10], B = t[e + 11], k = t[e + 12], x = t[e + 13], m = t[e + 14], S = t[e + 15], w = s[0], z = s[1], C = s[2], E = s[3], z = o(z = o(z = o(z = o(z = n(z = n(z = n(z = n(z = i(z = i(z = i(z = i(z = r(z = r(z = r(z = r(z, C = r(C, E = r(E, w = r(w, z, C, E, c, 7, h[0]), z, C, a, 12, h[1]), w, z, f, 17, h[2]), E, w, u, 22, h[3]), C = r(C, E = r(E, w = r(w, z, C, E, p, 7, h[4]), z, C, d, 12, h[5]), w, z, l, 17, h[6]), E, w, y, 22, h[7]), C = r(C, E = r(E, w = r(w, z, C, E, v, 7, h[8]), z, C, _, 12, h[9]), w, z, g, 17, h[10]), E, w, B, 22, h[11]), C = r(C, E = r(E, w = r(w, z, C, E, k, 7, h[12]), z, C, x, 12, h[13]), w, z, m, 17, h[14]), E, w, S, 22, h[15]), C = i(C, E = i(E, w = i(w, z, C, E, a, 5, h[16]), z, C, l, 9, h[17]), w, z, B, 14, h[18]), E, w, c, 20, h[19]), C = i(C, E = i(E, w = i(w, z, C, E, d, 5, h[20]), z, C, g, 9, h[21]), w, z, S, 14, h[22]), E, w, p, 20, h[23]), C = i(C, E = i(E, w = i(w, z, C, E, _, 5, h[24]), z, C, m, 9, h[25]), w, z, u, 14, h[26]), E, w, v, 20, h[27]), C = i(C, E = i(E, w = i(w, z, C, E, x, 5, h[28]), z, C, f, 9, h[29]), w, z, y, 14, h[30]), E, w, k, 20, h[31]), C = n(C, E = n(E, w = n(w, z, C, E, d, 4, h[32]), z, C, v, 11, h[33]), w, z, B, 16, h[34]), E, w, m, 23, h[35]), C = n(C, E = n(E, w = n(w, z, C, E, a, 4, h[36]), z, C, p, 11, h[37]), w, z, y, 16, h[38]), E, w, g, 23, h[39]), C = n(C, E = n(E, w = n(w, z, C, E, x, 4, h[40]), z, C, c, 11, h[41]), w, z, u, 16, h[42]), E, w, l, 23, h[43]), C = n(C, E = n(E, w = n(w, z, C, E, _, 4, h[44]), z, C, k, 11, h[45]), w, z, S, 16, h[46]), E, w, f, 23, h[47]), C = o(C, E = o(E, w = o(w, z, C, E, c, 6, h[48]), z, C, y, 10, h[49]), w, z, m, 15, h[50]), E, w, d, 21, h[51]), C = o(C, E = o(E, w = o(w, z, C, E, k, 6, h[52]), z, C, u, 10, h[53]), w, z, g, 15, h[54]), E, w, a, 21, h[55]), C = o(C, E = o(E, w = o(w, z, C, E, v, 6, h[56]), z, C, S, 10, h[57]), w, z, l, 15, h[58]), E, w, x, 21, h[59]), C = o(C, E = o(E, w = o(w, z, C, E, p, 6, h[60]), z, C, B, 10, h[61]), w, z, f, 15, h[62]), E, w, _, 21, h[63]);
      s[0] = s[0] + w | 0, s[1] = s[1] + z | 0, s[2] = s[2] + C | 0, s[3] = s[3] + E | 0;
    },
    _doFinalize: function() {
      var t = this._data, r = t.words, i = 8 * this._nDataBytes, n = 8 * t.sigBytes;
      r[n >>> 5] |= 128 << 24 - n % 32;
      var o = e.floor(i / 4294967296);
      for (r[15 + (n + 64 >>> 9 << 4)] = 16711935 & (o << 8 | o >>> 24) | 4278255360 & (o << 24 | o >>> 8),
             r[14 + (n + 64 >>> 9 << 4)] = 16711935 & (i << 8 | i >>> 24) | 4278255360 & (i << 24 | i >>> 8),
             t.sigBytes = 4 * (r.length + 1), this._process(), r = (t = this._hash).words, i = 0; 4 > i; i++) n = r[i],
        r[i] = 16711935 & (n << 8 | n >>> 24) | 4278255360 & (n << 24 | n >>> 8);
      return t;
    },
    clone: function() {
      var t = a.clone.call(this);
      return t._hash = this._hash.clone(), t;
    }
  }), s.MD5 = a._createHelper(f), s.HmacMD5 = a._createHmacHelper(f);
}(Math), function() {
  var e = t, r = e.lib, i = r.Base, n = r.WordArray, o = (r = e.algo).EvpKDF = i.extend({
    cfg: i.extend({
      keySize: 4,
      hasher: r.MD5,
      iterations: 1
    }),
    init: function(t) {
      this.cfg = this.cfg.extend(t);
    },
    compute: function(t, e) {
      for (var r = (c = this.cfg).hasher.create(), i = n.create(), o = i.words, s = c.keySize, c = c.iterations; o.length < s; ) {
        a && r.update(a);
        var a = r.update(t).finalize(e);
        r.reset();
        for (var f = 1; f < c; f++) a = r.finalize(a), r.reset();
        i.concat(a);
      }
      return i.sigBytes = 4 * s, i;
    }
  });
  e.EvpKDF = function(t, e, r) {
    return o.create(r).compute(t, e);
  };
}(), t.lib.Cipher || function(e) {
  var r = (l = t).lib, i = r.Base, n = r.WordArray, o = r.BufferedBlockAlgorithm, s = l.enc.Base64, c = l.algo.EvpKDF, a = r.Cipher = o.extend({
    cfg: i.extend(),
    createEncryptor: function(t, e) {
      return this.create(this._ENC_XFORM_MODE, t, e);
    },
    createDecryptor: function(t, e) {
      return this.create(this._DEC_XFORM_MODE, t, e);
    },
    init: function(t, e, r) {
      this.cfg = this.cfg.extend(r), this._xformMode = t, this._key = e, this.reset();
    },
    reset: function() {
      o.reset.call(this), this._doReset();
    },
    process: function(t) {
      return this._append(t), this._process();
    },
    finalize: function(t) {
      return t && this._append(t), this._doFinalize();
    },
    keySize: 4,
    ivSize: 4,
    _ENC_XFORM_MODE: 1,
    _DEC_XFORM_MODE: 2,
    _createHelper: function(t) {
      return {
        encrypt: function(e, r, i) {
          return ("string" == typeof r ? y : d).encrypt(t, e, r, i);
        },
        decrypt: function(e, r, i) {
          return ("string" == typeof r ? y : d).decrypt(t, e, r, i);
        }
      };
    }
  });
  r.StreamCipher = a.extend({
    _doFinalize: function() {
      return this._process(!0);
    },
    blockSize: 1
  });
  var f = l.mode = {}, h = function(t, e, r) {
    var i = this._iv;
    i ? this._iv = void 0 : i = this._prevBlock;
    for (var n = 0; n < r; n++) t[e + n] ^= i[n];
  }, u = (r.BlockCipherMode = i.extend({
    createEncryptor: function(t, e) {
      return this.Encryptor.create(t, e);
    },
    createDecryptor: function(t, e) {
      return this.Decryptor.create(t, e);
    },
    init: function(t, e) {
      this._cipher = t, this._iv = e;
    }
  })).extend();
  u.Encryptor = u.extend({
    processBlock: function(t, e) {
      var r = this._cipher, i = r.blockSize;
      h.call(this, t, e, i), r.encryptBlock(t, e), this._prevBlock = t.slice(e, e + i);
    }
  }), u.Decryptor = u.extend({
    processBlock: function(t, e) {
      var r = this._cipher, i = r.blockSize, n = t.slice(e, e + i);
      r.decryptBlock(t, e), h.call(this, t, e, i), this._prevBlock = n;
    }
  }), f = f.CBC = u, u = (l.pad = {}).Pkcs7 = {
    pad: function(t, e) {
      for (var r = 4 * e, i = (r = r - t.sigBytes % r) << 24 | r << 16 | r << 8 | r, o = [], s = 0; s < r; s += 4) o.push(i);
      r = n.create(o, r), t.concat(r);
    },
    unpad: function(t) {
      t.sigBytes -= 255 & t.words[t.sigBytes - 1 >>> 2];
    }
  }, r.BlockCipher = a.extend({
    cfg: a.cfg.extend({
      mode: f,
      padding: u
    }),
    reset: function() {
      a.reset.call(this);
      var t = (e = this.cfg).iv, e = e.mode;
      if (this._xformMode == this._ENC_XFORM_MODE) var r = e.createEncryptor; else r = e.createDecryptor,
        this._minBufferSize = 1;
      this._mode = r.call(e, this, t && t.words);
    },
    _doProcessBlock: function(t, e) {
      this._mode.processBlock(t, e);
    },
    _doFinalize: function() {
      var t = this.cfg.padding;
      if (this._xformMode == this._ENC_XFORM_MODE) {
        t.pad(this._data, this.blockSize);
        var e = this._process(!0);
      } else e = this._process(!0), t.unpad(e);
      return e;
    },
    blockSize: 4
  });
  var p = r.CipherParams = i.extend({
    init: function(t) {
      this.mixIn(t);
    },
    toString: function(t) {
      return (t || this.formatter).stringify(this);
    }
  }), f = (l.format = {}).OpenSSL = {
    stringify: function(t) {
      var e = t.ciphertext;
      return ((t = t.salt) ? n.create([ 1398893684, 1701076831 ]).concat(t).concat(e) : e).toString(s);
    },
    parse: function(t) {
      var e = (t = s.parse(t)).words;
      if (1398893684 == e[0] && 1701076831 == e[1]) {
        var r = n.create(e.slice(2, 4));
        e.splice(0, 4), t.sigBytes -= 16;
      }
      return p.create({
        ciphertext: t,
        salt: r
      });
    }
  }, d = r.SerializableCipher = i.extend({
    cfg: i.extend({
      format: f
    }),
    encrypt: function(t, e, r, i) {
      i = this.cfg.extend(i);
      var n = t.createEncryptor(r, i);
      return e = n.finalize(e), n = n.cfg, p.create({
        ciphertext: e,
        key: r,
        iv: n.iv,
        algorithm: t,
        mode: n.mode,
        padding: n.padding,
        blockSize: t.blockSize,
        formatter: i.format
      });
    },
    decrypt: function(t, e, r, i) {
      return i = this.cfg.extend(i), e = this._parse(e, i.format), t.createDecryptor(r, i).finalize(e.ciphertext);
    },
    _parse: function(t, e) {
      return "string" == typeof t ? e.parse(t, this) : t;
    }
  }), l = (l.kdf = {}).OpenSSL = {
    execute: function(t, e, r, i) {
      return i || (i = n.random(8)), t = c.create({
        keySize: e + r
      }).compute(t, i), r = n.create(t.words.slice(e), 4 * r), t.sigBytes = 4 * e, p.create({
        key: t,
        iv: r,
        salt: i
      });
    }
  }, y = r.PasswordBasedCipher = d.extend({
    cfg: d.cfg.extend({
      kdf: l
    }),
    encrypt: function(t, e, r, i) {
      return i = this.cfg.extend(i), r = i.kdf.execute(r, t.keySize, t.ivSize), i.iv = r.iv,
        (t = d.encrypt.call(this, t, e, r.key, i)).mixIn(r), t;
    },
    decrypt: function(t, e, r, i) {
      return i = this.cfg.extend(i), e = this._parse(e, i.format), r = i.kdf.execute(r, t.keySize, t.ivSize, e.salt),
        i.iv = r.iv, d.decrypt.call(this, t, e, r.key, i);
    }
  });
}(), function() {
  for (var e = t, r = e.lib.BlockCipher, i = e.algo, n = [], o = [], s = [], c = [], a = [], f = [], h = [], u = [], p = [], d = [], l = [], y = 0; 256 > y; y++) l[y] = 128 > y ? y << 1 : y << 1 ^ 283;
  for (var v = 0, _ = 0, y = 0; 256 > y; y++) {
    var g = (g = _ ^ _ << 1 ^ _ << 2 ^ _ << 3 ^ _ << 4) >>> 8 ^ 255 & g ^ 99;
    n[v] = g, o[g] = v;
    var B = l[v], k = l[B], x = l[k], m = 257 * l[g] ^ 16843008 * g;
    s[v] = m << 24 | m >>> 8, c[v] = m << 16 | m >>> 16, a[v] = m << 8 | m >>> 24, f[v] = m,
      m = 16843009 * x ^ 65537 * k ^ 257 * B ^ 16843008 * v, h[g] = m << 24 | m >>> 8,
      u[g] = m << 16 | m >>> 16, p[g] = m << 8 | m >>> 24, d[g] = m, v ? (v = B ^ l[l[l[x ^ B]]],
      _ ^= l[l[_]]) : v = _ = 1;
  }
  var S = [ 0, 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 ], i = i.AES = r.extend({
    _doReset: function() {
      for (var t = (r = this._key).words, e = r.sigBytes / 4, r = 4 * ((this._nRounds = e + 6) + 1), i = this._keySchedule = [], o = 0; o < r; o++) if (o < e) i[o] = t[o]; else {
        var s = i[o - 1];
        o % e ? 6 < e && 4 == o % e && (s = n[s >>> 24] << 24 | n[s >>> 16 & 255] << 16 | n[s >>> 8 & 255] << 8 | n[255 & s]) : (s = s << 8 | s >>> 24,
          s = n[s >>> 24] << 24 | n[s >>> 16 & 255] << 16 | n[s >>> 8 & 255] << 8 | n[255 & s],
          s ^= S[o / e | 0] << 24), i[o] = i[o - e] ^ s;
      }
      for (t = this._invKeySchedule = [], e = 0; e < r; e++) o = r - e, s = e % 4 ? i[o] : i[o - 4],
        t[e] = 4 > e || 4 >= o ? s : h[n[s >>> 24]] ^ u[n[s >>> 16 & 255]] ^ p[n[s >>> 8 & 255]] ^ d[n[255 & s]];
    },
    encryptBlock: function(t, e) {
      this._doCryptBlock(t, e, this._keySchedule, s, c, a, f, n);
    },
    decryptBlock: function(t, e) {
      var r = t[e + 1];
      t[e + 1] = t[e + 3], t[e + 3] = r, this._doCryptBlock(t, e, this._invKeySchedule, h, u, p, d, o),
        r = t[e + 1], t[e + 1] = t[e + 3], t[e + 3] = r;
    },
    _doCryptBlock: function(t, e, r, i, n, o, s, c) {
      for (var a = this._nRounds, f = t[e] ^ r[0], h = t[e + 1] ^ r[1], u = t[e + 2] ^ r[2], p = t[e + 3] ^ r[3], d = 4, l = 1; l < a; l++) var y = i[f >>> 24] ^ n[h >>> 16 & 255] ^ o[u >>> 8 & 255] ^ s[255 & p] ^ r[d++], v = i[h >>> 24] ^ n[u >>> 16 & 255] ^ o[p >>> 8 & 255] ^ s[255 & f] ^ r[d++], _ = i[u >>> 24] ^ n[p >>> 16 & 255] ^ o[f >>> 8 & 255] ^ s[255 & h] ^ r[d++], p = i[p >>> 24] ^ n[f >>> 16 & 255] ^ o[h >>> 8 & 255] ^ s[255 & u] ^ r[d++], f = y, h = v, u = _;
      y = (c[f >>> 24] << 24 | c[h >>> 16 & 255] << 16 | c[u >>> 8 & 255] << 8 | c[255 & p]) ^ r[d++],
        v = (c[h >>> 24] << 24 | c[u >>> 16 & 255] << 16 | c[p >>> 8 & 255] << 8 | c[255 & f]) ^ r[d++],
        _ = (c[u >>> 24] << 24 | c[p >>> 16 & 255] << 16 | c[f >>> 8 & 255] << 8 | c[255 & h]) ^ r[d++],
        p = (c[p >>> 24] << 24 | c[f >>> 16 & 255] << 16 | c[h >>> 8 & 255] << 8 | c[255 & u]) ^ r[d++],
        t[e] = y, t[e + 1] = v, t[e + 2] = _, t[e + 3] = p;
    },
    keySize: 8
  });
  e.AES = r._createHelper(i);
}(), t.enc.u8array = {
  stringify: function(t) {
    for (var e = t.words, r = t.sigBytes, i = new Uint8Array(r), n = 0; n < r; n++) {
      var o = e[n >>> 2] >>> 24 - n % 4 * 8 & 255;
      i[n] = o;
    }
    return i;
  },
  parse: function(e) {
    for (var r = e.length, i = [], n = 0; n < r; n++) i[n >>> 2] |= (255 & e[n]) << 24 - n % 4 * 8;
    return t.lib.WordArray.create(i, r);
  }
}, t.enc.int8array = {
  stringify: function(t) {
    for (var e = t.words, r = t.sigBytes, i = new Int8Array(r), n = 0; n < r; n++) {
      var o = e[n >>> 2] >> 24 - n % 4 * 8 & 255;
      i[n] = o;
    }
    return i;
  },
  parse: function(e) {
    for (var r = e.length, i = [], n = 0; n < r; n++) i[n >>> 2] |= (255 & e[n]) << 24 - n % 4 * 8;
    return t.lib.WordArray.create(i, r);
  }
}, t.enc.int16array = {
  stringify: function(t) {
    for (var e = t.words, r = t.sigBytes, i = new Uint8Array(r), n = 0; n < r; n++) {
      var o = e[n >>> 2] >>> 24 - n % 4 * 8 & 255;
      i[n] = o;
    }
    return i;
  },
  parse: function(e) {
    for (var r = e.length, i = [], n = 0; n < r; n++) i[n >>> 2] |= (255 & e[n]) << 24 - n % 4 * 8;
    return t.lib.WordArray.create(i, r);
  }
}, t.mode.CFB = function() {
  function e(t, e, r, i) {
    var n = this._iv;
    if (n) {
      o = n.slice(0);
      this._iv = void 0;
    } else var o = this._prevBlock;
    i.encryptBlock(o, 0);
    for (var s = 0; s < r; s++) t[e + s] ^= o[s];
  }
  var r = t.lib.BlockCipherMode.extend();
  return r.Encryptor = r.extend({
    processBlock: function(t, r) {
      var i = this._cipher, n = i.blockSize;
      e.call(this, t, r, n, i), this._prevBlock = t.slice(r, r + n);
    }
  }), r.Decryptor = r.extend({
    processBlock: function(t, r) {
      var i = this._cipher, n = i.blockSize, o = t.slice(r, r + n);
      e.call(this, t, r, n, i), this._prevBlock = o;
    }
  }), r;
}(), t.mode.ECB = function() {
  var e = t.lib.BlockCipherMode.extend();
  return e.Encryptor = e.extend({
    processBlock: function(t, e) {
      this._cipher.encryptBlock(t, e);
    }
  }), e.Decryptor = e.extend({
    processBlock: function(t, e) {
      this._cipher.decryptBlock(t, e);
    }
  }), e;
}(), t.pad.NoPadding = {
  pad: function() {},
  unpad: function() {}
}, module.exports = {
  CryptoJS: t
};
src/utils/http/axios/index.ts
src/utils/libgif/libgif.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,990 @@
/*
    SuperGif
    Example usage:
        <img src="./example1_preview.gif" rel:animated_src="./example1.gif" width="360" height="360" rel:auto_play="1" />
        <script type="text/javascript">
            $$('img').each(function (img_tag) {
                if (/.*\.gif/.test(img_tag.src)) {
                    var rub = new SuperGif({ gif: img_tag } );
                    rub.load();
                }
            });
        </script>
    Image tag attributes:
        rel:animated_src -    If this url is specified, it's loaded into the player instead of src.
                            This allows a preview frame to be shown until animated gif data is streamed into the canvas
        rel:auto_play -        Defaults to 1 if not specified. If set to zero, a call to the play() method is needed
    Constructor options args
        gif                 Required. The DOM element of an img tag.
        loop_mode            Optional. Setting this to false will force disable looping of the gif.
        auto_play             Optional. Same as the rel:auto_play attribute above, this arg overrides the img tag info.
        max_width            Optional. Scale images over max_width down to max_width. Helpful with mobile.
            on_end                Optional. Add a callback for when the gif reaches the end of a single loop (one iteration). The first argument passed will be the gif HTMLElement.
        loop_delay            Optional. The amount of time to pause (in ms) after each single loop (iteration).
        draw_while_loading    Optional. Determines whether the gif will be drawn to the canvas whilst it is loaded.
        show_progress_bar    Optional. Only applies when draw_while_loading is set to true.
    Instance methods
        // loading
        load( callback )        Loads the gif specified by the src or rel:animated_src sttributie of the img tag into a canvas element and then calls callback if one is passed
        load_url( src, callback )    Loads the gif file specified in the src argument into a canvas element and then calls callback if one is passed
        // play controls
        play -                Start playing the gif
        pause -                Stop playing the gif
        move_to(i) -        Move to frame i of the gif
        move_relative(i) -    Move i frames ahead (or behind if i < 0)
        // getters
        get_canvas            The canvas element that the gif is playing in. Handy for assigning event handlers to.
        get_playing            Whether or not the gif is currently playing
        get_loading            Whether or not the gif has finished loading/parsing
        get_auto_play        Whether or not the gif is set to play automatically
        get_length            The number of frames in the gif
        get_current_frame    The index of the currently displayed frame of the gif
        For additional customization (viewport inside iframe) these params may be passed:
        c_w, c_h - width and height of canvas
        vp_t, vp_l, vp_ w, vp_h - top, left, width and height of the viewport
        A bonus: few articles to understand what is going on
            http://enthusiasms.org/post/16976438906
            http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp
            http://humpy77.deviantart.com/journal/Frame-Delay-Times-for-Animated-GIFs-214150546
*/
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
      define([], factory);
  } else if (typeof exports === 'object') {
      module.exports = factory();
  } else {
      root.SuperGif = factory();
  }
}(this, function () {
  // Generic functions
  var bitsToNum = function (ba) {
      return ba.reduce(function (s, n) {
          return s * 2 + n;
      }, 0);
  };
  var byteToBitArr = function (bite) {
      var a = [];
      for (var i = 7; i >= 0; i--) {
          a.push(!!(bite & (1 << i)));
      }
      return a;
  };
  // Stream
  /**
   * @constructor
   */
  // Make compiler happy.
  var Stream = function (data) {
      this.data = data;
      this.len = this.data.length;
      this.pos = 0;
      this.readByte = function () {
          if (this.pos >= this.data.length) {
              throw new Error('Attempted to read past end of stream.');
          }
          if (data instanceof Uint8Array)
              return data[this.pos++];
          else
              return data.charCodeAt(this.pos++) & 0xFF;
      };
      this.readBytes = function (n) {
          var bytes = [];
          for (var i = 0; i < n; i++) {
              bytes.push(this.readByte());
          }
          return bytes;
      };
      this.read = function (n) {
          var s = '';
          for (var i = 0; i < n; i++) {
              s += String.fromCharCode(this.readByte());
          }
          return s;
      };
      this.readUnsigned = function () { // Little-endian.
          var a = this.readBytes(2);
          return (a[1] << 8) + a[0];
      };
  };
  var lzwDecode = function (minCodeSize, data) {
      // TODO: Now that the GIF parser is a bit different, maybe this should get an array of bytes instead of a String?
      var pos = 0; // Maybe this streaming thing should be merged with the Stream?
      var readCode = function (size) {
          var code = 0;
          for (var i = 0; i < size; i++) {
              if (data.charCodeAt(pos >> 3) & (1 << (pos & 7))) {
                  code |= 1 << i;
              }
              pos++;
          }
          return code;
      };
      var output = [];
      var clearCode = 1 << minCodeSize;
      var eoiCode = clearCode + 1;
      var codeSize = minCodeSize + 1;
      var dict = [];
      var clear = function () {
          dict = [];
          codeSize = minCodeSize + 1;
          for (var i = 0; i < clearCode; i++) {
              dict[i] = [i];
          }
          dict[clearCode] = [];
          dict[eoiCode] = null;
      };
      var code;
      var last;
      while (true) {
          last = code;
          code = readCode(codeSize);
          if (code === clearCode) {
              clear();
              continue;
          }
          if (code === eoiCode) break;
          if (code < dict.length) {
              if (last !== clearCode) {
                  dict.push(dict[last].concat(dict[code][0]));
              }
          }
          else {
              if (code !== dict.length) throw new Error('Invalid LZW code.');
              dict.push(dict[last].concat(dict[last][0]));
          }
          output.push.apply(output, dict[code]);
          if (dict.length === (1 << codeSize) && codeSize < 12) {
              // If we're at the last code and codeSize is 12, the next code will be a clearCode, and it'll be 12 bits long.
              codeSize++;
          }
      }
      // I don't know if this is technically an error, but some GIFs do it.
      //if (Math.ceil(pos / 8) !== data.length) throw new Error('Extraneous LZW bytes.');
      return output;
  };
  // The actual parsing; returns an object with properties.
  var parseGIF = function (st, handler) {
      handler || (handler = {});
      // LZW (GIF-specific)
      var parseCT = function (entries) { // Each entry is 3 bytes, for RGB.
          var ct = [];
          for (var i = 0; i < entries; i++) {
              ct.push(st.readBytes(3));
          }
          return ct;
      };
      var readSubBlocks = function () {
          var size, data;
          data = '';
          do {
              size = st.readByte();
              data += st.read(size);
          } while (size !== 0);
          return data;
      };
      var parseHeader = function () {
          var hdr = {};
          hdr.sig = st.read(3);
          hdr.ver = st.read(3);
          if (hdr.sig !== 'GIF') throw new Error('Not a GIF file.'); // XXX: This should probably be handled more nicely.
          hdr.width = st.readUnsigned();
          hdr.height = st.readUnsigned();
          var bits = byteToBitArr(st.readByte());
          hdr.gctFlag = bits.shift();
          hdr.colorRes = bitsToNum(bits.splice(0, 3));
          hdr.sorted = bits.shift();
          hdr.gctSize = bitsToNum(bits.splice(0, 3));
          hdr.bgColor = st.readByte();
          hdr.pixelAspectRatio = st.readByte(); // if not 0, aspectRatio = (pixelAspectRatio + 15) / 64
          if (hdr.gctFlag) {
              hdr.gct = parseCT(1 << (hdr.gctSize + 1));
          }
          handler.hdr && handler.hdr(hdr);
      };
      var parseExt = function (block) {
          var parseGCExt = function (block) {
              var blockSize = st.readByte(); // Always 4
              var bits = byteToBitArr(st.readByte());
              block.reserved = bits.splice(0, 3); // Reserved; should be 000.
              block.disposalMethod = bitsToNum(bits.splice(0, 3));
              block.userInput = bits.shift();
              block.transparencyGiven = bits.shift();
              block.delayTime = st.readUnsigned();
              block.transparencyIndex = st.readByte();
              block.terminator = st.readByte();
              handler.gce && handler.gce(block);
          };
          var parseComExt = function (block) {
              block.comment = readSubBlocks();
              handler.com && handler.com(block);
          };
          var parsePTExt = function (block) {
              // No one *ever* uses this. If you use it, deal with parsing it yourself.
              var blockSize = st.readByte(); // Always 12
              block.ptHeader = st.readBytes(12);
              block.ptData = readSubBlocks();
              handler.pte && handler.pte(block);
          };
          var parseAppExt = function (block) {
              var parseNetscapeExt = function (block) {
                  var blockSize = st.readByte(); // Always 3
                  block.unknown = st.readByte(); // ??? Always 1? What is this?
                  block.iterations = st.readUnsigned();
                  block.terminator = st.readByte();
                  handler.app && handler.app.NETSCAPE && handler.app.NETSCAPE(block);
              };
              var parseUnknownAppExt = function (block) {
                  block.appData = readSubBlocks();
                  // FIXME: This won't work if a handler wants to match on any identifier.
                  handler.app && handler.app[block.identifier] && handler.app[block.identifier](block);
              };
              var blockSize = st.readByte(); // Always 11
              block.identifier = st.read(8);
              block.authCode = st.read(3);
              switch (block.identifier) {
                  case 'NETSCAPE':
                      parseNetscapeExt(block);
                      break;
                  default:
                      parseUnknownAppExt(block);
                      break;
              }
          };
          var parseUnknownExt = function (block) {
              block.data = readSubBlocks();
              handler.unknown && handler.unknown(block);
          };
          block.label = st.readByte();
          switch (block.label) {
              case 0xF9:
                  block.extType = 'gce';
                  parseGCExt(block);
                  break;
              case 0xFE:
                  block.extType = 'com';
                  parseComExt(block);
                  break;
              case 0x01:
                  block.extType = 'pte';
                  parsePTExt(block);
                  break;
              case 0xFF:
                  block.extType = 'app';
                  parseAppExt(block);
                  break;
              default:
                  block.extType = 'unknown';
                  parseUnknownExt(block);
                  break;
          }
      };
      var parseImg = function (img) {
          var deinterlace = function (pixels, width) {
              // Of course this defeats the purpose of interlacing. And it's *probably*
              // the least efficient way it's ever been implemented. But nevertheless...
              var newPixels = new Array(pixels.length);
              var rows = pixels.length / width;
              var cpRow = function (toRow, fromRow) {
                  var fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width);
                  newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels));
              };
              // See appendix E.
              var offsets = [0, 4, 2, 1];
              var steps = [8, 8, 4, 2];
              var fromRow = 0;
              for (var pass = 0; pass < 4; pass++) {
                  for (var toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) {
                      cpRow(toRow, fromRow)
                      fromRow++;
                  }
              }
              return newPixels;
          };
          img.leftPos = st.readUnsigned();
          img.topPos = st.readUnsigned();
          img.width = st.readUnsigned();
          img.height = st.readUnsigned();
          var bits = byteToBitArr(st.readByte());
          img.lctFlag = bits.shift();
          img.interlaced = bits.shift();
          img.sorted = bits.shift();
          img.reserved = bits.splice(0, 2);
          img.lctSize = bitsToNum(bits.splice(0, 3));
          if (img.lctFlag) {
              img.lct = parseCT(1 << (img.lctSize + 1));
          }
          img.lzwMinCodeSize = st.readByte();
          var lzwData = readSubBlocks();
          img.pixels = lzwDecode(img.lzwMinCodeSize, lzwData);
          if (img.interlaced) { // Move
              img.pixels = deinterlace(img.pixels, img.width);
          }
          handler.img && handler.img(img);
      };
      var parseBlock = function () {
          var block = {};
          block.sentinel = st.readByte();
          switch (String.fromCharCode(block.sentinel)) { // For ease of matching
              case '!':
                  block.type = 'ext';
                  parseExt(block);
                  break;
              case ',':
                  block.type = 'img';
                  parseImg(block);
                  break;
              case ';':
                  block.type = 'eof';
                  handler.eof && handler.eof(block);
                  break;
              default:
                  throw new Error('Unknown block: 0x' + block.sentinel.toString(16)); // TODO: Pad this with a 0.
          }
          if (block.type !== 'eof') setTimeout(parseBlock, 0);
      };
      var parse = function () {
          parseHeader();
          setTimeout(parseBlock, 0);
      };
      parse();
  };
  var SuperGif = function (opts) {
      var options = {
          //viewport position
          vp_l: 0,
          vp_t: 0,
          vp_w: null,
          vp_h: null,
          //canvas sizes
          c_w: null,
          c_h: null
      };
      for (var i in opts) { options[i] = opts[i] }
      if (options.vp_w && options.vp_h) options.is_vp = true;
      var stream;
      var hdr;
      var loadError = null;
      var loading = false;
      var transparency = null;
      var delay = null;
      var disposalMethod = null;
      var disposalRestoreFromIdx = null;
      var lastDisposalMethod = null;
      var frame = null;
      var lastImg = null;
      var playing = true;
      var forward = true;
      var ctx_scaled = false;
      var frames = [];
      var frameOffsets = []; // elements have .x and .y properties
      var gif = options.gif;
      if (typeof options.auto_play == 'undefined')
          options.auto_play = (!gif.getAttribute('rel:auto_play') || gif.getAttribute('rel:auto_play') == '1');
      var onEndListener = (options.hasOwnProperty('on_end') ? options.on_end : null);
      var loopDelay = (options.hasOwnProperty('loop_delay') ? options.loop_delay : 0);
      var overrideLoopMode = (options.hasOwnProperty('loop_mode') ? options.loop_mode : 'auto');
      var drawWhileLoading = (options.hasOwnProperty('draw_while_loading') ? options.draw_while_loading : true);
      var showProgressBar = drawWhileLoading ? (options.hasOwnProperty('show_progress_bar') ? options.show_progress_bar : true) : false;
      var progressBarHeight = (options.hasOwnProperty('progressbar_height') ? options.progressbar_height : 25);
      var progressBarBackgroundColor = (options.hasOwnProperty('progressbar_background_color') ? options.progressbar_background_color : 'rgba(255,255,255,0.4)');
      var progressBarForegroundColor = (options.hasOwnProperty('progressbar_foreground_color') ? options.progressbar_foreground_color : 'rgba(255,0,22,.8)');
      var clear = function () {
          transparency = null;
          delay = null;
          lastDisposalMethod = disposalMethod;
          disposalMethod = null;
          frame = null;
      };
      // XXX: There's probably a better way to handle catching exceptions when
      // callbacks are involved.
      var doParse = function () {
          try {
              parseGIF(stream, handler);
          }
          catch (err) {
              doLoadError('parse');
          }
      };
      var doText = function (text) {
          toolbar.innerHTML = text; // innerText? Escaping? Whatever.
          toolbar.style.visibility = 'visible';
      };
      var setSizes = function (w, h) {
          canvas.width = w * get_canvas_scale();
          canvas.height = h * get_canvas_scale();
          toolbar.style.minWidth = (w * get_canvas_scale()) + 'px';
          tmpCanvas.width = w;
          tmpCanvas.height = h;
          tmpCanvas.style.width = w + 'px';
          tmpCanvas.style.height = h + 'px';
          tmpCanvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0);
      };
      var setFrameOffset = function (frame, offset) {
          if (!frameOffsets[frame]) {
              frameOffsets[frame] = offset;
              return;
          }
          if (typeof offset.x !== 'undefined') {
              frameOffsets[frame].x = offset.x;
          }
          if (typeof offset.y !== 'undefined') {
              frameOffsets[frame].y = offset.y;
          }
      };
      var doShowProgress = function (pos, length, draw) {
          if (draw && showProgressBar) {
              var height = progressBarHeight;
              var left, mid, top, width;
              if (options.is_vp) {
                  if (!ctx_scaled) {
                      top = (options.vp_t + options.vp_h - height);
                      height = height;
                      left = options.vp_l;
                      mid = left + (pos / length) * options.vp_w;
                      width = canvas.width;
                  } else {
                      top = (options.vp_t + options.vp_h - height) / get_canvas_scale();
                      height = height / get_canvas_scale();
                      left = (options.vp_l / get_canvas_scale());
                      mid = left + (pos / length) * (options.vp_w / get_canvas_scale());
                      width = canvas.width / get_canvas_scale();
                  }
                  //some debugging, draw rect around viewport
                  if (false) {
                      if (!ctx_scaled) {
                          var l = options.vp_l, t = options.vp_t;
                          var w = options.vp_w, h = options.vp_h;
                      } else {
                          var l = options.vp_l / get_canvas_scale(), t = options.vp_t / get_canvas_scale();
                          var w = options.vp_w / get_canvas_scale(), h = options.vp_h / get_canvas_scale();
                      }
                      ctx.rect(l, t, w, h);
                      ctx.stroke();
                  }
              }
              else {
                  top = (canvas.height - height) / (ctx_scaled ? get_canvas_scale() : 1);
                  mid = ((pos / length) * canvas.width) / (ctx_scaled ? get_canvas_scale() : 1);
                  width = canvas.width / (ctx_scaled ? get_canvas_scale() : 1);
                  height /= ctx_scaled ? get_canvas_scale() : 1;
              }
              ctx.fillStyle = progressBarBackgroundColor;
              ctx.fillRect(mid, top, width - mid, height);
              ctx.fillStyle = progressBarForegroundColor;
              ctx.fillRect(0, top, mid, height);
          }
      };
      var doLoadError = function (originOfError) {
          var drawError = function () {
              ctx.fillStyle = 'black';
              ctx.fillRect(0, 0, options.c_w ? options.c_w : hdr.width, options.c_h ? options.c_h : hdr.height);
              ctx.strokeStyle = 'red';
              ctx.lineWidth = 3;
              ctx.moveTo(0, 0);
              ctx.lineTo(options.c_w ? options.c_w : hdr.width, options.c_h ? options.c_h : hdr.height);
              ctx.moveTo(0, options.c_h ? options.c_h : hdr.height);
              ctx.lineTo(options.c_w ? options.c_w : hdr.width, 0);
              ctx.stroke();
          };
          loadError = originOfError;
          hdr = {
              width: gif.width,
              height: gif.height
          }; // Fake header.
          frames = [];
          drawError();
      };
      var doHdr = function (_hdr) {
          hdr = _hdr;
          setSizes(hdr.width, hdr.height)
      };
      var doGCE = function (gce) {
          pushFrame();
          clear();
          transparency = gce.transparencyGiven ? gce.transparencyIndex : null;
          delay = gce.delayTime;
          disposalMethod = gce.disposalMethod;
          // We don't have much to do with the rest of GCE.
      };
      var pushFrame = function () {
          if (!frame) return;
          frames.push({
              data: frame.getImageData(0, 0, hdr.width, hdr.height),
              delay: delay
          });
          frameOffsets.push({ x: 0, y: 0 });
      };
      var doImg = function (img) {
          if (!frame) frame = tmpCanvas.getContext('2d');
          var currIdx = frames.length;
          //ct = color table, gct = global color table
          var ct = img.lctFlag ? img.lct : hdr.gct; // TODO: What if neither exists?
          /*
          Disposal method indicates the way in which the graphic is to
          be treated after being displayed.
          Values :    0 - No disposal specified. The decoder is
                          not required to take any action.
                      1 - Do not dispose. The graphic is to be left
                          in place.
                      2 - Restore to background color. The area used by the
                          graphic must be restored to the background color.
                      3 - Restore to previous. The decoder is required to
                          restore the area overwritten by the graphic with
                          what was there prior to rendering the graphic.
                          Importantly, "previous" means the frame state
                          after the last disposal of method 0, 1, or 2.
          */
          if (currIdx > 0) {
              if (lastDisposalMethod === 3) {
                  // Restore to previous
                  // If we disposed every frame including first frame up to this point, then we have
                  // no composited frame to restore to. In this case, restore to background instead.
                  if (disposalRestoreFromIdx !== null) {
                      frame.putImageData(frames[disposalRestoreFromIdx].data, 0, 0);
                  } else {
                      frame.clearRect(lastImg.leftPos, lastImg.topPos, lastImg.width, lastImg.height);
                  }
              } else {
                  disposalRestoreFromIdx = currIdx - 1;
              }
              if (lastDisposalMethod === 2) {
                  // Restore to background color
                  // Browser implementations historically restore to transparent; we do the same.
                  // http://www.wizards-toolkit.org/discourse-server/viewtopic.php?f=1&t=21172#p86079
                  frame.clearRect(lastImg.leftPos, lastImg.topPos, lastImg.width, lastImg.height);
              }
          }
          // else, Undefined/Do not dispose.
          // frame contains final pixel data from the last frame; do nothing
          //Get existing pixels for img region after applying disposal method
          var imgData = frame.getImageData(img.leftPos, img.topPos, img.width, img.height);
          //apply color table colors
          img.pixels.forEach(function (pixel, i) {
              // imgData.data === [R,G,B,A,R,G,B,A,...]
              if (pixel !== transparency) {
                  imgData.data[i * 4 + 0] = ct[pixel][0];
                  imgData.data[i * 4 + 1] = ct[pixel][1];
                  imgData.data[i * 4 + 2] = ct[pixel][2];
                  imgData.data[i * 4 + 3] = 255; // Opaque.
              }
          });
          frame.putImageData(imgData, img.leftPos, img.topPos);
          if (!ctx_scaled) {
              ctx.scale(get_canvas_scale(), get_canvas_scale());
              ctx_scaled = true;
          }
          // We could use the on-page canvas directly, except that we draw a progress
          // bar for each image chunk (not just the final image).
          if (drawWhileLoading) {
              ctx.drawImage(tmpCanvas, 0, 0);
              drawWhileLoading = options.auto_play;
          }
          lastImg = img;
      };
      var player = (function () {
          var i = -1;
          var iterationCount = 0;
          var showingInfo = false;
          var pinned = false;
          /**
           * Gets the index of the frame "up next".
           * @returns {number}
           */
          var getNextFrameNo = function () {
              var delta = (forward ? 1 : -1);
              return (i + delta + frames.length) % frames.length;
          };
          var stepFrame = function (amount) { // XXX: Name is confusing.
              i = i + amount;
              putFrame();
          };
          var step = (function () {
              var stepping = false;
              var completeLoop = function () {
                  if (onEndListener !== null)
                      onEndListener(gif);
                  iterationCount++;
                  if (overrideLoopMode !== false || iterationCount < 0) {
                      doStep();
                  } else {
                      stepping = false;
                      playing = false;
                  }
              };
              var doStep = function () {
                  stepping = playing;
                  if (!stepping) return;
                  stepFrame(1);
                  var delay = frames[i].delay * 10;
                  if (!delay) delay = 100; // FIXME: Should this even default at all? What should it be?
                  var nextFrameNo = getNextFrameNo();
                  if (nextFrameNo === 0) {
                      delay += loopDelay;
                      setTimeout(completeLoop, delay);
                  } else {
                      setTimeout(doStep, delay);
                  }
              };
              return function () {
                  if (!stepping) setTimeout(doStep, 0);
              };
          }());
          var putFrame = function () {
              var offset;
              i = parseInt(i, 10);
              if (i > frames.length - 1) {
                  i = 0;
              }
              if (i < 0) {
                  i = 0;
              }
              offset = frameOffsets[i];
              tmpCanvas.getContext("2d").putImageData(frames[i].data, offset.x, offset.y);
              ctx.globalCompositeOperation = "copy";
              ctx.drawImage(tmpCanvas, 0, 0);
          };
          var play = function () {
              playing = true;
              step();
          };
          var pause = function () {
              playing = false;
          };
          return {
              init: function () {
                  if (loadError) return;
                  if (!(options.c_w && options.c_h)) {
                      ctx.scale(get_canvas_scale(), get_canvas_scale());
                  }
                  if (options.auto_play) {
                      step();
                  }
                  else {
                      i = 0;
                      putFrame();
                  }
              },
              step: step,
              play: play,
              pause: pause,
              playing: playing,
              move_relative: stepFrame,
              current_frame: function () { return i; },
              length: function () { return frames.length },
              move_to: function (frame_idx) {
                  i = frame_idx;
                  putFrame();
              }
          }
      }());
      var doDecodeProgress = function (draw) {
          doShowProgress(stream.pos, stream.data.length, draw);
      };
      var doNothing = function () { };
      /**
       * @param{boolean=} draw Whether to draw progress bar or not; this is not idempotent because of translucency.
       *                       Note that this means that the text will be unsynchronized with the progress bar on non-frames;
       *                       but those are typically so small (GCE etc.) that it doesn't really matter. TODO: Do this properly.
       */
      var withProgress = function (fn, draw) {
          return function (block) {
              fn(block);
              doDecodeProgress(draw);
          };
      };
      var handler = {
          hdr: withProgress(doHdr),
          gce: withProgress(doGCE),
          com: withProgress(doNothing),
          // I guess that's all for now.
          app: {
              // TODO: Is there much point in actually supporting iterations?
              NETSCAPE: withProgress(doNothing)
          },
          img: withProgress(doImg, true),
          eof: function (block) {
              //toolbar.style.display = '';
              pushFrame();
              doDecodeProgress(false);
              if (!(options.c_w && options.c_h)) {
                  canvas.width = hdr.width * get_canvas_scale();
                  canvas.height = hdr.height * get_canvas_scale();
              }
              player.init();
              loading = false;
              if (load_callback) {
                  load_callback(gif);
              }
          }
      };
      var init = function () {
          var parent = gif.parentNode;
          var div = document.createElement('div');
          canvas = document.createElement('canvas');
          ctx = canvas.getContext('2d');
          toolbar = document.createElement('div');
          tmpCanvas = document.createElement('canvas');
          div.width = canvas.width = gif.width;
          div.height = canvas.height = gif.height;
          toolbar.style.minWidth = gif.width + 'px';
          div.className = 'jsgif';
          toolbar.className = 'jsgif_toolbar';
          div.appendChild(canvas);
          div.appendChild(toolbar);
          parent.insertBefore(div, gif);
          parent.removeChild(gif);
          if (options.c_w && options.c_h) setSizes(options.c_w, options.c_h);
          initialized = true;
      };
      var get_canvas_scale = function () {
          var scale;
          if (options.max_width && hdr && hdr.width > options.max_width) {
              scale = options.max_width / hdr.width;
          }
          else {
              scale = 1;
          }
          return scale;
      }
      var canvas, ctx, toolbar, tmpCanvas;
      var initialized = false;
      var load_callback = false;
      var load_setup = function (callback) {
          if (loading) return false;
          if (callback) load_callback = callback;
          else load_callback = false;
          loading = true;
          frames = [];
          clear();
          disposalRestoreFromIdx = null;
          lastDisposalMethod = null;
          frame = null;
          lastImg = null;
          return true;
      }
      return {
          // play controls
          play: player.play,
          pause: player.pause,
          move_relative: player.move_relative,
          move_to: player.move_to,
          // getters for instance vars
          get_playing: function () { return playing },
          get_canvas: function () { return canvas },
          get_canvas_scale: function () { return get_canvas_scale() },
          get_loading: function () { return loading },
          get_auto_play: function () { return options.auto_play },
          get_length: function () { return player.length() },
          get_current_frame: function () { return player.current_frame() },
          load_url: function (src, callback) {
              if (!load_setup(callback)) return;
              var h = new XMLHttpRequest();
              // new browsers (XMLHttpRequest2-compliant)
              h.open('GET', src, true);
              if ('overrideMimeType' in h) {
                  h.overrideMimeType('text/plain; charset=x-user-defined');
              }
              // old browsers (XMLHttpRequest-compliant)
              else if ('responseType' in h) {
                  h.responseType = 'arraybuffer';
              }
              // IE9 (Microsoft.XMLHTTP-compliant)
              else {
                  h.setRequestHeader('Accept-Charset', 'x-user-defined');
              }
              h.onloadstart = function () {
                  // Wait until connection is opened to replace the gif element with a canvas to avoid a blank img
                  if (!initialized) init();
              };
              h.onload = function (e) {
                  if (this.status != 200) {
                      doLoadError('xhr - response');
                  }
                  // emulating response field for IE9
                  if (!('response' in this)) {
                      this.response = new VBArray(this.responseText).toArray().map(String.fromCharCode).join('');
                  }
                  var data = this.response;
                  if (data.toString().indexOf("ArrayBuffer") > 0) {
                      data = new Uint8Array(data);
                  }
                  stream = new Stream(data);
                  setTimeout(doParse, 0);
              };
              h.onprogress = function (e) {
                  if (e.lengthComputable) doShowProgress(e.loaded, e.total, true);
              };
              h.onerror = function () { doLoadError('xhr'); };
              h.send();
          },
          load: function (callback) {
              this.load_url(gif.getAttribute('rel:animated_src') || gif.src, callback);
          },
          load_raw: function (arr, callback) {
              if (!load_setup(callback)) return;
              if (!initialized) init();
              stream = new Stream(arr);
              setTimeout(doParse, 0);
          },
          set_frame_offset: setFrameOffset
      };
  };
  return SuperGif;
}));
src/utils/public.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
const jm = require("./aes.js");
//  ç¡¬ä»¶æ–¹æä¾›çš„key,开发文档会说明的
var key = "d4acfcad77843a0ba17fe906c65255c6";
// åР坆
function encryptionData(data) {
  var byteKey = jm.CryptoJS.enc.Hex.parse(key);
  var byteData = jm.CryptoJS.enc.Hex.parse(data);
  var encrypt = jm.CryptoJS.AES.encrypt(byteData, byteKey, { mode: jm.CryptoJS.mode.ECB, padding: jm.CryptoJS.pad.NoPadding });
  var encryptedStr = encrypt.ciphertext.toString();
  return encryptedStr;
}
//解密
function decryptData(data) {
  var byteKey = jm.CryptoJS.enc.Hex.parse(key);
  var byteData = jm.CryptoJS.enc.Hex.parse(data);
  byteData = jm.CryptoJS.enc.Base64.stringify(byteData);
  var decrypt = jm.CryptoJS.AES.decrypt(byteData, byteKey, { mode: jm.CryptoJS.mode.ECB, padding: jm.CryptoJS.pad.NoPadding });
  var decryptedStr = decrypt.toString(jm.CryptoJS.enc.Hex);
  return decryptedStr.toString();
}
module.exports = {
  decryptData, //  è§£å¯†
  encryptionData, //  åР坆
}
src/views/demo/form/index.vue
@@ -47,35 +47,35 @@
  </PageWrapper>
</template>
<script lang="ts">
  import { computed, defineComponent, unref, ref } from 'vue';
  import { BasicForm, FormSchema, ApiSelect, JAreaLinkage } from '/@/components/Form/index';
  import { CollapseContainer } from '/@/components/Container';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { PageWrapper } from '/@/components/Page';
    import { computed, defineComponent, unref, ref } from 'vue'
    import { BasicForm, FormSchema, ApiSelect, JAreaLinkage } from '/@/components/Form/index'
    import { CollapseContainer } from '/@/components/Container'
    import { useMessage } from '/@/hooks/web/useMessage'
    import { PageWrapper } from '/@/components/Page'
  import { optionsListApi } from '/@/api/demo/select';
  import { useDebounceFn } from '@vueuse/core';
  import { treeOptionsListApi } from '/@/api/demo/tree';
  import { Select } from 'ant-design-vue';
  import { cloneDeep } from 'lodash-es';
    import { optionsListApi } from '/@/api/demo/select'
    import { useDebounceFn } from '@vueuse/core'
    import { treeOptionsListApi } from '/@/api/demo/tree'
    import { Select } from 'ant-design-vue'
    import { cloneDeep } from 'lodash-es'
  const valueSelectA = ref<string[]>([]);
  const valueSelectB = ref<string[]>([]);
  const options = ref<Recordable[]>([]);
  for (let i = 1; i < 10; i++) options.value.push({ label: '选项' + i, value: `${i}` });
    const valueSelectA = ref<string[]>([])
    const valueSelectB = ref<string[]>([])
    const options = ref<Recordable[]>([])
    for (let i = 1; i < 10; i++) options.value.push({ label: '选项' + i, value: `${i}` })
  const optionsA = computed(() => {
    return cloneDeep(unref(options)).map((op) => {
      op.disabled = unref(valueSelectB).indexOf(op.value) !== -1;
      return op;
    });
  });
            op.disabled = unref(valueSelectB).indexOf(op.value) !== -1
            return op
        })
    })
  const optionsB = computed(() => {
    return cloneDeep(unref(options)).map((op) => {
      op.disabled = unref(valueSelectA).indexOf(op.value) !== -1;
      return op;
    });
  });
            op.disabled = unref(valueSelectA).indexOf(op.value) !== -1
            return op
        })
    })
  const provincesOptions = [
    {
      id: 'guangdong',
@@ -89,7 +89,7 @@
      value: '2',
      key: '2',
    },
  ];
    ]
  const citiesOptionsData = {
    guangdong: [
      {
@@ -125,7 +125,7 @@
        key: '3',
      },
    ],
  };
    }
  const schemas: FormSchema[] = [
    {
@@ -144,20 +144,20 @@
      // componentProps:{},
      // can func
      componentProps: ({ schema, formModel }) => {
        console.log('form:', schema);
        console.log('formModel:', formModel);
                console.log('form:', schema)
                console.log('formModel:', formModel)
        return {
          placeholder: '自定义placeholder',
          onChange: (e: any) => {
            console.log(e);
                        console.log(e)
          },
        };
                }
      },
      renderComponentContent: () => {
        return {
          prefix: () => 'pSlot',
          suffix: () => 'sSlot',
        };
                }
      },
    },
    {
@@ -170,7 +170,7 @@
      },
      componentProps: {
        onChange: (e: any) => {
          console.log(e);
                    console.log(e)
        },
      },
      suffix: '天',
@@ -350,11 +350,11 @@
        // not request untill to select
        immediate: false,
        onChange: (e) => {
          console.log('selected:', e);
                    console.log('selected:', e)
        },
        // atfer request callback
        onOptionsChange: (options) => {
          console.log('get options', options.length, options);
                    console.log('get options', options.length, options)
        },
      },
      colProps: {
@@ -474,21 +474,21 @@
          placeholder: '省份与城市联动',
          onChange: (e: any) => {
            // console.log(e)
            let citiesOptions = e == 1 ? citiesOptionsData[provincesOptions[0].id] : citiesOptionsData[provincesOptions[1].id];
                        let citiesOptions = e == 1 ? citiesOptionsData[provincesOptions[0].id] : citiesOptionsData[provincesOptions[1].id]
            // console.log(citiesOptions)
            if (e === undefined) {
              citiesOptions = [];
                            citiesOptions = []
            }
            formModel.city = undefined; //  reset city value
            const { updateSchema } = formActionType;
                        formModel.city = undefined //  reset city value
                        const { updateSchema } = formActionType
            updateSchema({
              field: 'city',
              componentProps: {
                options: citiesOptions,
              },
            });
                        })
          },
        };
                }
      },
    },
    {
@@ -573,7 +573,7 @@
        allowHalf: true,
      },
    },
  ];
    ]
  export default defineComponent({
    components: {
@@ -585,18 +585,18 @@
      ASelect: Select,
    },
    setup() {
      const check = ref(null);
      const { createMessage } = useMessage();
      const keyword = ref<string>('');
            const check = ref(null)
            const { createMessage } = useMessage()
            const keyword = ref<string>('')
      const searchParams = computed<Recordable>(() => {
        return { keyword: unref(keyword) };
      });
                return { keyword: unref(keyword) }
            })
      function onSearch(value: string) {
        keyword.value = value;
                keyword.value = value
      }
      function areaChange(value) {
        alert(value);
                alert(value)
      }
      return {
@@ -609,13 +609,13 @@
        onSearch: useDebounceFn(onSearch, 300),
        searchParams,
        handleReset: () => {
          keyword.value = '';
                    keyword.value = ''
        },
        handleSubmit: (values: any) => {
          createMessage.success('click search,values:' + JSON.stringify(values));
                    createMessage.success('click search,values:' + JSON.stringify(values))
        },
        check,
      };
            }
    },
  });
    })
</script>
src/views/demo/page/list/basic/index.vue
@@ -51,12 +51,12 @@
  </PageWrapper>
</template>
<script lang="ts">
  import { Progress, Row, Col } from 'ant-design-vue';
  import { defineComponent } from 'vue';
  import Icon from '/@/components/Icon/index';
  import { cardList } from './data';
  import { PageWrapper } from '/@/components/Page';
  import { List } from 'ant-design-vue';
    import { Progress, Row, Col } from 'ant-design-vue'
    import { defineComponent } from 'vue'
    import Icon from '/@/components/Icon/index'
    import { cardList } from './data'
    import { PageWrapper } from '/@/components/Page'
    import { List } from 'ant-design-vue'
  export default defineComponent({
    components: {
@@ -77,9 +77,9 @@
          show: true,
          pageSize: 3,
        },
      };
            }
    },
  });
    })
</script>
<style lang="less" scoped>
  .list-basic {
src/views/dry/DryEquipmentList.vue
@@ -16,7 +16,8 @@
              </a-menu-item>
            </a-menu>
          </template>
          <a-button>批量操作
                    <a-button
                        >批量操作
            <Icon icon="mdi:chevron-down" />
          </a-button>
        </a-dropdown>
@@ -35,8 +36,7 @@
      </template>
      <template #fileSlot="{ text }">
        <span v-if="!text" style="font-size: 12px; font-style: italic">无文件</span>
        <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small"
          @click="downloadFile(text)">下载</a-button>
                <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
      </template>
    </BasicTable>
    <!-- è¡¨å•区域 -->
src/views/dry/DryHerbFormulaList.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,169 @@
<template>
    <div>
        <!--引用表格-->
        <BasicTable @register="registerTable" :rowSelection="rowSelection">
            <!--插槽:table标题-->
            <template #tableTitle>
                <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> æ–°å¢ž</a-button>
                <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> å¯¼å‡º</a-button>
                <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
                <a-dropdown v-if="selectedRowKeys.length > 0">
                    <template #overlay>
                        <a-menu>
                            <a-menu-item key="1" @click="batchHandleDelete">
                                <Icon icon="ant-design:delete-outlined" />
                                åˆ é™¤
                            </a-menu-item>
                        </a-menu>
                    </template>
                    <a-button
                        >批量操作
                        <Icon icon="mdi:chevron-down" />
                    </a-button>
                </a-dropdown>
            </template>
            <!--操作栏-->
            <template #action="{ record }">
                <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
            </template>
            <!--字段回显插槽-->
            <template #htmlSlot="{ text }">
                <div v-html="text"></div>
            </template>
            <!--省市区字段回显插槽-->
            <template #pcaSlot="{ text }">
                {{ getAreaTextByCode(text) }}
            </template>
            <template #fileSlot="{ text }">
                <span v-if="!text" style="font-size: 12px; font-style: italic">无文件</span>
                <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
            </template>
        </BasicTable>
        <!-- è¡¨å•区域 -->
        <DryHerbFormulaModal @register="registerModal" @success="handleSuccess" />
    </div>
</template>
<script lang="ts" name="dry-dryHerbFormula" setup>
    import { ref, computed, unref } from 'vue'
    import { BasicTable, useTable, TableAction } from '/@/components/Table'
    import { useModal } from '/@/components/Modal'
    import { useListPage } from '/@/hooks/system/useListPage'
    import DryHerbFormulaModal from './components/DryHerbFormulaModal.vue'
    import { columns, searchFormSchema } from './dataDefine/DryHerbFormula.data'
    import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './api/DryHerbFormula.api'
    import { downloadFile } from '/@/utils/common/renderUtils'
    const checkedKeys = ref<Array<string | number>>([])
    //注册model
    const [registerModal, { openModal }] = useModal()
    //注册table数据
    const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
        tableProps: {
            title: '干燥配方',
            api: list,
            columns,
            canResize: false,
            formConfig: {
                //labelWidth: 120,
                schemas: searchFormSchema,
                autoSubmitOnEnter: true,
                showAdvancedButton: true,
                fieldMapToNumber: [],
                fieldMapToTime: [],
            },
            actionColumn: {
                width: 120,
                fixed: 'right',
            },
        },
        exportConfig: {
            name: '干燥配方',
            url: getExportUrl,
        },
        importConfig: {
            url: getImportUrl,
            success: handleSuccess,
        },
    })
    const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext
    /**
     * æ–°å¢žäº‹ä»¶
     */
    function handleAdd() {
        openModal(true, {
            isUpdate: false,
            showFooter: true,
        })
    }
    /**
     * ç¼–辑事件
     */
    function handleEdit(record: Recordable) {
        openModal(true, {
            record,
            isUpdate: true,
            showFooter: true,
        })
    }
    /**
     * è¯¦æƒ…
     */
    function handleDetail(record: Recordable) {
        openModal(true, {
            record,
            isUpdate: true,
            showFooter: false,
        })
    }
    /**
     * åˆ é™¤äº‹ä»¶
     */
    async function handleDelete(record) {
        await deleteOne({ id: record.id }, handleSuccess)
    }
    /**
     * æ‰¹é‡åˆ é™¤äº‹ä»¶
     */
    async function batchHandleDelete() {
        await batchDelete({ ids: selectedRowKeys.value }, handleSuccess)
    }
    /**
     * æˆåŠŸå›žè°ƒ
     */
    function handleSuccess() {
        ;(selectedRowKeys.value = []) && reload()
    }
    /**
     * æ“ä½œæ 
     */
    function getTableAction(record) {
        return [
            {
                label: '编辑',
                onClick: handleEdit.bind(null, record),
            },
        ]
    }
    /**
     * ä¸‹æ‹‰æ“ä½œæ 
     */
    function getDropDownAction(record) {
        return [
            {
                label: '详情',
                onClick: handleDetail.bind(null, record),
            },
            {
                label: '删除',
                popConfirm: {
                    title: '是否确认删除',
                    confirm: handleDelete.bind(null, record),
                },
            },
        ]
    }
</script>
<style scoped></style>
src/views/dry/DryHerbList.vue
@@ -45,17 +45,17 @@
</template>
<script lang="ts" name="dry-dryHerb" setup>
  import { ref } from 'vue';
  import DryHerbModal from './components/DryHerbModal.vue';
  import { batchDelete, deleteOne, getExportUrl, getImportUrl, list } from './api/DryHerb.api';
  import { columns, searchFormSchema } from './dataDefine/DryHerb.data';
  import { useModal } from '/@/components/Modal';
  import { BasicTable, TableAction } from '/@/components/Table';
  import { useListPage } from '/@/hooks/system/useListPage';
  import { downloadFile } from '/@/utils/common/renderUtils';
  const checkedKeys = ref<Array<string | number>>([]);
    import { ref } from 'vue'
    import DryHerbModal from './components/DryHerbModal.vue'
    import { batchDelete, deleteOne, getExportUrl, getImportUrl, list } from './api/DryHerb.api'
    import { columns, searchFormSchema } from './dataDefine/DryHerb.data'
    import { useModal } from '/@/components/Modal'
    import { BasicTable, TableAction } from '/@/components/Table'
    import { useListPage } from '/@/hooks/system/useListPage'
    import { downloadFile } from '/@/utils/common/renderUtils'
    const checkedKeys = ref<Array<string | number>>([])
  //注册model
  const [registerModal, { openModal }] = useModal();
    const [registerModal, { openModal }] = useModal()
  //注册table数据
  const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
    tableProps: {
@@ -84,9 +84,9 @@
      url: getImportUrl,
      success: handleSuccess,
    },
  });
    })
  const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
    const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext
  /**
   * æ–°å¢žäº‹ä»¶
@@ -95,7 +95,7 @@
    openModal(true, {
      isUpdate: false,
      showFooter: true,
    });
        })
  }
  /**
   * ç¼–辑事件
@@ -105,7 +105,7 @@
      record,
      isUpdate: true,
      showFooter: true,
    });
        })
  }
  /**
   * è¯¦æƒ…
@@ -115,25 +115,25 @@
      record,
      isUpdate: true,
      showFooter: false,
    });
        })
  }
  /**
   * åˆ é™¤äº‹ä»¶
   */
  async function handleDelete(record) {
    await deleteOne({ id: record.id }, handleSuccess);
        await deleteOne({ id: record.id }, handleSuccess)
  }
  /**
   * æ‰¹é‡åˆ é™¤äº‹ä»¶
   */
  async function batchHandleDelete() {
    await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
        await batchDelete({ ids: selectedRowKeys.value }, handleSuccess)
  }
  /**
   * æˆåŠŸå›žè°ƒ
   */
  function handleSuccess() {
    (selectedRowKeys.value = []) && reload();
        ;(selectedRowKeys.value = []) && reload()
  }
  /**
   * æ“ä½œæ 
@@ -144,7 +144,7 @@
        label: '编辑',
        onClick: handleEdit.bind(null, record),
      },
    ];
        ]
  }
  /**
   * ä¸‹æ‹‰æ“ä½œæ 
@@ -162,7 +162,7 @@
          confirm: handleDelete.bind(null, record),
        },
      },
    ];
        ]
  }
</script>
src/views/dry/DryHerbTypeList.vue
@@ -1,8 +1,13 @@
<template>
  <div>
    <!--引用表格-->
    <BasicTable @register="registerTable" :rowSelection="rowSelection" :expandedRowKeys="expandedRowKeys"
      @expand="handleExpand" @fetch-success="onFetchSuccess">
        <BasicTable
            @register="registerTable"
            :rowSelection="rowSelection"
            :expandedRowKeys="expandedRowKeys"
            @expand="handleExpand"
            @fetch-success="onFetchSuccess"
        >
      <!--插槽:table标题-->
      <template #tableTitle>
        <a-button type="primary" @click="handleCreate" preIcon="ant-design:plus-outlined"> æ–°å¢ž</a-button>
@@ -18,7 +23,8 @@
              </a-menu-item>
            </a-menu>
          </template>
          <a-button>批量操作
                    <a-button
                        >批量操作
            <Icon icon="ant-design:down-outlined" />
          </a-button>
        </a-dropdown>
@@ -37,8 +43,7 @@
      </template>
      <template #fileSlot="{ text }">
        <span v-if="!text" style="font-size: 12px; font-style: italic">无文件</span>
        <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small"
          @click="downloadFile(text)">下载</a-button>
                <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
      </template>
    </BasicTable>
    <!--字典弹窗-->
src/views/dry/DryOrderList.vue
@@ -16,7 +16,8 @@
              </a-menu-item>
            </a-menu>
          </template>
          <a-button>批量操作
                    <a-button
                        >批量操作
            <Icon icon="mdi:chevron-down" />
          </a-button>
        </a-dropdown>
@@ -35,8 +36,7 @@
      </template>
      <template #fileSlot="{ text }">
        <span v-if="!text" style="font-size: 12px; font-style: italic">无文件</span>
        <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small"
          @click="downloadFile(text)">下载</a-button>
                <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
      </template>
    </BasicTable>
    <!-- è¡¨å•区域 -->
src/views/dry/DryOrderTrendList.vue
@@ -16,7 +16,8 @@
              </a-menu-item>
            </a-menu>
          </template>
          <a-button>批量操作
                    <a-button
                        >批量操作
            <Icon icon="mdi:chevron-down" />
          </a-button>
        </a-dropdown>
@@ -35,8 +36,7 @@
      </template>
      <template #fileSlot="{ text }">
        <span v-if="!text" style="font-size: 12px; font-style: italic">无文件</span>
        <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small"
          @click="downloadFile(text)">下载</a-button>
                <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
      </template>
    </BasicTable>
    <!-- è¡¨å•区域 -->
src/views/dry/api/DryEquipment.api.ts
@@ -5,6 +5,7 @@
enum Api {
  list = '/dry/dryEquipment/list',
    listAll = '/dry/dryEquipment/listAll',
  save = '/dry/dryEquipment/add',
  edit = '/dry/dryEquipment/edit',
  deleteOne = '/dry/dryEquipment/delete',
@@ -28,6 +29,12 @@
export const list = (params) => defHttp.get({ url: Api.list, params })
/**
 * æ‰€æœ‰æœºå°
 * @param params
 */
export const listAll = (params) => defHttp.get({ url: Api.listAll, params })
/**
 * åˆ é™¤å•个
 */
export const deleteOne = (params, handleSuccess) => {
src/views/dry/api/DryHerbFormula.api.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,64 @@
import {defHttp} from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
  list = '/dry/dryHerbFormula/list',
  save='/dry/dryHerbFormula/add',
  edit='/dry/dryHerbFormula/edit',
  deleteOne = '/dry/dryHerbFormula/delete',
  deleteBatch = '/dry/dryHerbFormula/deleteBatch',
  importExcel = '/dry/dryHerbFormula/importExcel',
  exportXls = '/dry/dryHerbFormula/exportXls',
}
/**
 * å¯¼å‡ºapi
 * @param params
 */
export const getExportUrl = Api.exportXls;
/**
 * å¯¼å…¥api
 */
export const getImportUrl = Api.importExcel;
/**
 * åˆ—表接口
 * @param params
 */
export const list = (params) =>
  defHttp.get({url: Api.list, params});
/**
 * åˆ é™¤å•个
 */
export const deleteOne = (params,handleSuccess) => {
  return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
    handleSuccess();
  });
}
/**
 * æ‰¹é‡åˆ é™¤
 * @param params
 */
export const batchDelete = (params, handleSuccess) => {
  createConfirm({
    iconType: 'warning',
    title: '确认删除',
    content: '是否删除选中数据',
    okText: '确认',
    cancelText: '取消',
    onOk: () => {
      return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
        handleSuccess();
      });
    }
  });
}
/**
 * ä¿å­˜æˆ–者更新
 * @param params
 */
export const saveOrUpdate = (params, isUpdate) => {
  let url = isUpdate ? Api.edit : Api.save;
  return defHttp.post({url: url, params});
}
src/views/dry/components/DryEquipmentForm.vue
@@ -8,12 +8,12 @@
</template>
<script lang="ts">
  import { computed, defineComponent } from 'vue';
import { saveOrUpdate } from '../api/DryEquipment.api';
import { getBpmFormSchema } from '../dataDefine/DryEquipment.data';
import { BasicForm, useForm } from '/@/components/Form/index';
import { defHttp } from '/@/utils/http/axios';
import { propTypes } from '/@/utils/propTypes';
    import { computed, defineComponent } from 'vue'
    import { saveOrUpdate } from '../api/DryEquipment.api'
    import { getBpmFormSchema } from '../dataDefine/DryEquipment.data'
    import { BasicForm, useForm } from '/@/components/Form/index'
    import { defHttp } from '/@/utils/http/axios'
    import { propTypes } from '/@/utils/propTypes'
  export default defineComponent({
    name: 'DryEquipmentForm',
@@ -30,41 +30,41 @@
        schemas: getBpmFormSchema(props.formData),
        showActionButtonGroup: false,
        baseColProps: { span: 24 },
      });
            })
      const formDisabled = computed(() => {
        if (props.formData.disabled === false) {
          return false;
                    return false
        }
        return true;
      });
                return true
            })
      let formData = {};
      const queryByIdUrl = '/dry/dryEquipment/queryById';
            let formData = {}
            const queryByIdUrl = '/dry/dryEquipment/queryById'
      async function initFormData() {
        let params = { id: props.formData.dataId };
        const data = await defHttp.get({ url: queryByIdUrl, params });
        formData = { ...data };
                let params = { id: props.formData.dataId }
                const data = await defHttp.get({ url: queryByIdUrl, params })
                formData = { ...data }
        //设置表单的值
        await setFieldsValue(formData);
                await setFieldsValue(formData)
        //默认是禁用
        await setProps({ disabled: formDisabled.value });
                await setProps({ disabled: formDisabled.value })
      }
      async function submitForm() {
        let data = getFieldsValue();
        let params = Object.assign({}, formData, data);
        console.log('表单数据', params);
        await saveOrUpdate(params, true);
                let data = getFieldsValue()
                let params = Object.assign({}, formData, data)
                console.log('表单数据', params)
                await saveOrUpdate(params, true)
      }
      initFormData();
            initFormData()
      return {
        registerForm,
        formDisabled,
        submitForm,
      };
            }
    },
  });
    })
</script>
src/views/dry/components/DryEquipmentModal.vue
@@ -5,51 +5,51 @@
</template>
<script lang="ts" setup>
    import {ref, computed, unref} from 'vue';
    import {BasicModal, useModalInner} from '/@/components/Modal';
    import {BasicForm, useForm} from '/@/components/Form/index';
    import {formSchema} from '../dataDefine/DryEquipment.data';
    import {saveOrUpdate} from '../api/DryEquipment.api';
    import { ref, computed, unref } from 'vue'
    import { BasicModal, useModalInner } from '/@/components/Modal'
    import { BasicForm, useForm } from '/@/components/Form/index'
    import { formSchema } from '../dataDefine/DryEquipment.data'
    import { saveOrUpdate } from '../api/DryEquipment.api'
    // Emits声明
    const emit = defineEmits(['register','success']);
    const isUpdate = ref(true);
    const emit = defineEmits(['register', 'success'])
    const isUpdate = ref(true)
    //表单配置
    const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
        //labelWidth: 150,
        schemas: formSchema,
        showActionButtonGroup: false,
        baseColProps: {span: 24}
    });
        baseColProps: { span: 24 },
    })
    //表单赋值
    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
        //重置表单
        await resetFields();
        setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
        isUpdate.value = !!data?.isUpdate;
        await resetFields()
        setModalProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter })
        isUpdate.value = !!data?.isUpdate
        if (unref(isUpdate)) {
            //表单赋值
            await setFieldsValue({
                ...data.record,
            });
            })
        }
        // éšè—åº•部时禁用整个表单
       setProps({ disabled: !data?.showFooter })
    });
    })
    //设置标题
    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'))
    //表单提交事件
    async function handleSubmit(v) {
        try {
            let values = await validate();
            setModalProps({confirmLoading: true});
            let values = await validate()
            setModalProps({ confirmLoading: true })
            //提交表单
            await saveOrUpdate(values, isUpdate.value);
            await saveOrUpdate(values, isUpdate.value)
            //关闭弹窗
            closeModal();
            closeModal()
            //刷新列表
            emit('success');
            emit('success')
        } finally {
            setModalProps({confirmLoading: false});
            setModalProps({ confirmLoading: false })
        }
    }
</script>
@@ -57,10 +57,10 @@
<style lang="less" scoped>
    /** æ—¶é—´å’Œæ•°å­—输入框样式 */
  :deep(.ant-input-number){
        width: 100%
        width: 100%;
    }
    :deep(.ant-calendar-picker){
        width: 100%
        width: 100%;
    }
</style>
src/views/dry/components/DryHerbForm.vue
@@ -8,12 +8,12 @@
</template>
<script lang="ts">
  import { computed, defineComponent } from 'vue';
import { saveOrUpdate } from '../api/DryHerb.api';
import { getBpmFormSchema } from '../dataDefine/DryHerb.data';
import { BasicForm, useForm } from '/@/components/Form/index';
import { defHttp } from '/@/utils/http/axios';
import { propTypes } from '/@/utils/propTypes';
    import { computed, defineComponent } from 'vue'
    import { saveOrUpdate } from '../api/DryHerb.api'
    import { getBpmFormSchema } from '../dataDefine/DryHerb.data'
    import { BasicForm, useForm } from '/@/components/Form/index'
    import { defHttp } from '/@/utils/http/axios'
    import { propTypes } from '/@/utils/propTypes'
  export default defineComponent({
    name: 'DryHerbForm',
@@ -30,41 +30,41 @@
        schemas: getBpmFormSchema(props.formData),
        showActionButtonGroup: false,
        baseColProps: { span: 24 },
      });
            })
      const formDisabled = computed(() => {
        if (props.formData.disabled === false) {
          return false;
                    return false
        }
        return true;
      });
                return true
            })
      let formData = {};
      const queryByIdUrl = '/dry/dryHerb/queryById';
            let formData = {}
            const queryByIdUrl = '/dry/dryHerb/queryById'
      async function initFormData() {
        let params = { id: props.formData.dataId };
        const data = await defHttp.get({ url: queryByIdUrl, params });
        formData = { ...data };
                let params = { id: props.formData.dataId }
                const data = await defHttp.get({ url: queryByIdUrl, params })
                formData = { ...data }
        //设置表单的值
        await setFieldsValue(formData);
                await setFieldsValue(formData)
        //默认是禁用
        await setProps({ disabled: formDisabled.value });
                await setProps({ disabled: formDisabled.value })
      }
      async function submitForm() {
        let data = getFieldsValue();
        let params = Object.assign({}, formData, data);
        console.log('表单数据', params);
        await saveOrUpdate(params, true);
                let data = getFieldsValue()
                let params = Object.assign({}, formData, data)
                console.log('表单数据', params)
                await saveOrUpdate(params, true)
      }
      initFormData();
            initFormData()
      return {
        registerForm,
        formDisabled,
        submitForm,
      };
            }
    },
  });
    })
</script>
src/views/dry/components/DryHerbFormulaForm.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,70 @@
<template>
    <div style="min-height: 400px">
        <BasicForm @register="registerForm" />
        <div style="width: 100%; text-align: center" v-if="!formDisabled">
            <a-button @click="submitForm" pre-icon="ant-design:check" type="primary">提 äº¤</a-button>
        </div>
    </div>
</template>
<script lang="ts">
    import { BasicForm, useForm } from '/@/components/Form/index'
    import { computed, defineComponent } from 'vue'
    import { defHttp } from '/@/utils/http/axios'
    import { propTypes } from '/@/utils/propTypes'
    import { getBpmFormSchema } from '../dataDefine/DryHerbFormula.data'
    import { saveOrUpdate } from '../api/DryHerbFormula.api'
    export default defineComponent({
        name: 'DryHerbFormulaForm',
        components: {
            BasicForm,
        },
        props: {
            formData: propTypes.object.def({}),
            formBpm: propTypes.bool.def(true),
        },
        setup(props) {
            const [registerForm, { setFieldsValue, setProps, getFieldsValue }] = useForm({
                labelWidth: 150,
                schemas: getBpmFormSchema(props.formData),
                showActionButtonGroup: false,
                baseColProps: { span: 24 },
            })
            const formDisabled = computed(() => {
                if (props.formData.disabled === false) {
                    return false
                }
                return true
            })
            let formData = {}
            const queryByIdUrl = '/dry/dryHerbFormula/queryById'
            async function initFormData() {
                let params = { id: props.formData.dataId }
                const data = await defHttp.get({ url: queryByIdUrl, params })
                formData = { ...data }
                //设置表单的值
                await setFieldsValue(formData)
                //默认是禁用
                await setProps({ disabled: formDisabled.value })
            }
            async function submitForm() {
                let data = getFieldsValue()
                let params = Object.assign({}, formData, data)
                console.log('表单数据', params)
                await saveOrUpdate(params, true)
            }
            initFormData()
            return {
                registerForm,
                formDisabled,
                submitForm,
            }
        },
    })
</script>
src/views/dry/components/DryHerbFormulaModal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
<template>
    <BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
        <BasicForm @register="registerForm" />
    </BasicModal>
</template>
<script lang="ts" setup>
    import { ref, computed, unref } from 'vue'
    import { BasicModal, useModalInner } from '/@/components/Modal'
    import { BasicForm, useForm } from '/@/components/Form/index'
    import { formSchema } from '../dataDefine/DryHerbFormula.data'
    import { saveOrUpdate } from '../api/DryHerbFormula.api'
    // Emits声明
    const emit = defineEmits(['register', 'success'])
    const isUpdate = ref(true)
    //表单配置
    const [registerForm, { setProps, resetFields, setFieldsValue, validate }] = useForm({
        //labelWidth: 150,
        schemas: formSchema,
        showActionButtonGroup: false,
        baseColProps: { span: 24 },
    })
    //表单赋值
    const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
        //重置表单
        await resetFields()
        setModalProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter })
        isUpdate.value = !!data?.isUpdate
        if (unref(isUpdate)) {
            //表单赋值
            await setFieldsValue({
                ...data.record,
            })
        }
        // éšè—åº•部时禁用整个表单
        setProps({ disabled: !data?.showFooter })
    })
    //设置标题
    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'))
    //表单提交事件
    async function handleSubmit(v) {
        try {
            let values = await validate()
            setModalProps({ confirmLoading: true })
            //提交表单
            await saveOrUpdate(values, isUpdate.value)
            //关闭弹窗
            closeModal()
            //刷新列表
            emit('success')
        } finally {
            setModalProps({ confirmLoading: false })
        }
    }
</script>
<style lang="less" scoped>
    /** æ—¶é—´å’Œæ•°å­—输入框样式 */
    :deep(.ant-input-number) {
        width: 100%;
    }
    :deep(.ant-calendar-picker) {
        width: 100%;
    }
</style>
src/views/dry/components/DryHerbModal.vue
@@ -5,51 +5,51 @@
</template>
<script lang="ts" setup>
  import { computed, ref, unref } from 'vue';
import { saveOrUpdate } from '../api/DryHerb.api';
import { formSchema } from '../dataDefine/DryHerb.data';
import { BasicForm, useForm } from '/@/components/Form/index';
import { BasicModal, useModalInner } from '/@/components/Modal';
    import { computed, ref, unref } from 'vue'
    import { saveOrUpdate } from '../api/DryHerb.api'
    import { formSchema } from '../dataDefine/DryHerb.data'
    import { BasicForm, useForm } from '/@/components/Form/index'
    import { BasicModal, useModalInner } from '/@/components/Modal'
  // Emits声明
  const emit = defineEmits(['register', 'success']);
  const isUpdate = ref(true);
    const emit = defineEmits(['register', 'success'])
    const isUpdate = ref(true)
  //表单配置
  const [registerForm, { setProps, resetFields, setFieldsValue, validate }] = useForm({
    //labelWidth: 150,
    schemas: formSchema,
    showActionButtonGroup: false,
    baseColProps: { span: 24 },
  });
    })
  //表单赋值
  const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
    //重置表单
    await resetFields();
    setModalProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter });
    isUpdate.value = !!data?.isUpdate;
        await resetFields()
        setModalProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter })
        isUpdate.value = !!data?.isUpdate
    if (unref(isUpdate)) {
      //表单赋值
      await setFieldsValue({
        ...data.record,
      });
            })
    }
    // éšè—åº•部时禁用整个表单
    setProps({ disabled: !data?.showFooter });
  });
        setProps({ disabled: !data?.showFooter })
    })
  //设置标题
  const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'))
  //表单提交事件
  async function handleSubmit(v) {
    try {
      let values = await validate();
      setModalProps({ confirmLoading: true });
            let values = await validate()
            setModalProps({ confirmLoading: true })
      //提交表单
      await saveOrUpdate(values, isUpdate.value);
            await saveOrUpdate(values, isUpdate.value)
      //关闭弹窗
      closeModal();
            closeModal()
      //刷新列表
      emit('success');
            emit('success')
    } finally {
      setModalProps({ confirmLoading: false });
            setModalProps({ confirmLoading: false })
    }
  }
</script>
src/views/dry/components/DryOrderForm.vue
@@ -8,12 +8,12 @@
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
import { saveOrUpdate } from '../api/DryOrder.api';
import { getBpmFormSchema } from '../dataDefine/DryOrder.data';
import { BasicForm, useForm } from '/@/components/Form/index';
import { defHttp } from '/@/utils/http/axios';
import { propTypes } from '/@/utils/propTypes';
    import { computed, defineComponent } from 'vue'
    import { saveOrUpdate } from '../api/DryOrder.api'
    import { getBpmFormSchema } from '../dataDefine/DryOrder.data'
    import { BasicForm, useForm } from '/@/components/Form/index'
    import { defHttp } from '/@/utils/http/axios'
    import { propTypes } from '/@/utils/propTypes'
export default defineComponent({
  name: 'DryOrderForm',
@@ -30,41 +30,41 @@
      schemas: getBpmFormSchema(props.formData),
      showActionButtonGroup: false,
      baseColProps: { span: 24 },
    });
            })
    const formDisabled = computed(() => {
      if (props.formData.disabled === false) {
        return false;
                    return false
      }
      return true;
    });
                return true
            })
    let formData = {};
    const queryByIdUrl = '/dry/dryOrder/queryById';
            let formData = {}
            const queryByIdUrl = '/dry/dryOrder/queryById'
    async function initFormData() {
      let params = { id: props.formData.dataId };
      const data = await defHttp.get({ url: queryByIdUrl, params });
      formData = { ...data };
                let params = { id: props.formData.dataId }
                const data = await defHttp.get({ url: queryByIdUrl, params })
                formData = { ...data }
      //设置表单的值
      await setFieldsValue(formData);
                await setFieldsValue(formData)
      //默认是禁用
      await setProps({ disabled: formDisabled.value });
                await setProps({ disabled: formDisabled.value })
    }
    async function submitForm() {
      let data = getFieldsValue();
      let params = Object.assign({}, formData, data);
      console.log('表单数据', params);
      await saveOrUpdate(params, true);
                let data = getFieldsValue()
                let params = Object.assign({}, formData, data)
                console.log('表单数据', params)
                await saveOrUpdate(params, true)
    }
    initFormData();
            initFormData()
    return {
      registerForm,
      formDisabled,
      submitForm,
    };
            }
  },
});
    })
</script>
src/views/dry/components/DryOrderModal.vue
@@ -5,51 +5,51 @@
</template>
<script lang="ts" setup>
import { computed, ref, unref } from 'vue';
import { saveOrUpdate } from '../api/DryOrder.api';
import { formSchema } from '../dataDefine/DryOrder.data';
import { BasicForm, useForm } from '/@/components/Form/index';
import { BasicModal, useModalInner } from '/@/components/Modal';
    import { computed, ref, unref } from 'vue'
    import { saveOrUpdate } from '../api/DryOrder.api'
    import { formSchema } from '../dataDefine/DryOrder.data'
    import { BasicForm, useForm } from '/@/components/Form/index'
    import { BasicModal, useModalInner } from '/@/components/Modal'
// Emits声明
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
//表单配置
    const emit = defineEmits(['register', 'success'])
    const isUpdate = ref(true)
    //searchFormSchema
const [registerForm, { setProps, resetFields, setFieldsValue, validate }] = useForm({
  //labelWidth: 150,
  schemas: formSchema,
  showActionButtonGroup: false,
  baseColProps: { span: 24 },
});
    })
//表单赋值
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
  //重置表单
  await resetFields();
  setModalProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter });
  isUpdate.value = !!data?.isUpdate;
        await resetFields()
        setModalProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter })
        isUpdate.value = !!data?.isUpdate
  if (unref(isUpdate)) {
    //表单赋值
    await setFieldsValue({
      ...data.record,
    });
            })
  }
  // éšè—åº•部时禁用整个表单
  setProps({ disabled: !data?.showFooter });
});
        setProps({ disabled: !data?.showFooter })
    })
//设置标题
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'))
//表单提交事件
async function handleSubmit(v) {
  try {
    let values = await validate();
    setModalProps({ confirmLoading: true });
            let values = await validate()
            setModalProps({ confirmLoading: true })
    //提交表单
    await saveOrUpdate(values, isUpdate.value);
            await saveOrUpdate(values, isUpdate.value)
    //关闭弹窗
    closeModal();
            closeModal()
    //刷新列表
    emit('success');
            emit('success')
  } finally {
    setModalProps({ confirmLoading: false });
            setModalProps({ confirmLoading: false })
  }
}
</script>
src/views/dry/dataDefine/DryEquipment.data.ts
@@ -1,3 +1,4 @@
import { dryOrder } from './DryOrder.data'
import { BasicColumn, FormSchema } from '/@/components/Table'
import { getTenantId } from '/@/utils/auth'
import { render } from '/@/utils/common/renderUtils'
@@ -145,3 +146,19 @@
  // é»˜è®¤å’ŒåŽŸå§‹è¡¨å•ä¿æŒä¸€è‡´ å¦‚果流程中配置了权限数据,这里需要单独处理formSchema
  return formSchema
}
export interface dryEquipment {
    id: string
    code: string
    name: string
    type: string
    remark: string
    shop_id: string
    enable: string
    create_by: string
    create_time: Date
    update_by: string
    update_time: Date
    tenant_id: number
    order: dryOrder
}
src/views/dry/dataDefine/DryHerbFormula.data.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,226 @@
import { BasicColumn, FormSchema } from '/@/components/Table'
//列表数据
export const columns: BasicColumn[] = [
    {
        title: '药材',
        align: 'center',
        dataIndex: 'herbId_dictText',
    },
    // {
    //     title: '药材名称',
    //     align: 'center',
    //     dataIndex: 'herbName',
    // },
    {
        title: '适用设备',
        align: 'center',
        dataIndex: 'eqpType_dictText',
    },
    {
        title: '目标含水率',
        align: 'center',
        dataIndex: 'target',
    },
    {
        title: '投料量',
        align: 'center',
        dataIndex: 'feed',
    },
    {
        title: '预计干燥时间',
        align: 'center',
        dataIndex: 'et',
    },
    {
        title: '热风温度',
        align: 'center',
        dataIndex: 'windTemp',
    },
    {
        title: '环境温度',
        align: 'center',
        dataIndex: 'envTemp',
    },
    {
        title: '环境湿度',
        align: 'center',
        dataIndex: 'envHum',
    },
    {
        title: '荡料延时ms',
        align: 'center',
        dataIndex: 'delay',
    },
    {
        title: '翻料次数',
        align: 'center',
        dataIndex: 'turn',
    },
    // {
    //     title: '租户id',
    //     align: 'center',
    //     dataIndex: 'tenantId',
    // },
]
//查询数据
export const searchFormSchema: FormSchema[] = [
    {
        label: '药材',
        field: 'herbId',
        component: 'JSearchSelect',
        componentProps: {
            dict: 'dry_herb,name,id',
        },
        colProps: { span: 6 },
    },
]
//表单数据
export const formSchema: FormSchema[] = [
    {
        label: '药材',
        field: 'herbId',
        component: 'JSearchSelect',
        componentProps: {
            dict: 'dry_herb,name,id',
        },
        dynamicRules: ({ model, schema }) => {
            return [{ required: true, message: '请选择药材!' }]
        },
    },
    // {
    //     label: '药材名称',
    //     field: 'herbName',
    //     component: 'Input',
    // },
    {
        label: '设备类型',
        field: 'eqpType',
        component: 'JSearchSelect',
        componentProps: {
            dict: 'dry_eqp_type,name,id',
        },
        dynamicRules: ({ model, schema }) => {
            return [{ required: true, message: '请设备设备类型!' }]
        },
    },
    {
        label: '目标含水率',
        field: 'target',
        component: 'Input',
        dynamicRules: ({ model, schema }) => {
            return [{ required: false }, { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!' }]
        },
        renderComponentContent: () => {
            return {
                suffix: () => '%',
            }
        },
    },
    {
        label: '投料量',
        field: 'feed',
        component: 'Input',
        dynamicRules: ({ model, schema }) => {
            return [{ required: false }, { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!' }]
        },
        renderComponentContent: () => {
            return {
                suffix: () => '筐',
            }
        },
    },
    {
        label: '预计干燥时间',
        field: 'et',
        component: 'Input',
        dynamicRules: ({ model, schema }) => {
            return [{ required: false }, { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!' }]
        },
        renderComponentContent: () => {
            return {
                suffix: () => '分钟',
            }
        },
    },
    {
        label: '热风温度',
        field: 'windTemp',
        component: 'Input',
        dynamicRules: ({ model, schema }) => {
            return [{ required: false }, { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!' }]
        },
        renderComponentContent: () => {
            return {
                suffix: () => '℃',
            }
        },
    },
    {
        label: '环境温度',
        field: 'envTemp',
        component: 'Input',
        dynamicRules: ({ model, schema }) => {
            return [{ required: false }, { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!' }]
        },
        renderComponentContent: () => {
            return {
                suffix: () => '℃',
            }
        },
    },
    {
        label: '环境湿度',
        field: 'envHum',
        component: 'Input',
        dynamicRules: ({ model, schema }) => {
            return [{ required: false }, { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!' }]
        },
        renderComponentContent: () => {
            return {
                suffix: () => 'rh',
            }
        },
    },
    {
        label: '荡料延时',
        field: 'delay',
        component: 'Input',
        dynamicRules: ({ model, schema }) => {
            return [{ required: false }, { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!' }]
        },
        renderComponentContent: () => {
            return {
                suffix: () => 'ms',
            }
        },
    },
    {
        label: '翻料次数',
        field: 'turn',
        component: 'Input',
        dynamicRules: ({ model, schema }) => {
            return [{ required: false }, { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!' }]
        },
        renderComponentContent: () => {
            return {
                suffix: () => '次',
            }
        },
    },
    // TODO ä¸»é”®éšè—å­—段,目前写死为ID
    {
        label: '',
        field: 'id',
        component: 'Input',
        show: false,
    },
]
/**
 * æµç¨‹è¡¨å•调用这个方法获取formSchema
 * @param param
 */
export function getBpmFormSchema(_formData): FormSchema[] {
    // é»˜è®¤å’ŒåŽŸå§‹è¡¨å•ä¿æŒä¸€è‡´ å¦‚果流程中配置了权限数据,这里需要单独处理formSchema
    return formSchema
}
src/views/dry/dataDefine/DryOrder.data.ts
@@ -134,7 +134,7 @@
        component: 'DatePicker',
    componentProps: {
      showTime: true,
      valueFormat: 'YYYY-MM-DD HH:mm:ss'
            valueFormat: 'YYYY-MM-DD HH:mm:ss',
    },
    },
    {
@@ -264,3 +264,34 @@
    // é»˜è®¤å’ŒåŽŸå§‹è¡¨å•ä¿æŒä¸€è‡´ å¦‚果流程中配置了权限数据,这里需要单独处理formSchema
    return formSchema
}
export interface dryOrder {
    id: string
    order_time: Date
    code: string
    herb_id: string
    herb_name: string
    initial: number
    target: number
    feed: number
    origin_weight: number
    et: number
    yield: number
    dry_time: number
    wind_temp: number
    env_temp: number
    env_hum: number
    delay: number
    turn: number
    remain: number
    equ_id: string
    shop_id: string
    tenant_id: string
    create_by: string
    create_time: Date
    update_by: string
    update_time: Date
    order_status: number
    operator: string
    temps: string
}
src/views/dry/monitor/WorkShop.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,513 @@
<template>
    <div class="workshop">
        <div class="eqp-row">
            <div v-for="(item, index) in eqps" :key="index">
                <div class="eqp-card">
                    <div class="eqp-content">
                        <div class="chart">
                                <div>
                                <div class="progress">
                                    <div style="">
                                        <div>加热</div>
                                        <div></div>
                                    <span class="info-text">36</span> åˆ†é’Ÿ
                                    </div>
                                    <div style=" padding: 0 10px;width: 200px;height: 40px;">
                                        <div style="padding-top: 10px">
                                                <Progress
                                                    :stroke-color="{
                                                        from: '#108ee9',
                                                        to: '#87d068',
                                                    }"
                                                    :percent="55.9"
                                                    status="active"
                                                    :show-info="false">
                                            </Progress>
                                        </div>
                                    </div>
                                    <div>
                                        <div>预计 </div>
                                        <div><span class="info-text">90</span>  åˆ†é’Ÿ
                                        </div>
                                    </div>
                            </div>
                            <div style="height:50px; text-align: left; padding-left: 25px; display: flex;">
                                <div class="herbInfo">
                                    <div>药材:<span class="info-text">当归</span></div>
                                    <div>投料:<span class="info-text">16</span> ç­</div>
                                </div>
                                <div class="herbInfo">
                                    <div>原始重量:<span class="info-text">160</span> Kg</div>
                                    <div>实时重量:<span class="info-text">70</span> Kg</div>
                                </div>
                            </div>
                        </div>
                            <div class="eqpStatus">
                                <div > <span class="info-text">运行</span>  </div>
                            </div>
                        </div>
                        <!-- <div :id="'chartDom' + item.id" class="chart"> </div> -->
                        <div class="info">
                            <div class="leftInfo">
                                <!-- <div class="herbName"> å½“å½’ </div> -->
                                <div class="eqpName">{{ item.name }}</div>
                            </div>
                            <div class="rightInfo">
                                <div style="width: 120px" >
                                    <div style="    height: 1px;
    font-size: 10px;
    text-align: center;
    margin-top: 10px;
    margin-bottom: -10px; ">初始:{{ (mois[0] * 100).toFixed(2) }}%</div>
                                    <div :id="'moisture' + item.id" style="width: 110px; height: 187px"></div>
                                    <div style="height: 1px;
    font-size: 10px;
    text-align: center;
    margin-top: -25px;">目标:{{ (mois[2] * 100).toFixed(2) }}%</div>
                                    <div style="    width: 110px;
    text-align: center;
    margin-top: 23px;">含水率</div>
                                </div>
                                <div class="tempChart"    style="pointer-events: none; cursor: none;"  :id="'tempDom' + item.id">
                                    <a-slider v-model:value="tempValue"
                                     :min="0" range :max="100" :marks="marks" vertical />
                                     <div>热风:<span class="info-text">{{ tempValue[0] }}</span> Â°C</div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>
<script setup lang="ts">
    import { onMounted, ref } from 'vue'
    import { Progress } from 'ant-design-vue'
    import * as echarts from 'echarts'
    import 'echarts-liquidfill'
    import { listAll } from '../api/DryEquipment.api'
    import { dryEquipment } from '../dataDefine/DryEquipment.data'
    const eqps = ref([] as dryEquipment[])
    const mois = ref([0.3939,0.2112,0.11])
    const tempValue = ref(<Record<number, number>>([70, 100]))
    const marks = ref<Record<number, any>>({
        0: '0°C',
        1: '',
        2: '',
        3: '',
        4: '',
        5: '',
        6: '',
        7: '',
        8: '',
        9: '',
        10: '',
        11: '',
        12: '',
        13: '',
        14: '',
        15: '',
        16: '',
        17: '',
        18: '',
        19: '',
        20: '',
        21: '',
        22: '',
        23: '',
        24: '',
        25: '25°C',
        26: '',
        27: '',
        28: '',
        29: '',
        30: '',
        31: '',
        32: '',
        33: '',
        34: '',
        35: '',
        36: '',
        37: '',
        38: '',
        39: '',
        40: '',
        41: '',
        42: '',
        43: '',
        44: '',
        45: '',
        46: '',
        47: '',
        48: '',
        49: '',
        50: '50°C',
        51: '',
        52: '',
        53: '',
        54: '',
        55: '',
        56: '',
        57: '',
        58: '',
        59: '',
        60: '',
        61: '',
        62: '',
        63: '',
        64: '',
        65: '',
        66: '',
        67: '',
        68: '',
        69: '',
        70: '',
        71: '',
        72: '',
        73: '',
        74: '',
        75: '75°C',
        76: '',
        77: '',
        78: '',
        79: '',
        80: '',
        81: '',
        82: '',
        83: '',
        84: '',
        85: '',
        86: '',
        87: '',
        88: '',
        89: '',
        90: '',
        91: '',
        92: '',
        93: '',
        94: '',
        95: '',
        96: '',
        97: '',
        98: '',
        99: '',
        100: '100°C',
    })
    function listAllEqp() {
        listAll({ enable: 'Y' })
            .then((result) => {
                console.log(`output->result`, result)
                eqps.value = result
                setTimeout(initCharts, 1000)
            })
            .catch((err) => {
                console.log(`output->err`, err)
            })
    }
    // var wetCharts: Map<string, echarts.ECharts> = new Map()
        var moistureCharts: Map<String, echarts.ECharts> = new Map()
     function initCharts() {
    //     console.log(`output->initChart`)
         eqps.value.forEach((item) => {
    //         console.log(`output->item.id`, item.id)
             let domId = 'moisture' + item.id
    //         console.log(`output->domId`, domId)
             var chartDom: HTMLElement = document.getElementById(domId) as HTMLElement
    //         console.log(`output->chartDom`, chartDom)
             let myChart = echarts.init(chartDom)
         //    var option
//              option = {
//                 grid: {
//                     left: 30,
//                     top: 15,
//                     bottom: 13,
//                     right: 45
//                 },
//   xAxis: {
//     type: 'category',
//         show: false,
//     data: ['含水率'],
//         axisLine: {
//             show: false,
//         },
//         axisTick: {
//             show: false,
//         }
//   },
//   yAxis: {
//     type: 'value',
//         axisLine: {
//             show: false,
//         },
//         min: 0,
//         max: 100,
//         axisTick: {
//             show: true,
//         },
//         splitLine: {
//             show: false
//         }
//   },
//   series: [
//     {
//       data: [20],
//       type: 'bar',
//       showBackground: true,
//       backgroundStyle: {
//         color: 'rgba(180, 180, 180, 0.2)'
//       },
//             label: {
//                 show: true,
//             },
//             barWidth: 20,
//             markLine: {
//                 symbol: 'none',
//                 data: [
//                     {symbol: 'none',
//                         xAxis:0,
//                         x:60,
//                         yAxis:60,
//                         lineStyle:{
//                             color: '#000',
//                             width:1,
//                         },
//                         label: {
//                             formatter: '初始\n'+ '{c}%'
//                         }
//                     },
//                     {symbol: 'none',
//                         xAxis:0,
//                         x:60,
//                         yAxis:11,
//                         lineStyle:{
//                             color: '#000',
//                             width:1,
//                         },
//                         label: {
//                             formatter: '目标\n'+ '{c}%'
//                         }
//                     },
//                     // {yAxis: 0},
//                     // {yAxis: 100}
//                 ]
//             }
//     },
//   ]
// };
const option = {
    series: [{
        type: 'liquidFill',
                radius: '100%',
                //waveAnimation: false,
                amplitude: 3,
        animationDuration: 5,
        //animationDurationUpdate: 0,
        data: mois.value,
                shape: 'path://M828.817,706.209C828.817,881.725,686.98,1024,512,1024c-174.98,0-316.817-142.275-316.817-317.791C195.183,530.74,512,0,512,0s316.817,530.74,316.817,706.209z',
                outline: {
            show: false
        },
                label: {
                    formatter: function(params) {
                        console.log(`output->params`,params,mois.value)
                        return ''
                        // +'初始'+(mois.value[0]*100).toFixed(2) + '%\n\n\n'
                        + (mois.value[1]*100).toFixed(2) + '%'
                        // + '\n\n\n目标'+(mois.value[2]*100).toFixed(2) + '%'
                        ;
                    },
                    fontSize: 10,
                    position: ['50%',(100-mois.value[1]*100).toFixed(2) + '%'],
                }
    }]
};
             option && myChart.setOption(option)
             moistureCharts.set(item.id, myChart)
         })
     }
    listAllEqp()
    // DOM挂载完成后渲染图表
    onMounted(() => {})
</script>
<style>
    .workshop {
    }
    .eqp-row {
        display: flex;
        flex-wrap: wrap;
    }
    .eqp-card {
        width: 566px;
        height: 400px;
        padding: 6px 6px;
    }
    .eqp-content {
        height: 100%;
        background-color: white;
        background-image: url('../../../assets/images/dry/ganzaoji-x.png');
        background-repeat: no-repeat;
        background-size: 60% 60%;
        background-position: 10px 150px;
        border-radius: 8px;
    }
    .chart {
        width: 550px;
        height: 160px;
        display: flex;
        text-align: center;
    }
    .progress {
        padding:25px 25px;
        width: 360px;
        display: flex;
    }
    .ant-progress-bg {
        height: 25px !important;
    }
    .eqpStatus {
        width:170px;
        background-position: 0 -10px;
        background-image: url('../../../assets/images/dry/ganzaoji.gif');
        background-size: 100% 100%;
        display: inline-flex;
        flex-direction: column-reverse;
        padding: 15px;
    }
    .info {
        display: flex;
    }
    .leftInfo {
        width: 335px;
        /* background: gray; */
    }
    .rightInfo {
        flex: 1;
        height: 210px;
        display: flex;
    }
    .info-text {
        font-size: 16px;
        font-weight: bold;
    }
    .herbName {
        margin-top: -10px;
        width: 180px;
        height: 35px;
        background: rgb(56, 56, 56);
        margin-left: 120px;
        text-align: center;
        color: white;
        font-size: 16px;
        font-weight: bold;
        line-height: 35px;
    }
    .eqpName {
        margin-top: 68px;
        margin-left: 174px;
        width: 95px;
        font-weight: bold;
        text-align: center;
        background-color: white;
    }
    .tempChart {
        padding-top: 10px;
        height: 150px;
        width: 100px;
    }
    .herbInfo {
    width: 160px;
    }
    .ant-slider-mark-text {
        padding-left: 15px;
        font-size: 10px;
    }
    .ant-slider-mark-text::before {
        content: '';
        display: block;
        width: 6px;
        height: 1px;
        background-color: #1890ff;
        position: absolute;
        top: 10px;
        left: 0px;
    }
    .ant-slider-rail {
        width: 6px !important;
        border-radius: 6px 6px 0 0;
        background: linear-gradient(to top, #ce0000 0%, #ce0000 40%, #ce0000 75%, rgb(160, 160, 160) 100%);
    }
    .ant-slider-track {
        background: rgb(175, 175, 175);
        height: 20px;
        width: 6px !important;
        border-radius: 6px 6px 0 0;
    }
    .ant-slider-track:hover {
    }
    .ant-slider-handle {
        display: none;
    }
    .ant-slider-dot {
        display: none;
    }
    .ant-slider-step {
        width: 10px !important;
    }
    .ant-slider-step > :first-child {
        display: block !important;
        width: 22px !important;
        height: 22px !important;
        bottom: -17px !important;
        left: -4px;
        border: none;
        background: #ce0000;
    }
</style>
src/views/dry/sql/DryHerbFormula_menu_insert.sql
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
-- æ³¨æ„ï¼šè¯¥é¡µé¢å¯¹åº”的前台目录为views/dry文件夹下
-- å¦‚果你想更改到其他目录,请修改sql中component字段对应的值
INSERT INTO sys_permission(id, parent_id, name, url, component, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_route, is_leaf, keep_alive, hidden, hide_tab, description, status, del_flag, rule_flag, create_by, create_time, update_by, update_time, internal_or_external)
VALUES ('2023051608547290510', NULL, '干燥配方', '/dry/dryHerbFormulaList', 'dry/DryHerbFormulaList', NULL, NULL, 0, NULL, '1', 0.00, 0, NULL, 1, 0, 0, 0, 0, NULL, '1', 0, 0, 'admin', '2023-05-16 08:54:51', NULL, NULL, 0);
-- æƒé™æŽ§åˆ¶sql
-- æ–°å¢ž
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2023051608547300511', '2023051608547290510', '添加干燥配方', NULL, NULL, 0, NULL, NULL, 2, 'dry:dry_herb_formula:add', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2023-05-16 08:54:51', NULL, NULL, 0, 0, '1', 0);
-- ç¼–辑
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2023051608547300512', '2023051608547290510', '编辑干燥配方', NULL, NULL, 0, NULL, NULL, 2, 'dry:dry_herb_formula:edit', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2023-05-16 08:54:51', NULL, NULL, 0, 0, '1', 0);
-- åˆ é™¤
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2023051608547300513', '2023051608547290510', '删除干燥配方', NULL, NULL, 0, NULL, NULL, 2, 'dry:dry_herb_formula:delete', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2023-05-16 08:54:51', NULL, NULL, 0, 0, '1', 0);
-- æ‰¹é‡åˆ é™¤
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2023051608547300514', '2023051608547290510', '批量删除干燥配方', NULL, NULL, 0, NULL, NULL, 2, 'dry:dry_herb_formula:deleteBatch', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2023-05-16 08:54:51', NULL, NULL, 0, 0, '1', 0);
-- å¯¼å‡ºexcel
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2023051608547300515', '2023051608547290510', '导出excel_干燥配方', NULL, NULL, 0, NULL, NULL, 2, 'dry:dry_herb_formula:exportXls', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2023-05-16 08:54:51', NULL, NULL, 0, 0, '1', 0);
-- å¯¼å…¥excel
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2023051608547300516', '2023051608547290510', '导入excel_干燥配方', NULL, NULL, 0, NULL, NULL, 2, 'dry:dry_herb_formula:importExcel', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2023-05-16 08:54:51', NULL, NULL, 0, 0, '1', 0);
src/views/system/departUser/components/DepartRoleAuthDrawer.vue
@@ -1,17 +1,31 @@
<template>
  <BasicDrawer title="部门角色权限配置"
    <BasicDrawer
        title="部门角色权限配置"
               :width="650"
               :loading="loading"
               showFooter
               okText="保存并关闭"
               @ok="onSubmit(true)"
    @close="onClose" @register="registerDrawer">
        @close="onClose"
        @register="registerDrawer"
    >
    <div>
      <a-spin :spinning="loading">
        <template v-if="treeData.length > 0">
          <BasicTree title="所拥有的部门权限" toolbar checkable :treeData="treeData" :checkedKeys="checkedKeys"
            :selectedKeys="selectedKeys" :expandedKeys="expandedKeys" :checkStrictly="checkStrictly"
            :clickRowToExpand="false" @check="onCheck" @expand="onExpand" @select="onSelect">
                    <BasicTree
                        title="所拥有的部门权限"
                        toolbar
                        checkable
                        :treeData="treeData"
                        :checkedKeys="checkedKeys"
                        :selectedKeys="selectedKeys"
                        :expandedKeys="expandedKeys"
                        :checkStrictly="checkStrictly"
                        :clickRowToExpand="false"
                        @check="onCheck"
                        @expand="onExpand"
                        @select="onSelect"
                    >
            <template #title="{ slotTitle, ruleFlag }">
              <span>{{ slotTitle }}</span>
              <Icon v-if="ruleFlag" icon="ant-design:align-left-outlined" style="margin-left: 5px; color: red" />
@@ -30,114 +44,114 @@
</template>
<script lang="ts" setup>
import { ref } from 'vue';
    import { ref } from 'vue'
import { BasicTree } from '/@/components/Tree/index';
import { BasicDrawer, useDrawer, useDrawerInner } from '/@/components/Drawer';
import { useMessage } from '/@/hooks/web/useMessage';
    import { BasicDrawer, useDrawer, useDrawerInner } from '/@/components/Drawer'
    import { BasicTree } from '/@/components/Tree/index'
    import { useMessage } from '/@/hooks/web/useMessage'
import DepartRoleDataRuleDrawer from './DepartRoleDataRuleDrawer.vue';
import { queryTreeListForDeptRole, queryDeptRolePermission, saveDeptRolePermission } from '../depart.user.api';
    import { queryDeptRolePermission, queryTreeListForDeptRole, saveDeptRolePermission } from '../depart.user.api'
    import DepartRoleDataRuleDrawer from './DepartRoleDataRuleDrawer.vue'
defineEmits(['register']);
const { createMessage } = useMessage();
const loading = ref(false);
const departId = ref('');
const roleId = ref('');
const treeData = ref<Array<any>>([]);
const checkedKeys = ref<Array<any>>([]);
const lastCheckedKeys = ref<Array<any>>([]);
const expandedKeys = ref<Array<any>>([]);
const selectedKeys = ref<Array<any>>([]);
const allTreeKeys = ref<Array<any>>([]);
const checkStrictly = ref(true);
    defineEmits(['register'])
    const { createMessage } = useMessage()
    const loading = ref(false)
    const departId = ref('')
    const roleId = ref('')
    const treeData = ref<Array<any>>([])
    const checkedKeys = ref<Array<any>>([])
    const lastCheckedKeys = ref<Array<any>>([])
    const expandedKeys = ref<Array<any>>([])
    const selectedKeys = ref<Array<any>>([])
    const allTreeKeys = ref<Array<any>>([])
    const checkStrictly = ref(true)
// æ³¨å†ŒæŠ½å±‰ç»„ä»¶
const [registerDrawer, { closeDrawer }] = useDrawerInner((data) => {
  roleId.value = data.record.id;
  departId.value = data.record.departId;
  loadData();
});
        roleId.value = data.record.id
        departId.value = data.record.departId
        loadData()
    })
// æ³¨å†Œæ•°æ®è§„则授权弹窗抽屉
const [registerDataRuleDrawer, dataRuleDrawer] = useDrawer();
    const [registerDataRuleDrawer, dataRuleDrawer] = useDrawer()
async function loadData() {
  try {
    loading.value = true;
            loading.value = true
    // ç”¨æˆ·è§’色授权功能,查询菜单权限树
    const { ids, treeList } = await queryTreeListForDeptRole({ departId: departId.value });
            const { ids, treeList } = await queryTreeListForDeptRole({ departId: departId.value })
    if (ids.length > 0) {
      allTreeKeys.value = ids;
      expandedKeys.value = ids;
      treeData.value = treeList;
                allTreeKeys.value = ids
                expandedKeys.value = ids
                treeData.value = treeList
      // æŸ¥è¯¢è§’色授权
      checkedKeys.value = await queryDeptRolePermission({ roleId: roleId.value });
      lastCheckedKeys.value = [checkedKeys.value];
                checkedKeys.value = await queryDeptRolePermission({ roleId: roleId.value })
                lastCheckedKeys.value = [checkedKeys.value]
    } else {
      reset();
                reset()
    }
  } finally {
    loading.value = false;
            loading.value = false
  }
}
// é‡ç½®é¡µé¢
function reset() {
  treeData.value = [];
  expandedKeys.value = [];
  checkedKeys.value = [];
  lastCheckedKeys.value = [];
  loading.value = false;
        treeData.value = []
        expandedKeys.value = []
        checkedKeys.value = []
        lastCheckedKeys.value = []
        loading.value = false
}
// tree勾选复选框事件
function onCheck(event) {
  if (checkStrictly.value) {
    checkedKeys.value = event.checked;
            checkedKeys.value = event.checked
  } else {
    checkedKeys.value = event;
            checkedKeys.value = event
  }
}
// tree展开事件
function onExpand($expandedKeys) {
  expandedKeys.value = $expandedKeys;
        expandedKeys.value = $expandedKeys
}
// tree选中事件
function onSelect($selectedKeys, { selectedNodes }) {
  if (selectedNodes[0]?.ruleFlag) {
    let functionId = $selectedKeys[0];
    dataRuleDrawer.openDrawer(true, { roleId, departId, functionId });
            let functionId = $selectedKeys[0]
            dataRuleDrawer.openDrawer(true, { roleId, departId, functionId })
  }
  selectedKeys.value = [];
        selectedKeys.value = []
}
function doClose() {
  reset();
  closeDrawer();
        reset()
        closeDrawer()
}
function onClose() {
  reset();
        reset()
}
async function onSubmit(exit) {
  try {
    loading.value = true;
            loading.value = true
    let params = {
      roleId: roleId.value,
      permissionIds: checkedKeys.value.join(','),
      lastpermissionIds: lastCheckedKeys.value.join(','),
    };
    await saveDeptRolePermission(params);
            }
            await saveDeptRolePermission(params)
    if (exit) {
      doClose();
                doClose()
    }
  } finally {
    loading.value = false;
            loading.value = false
    if (!exit) {
      loadData();
                loadData()
    }
  }
}
src/views/system/loginmini/MiniLogin.vue
@@ -91,7 +91,8 @@
                <div class="aui-formButton">
                  <div class="aui-flex">
                    <a-button :loading="loginLoading" class="aui-link-login aui-flex-box" type="primary" @click="loginHandleClick">
                      {{ t('sys.login.loginButton') }}</a-button>
                                            {{ t('sys.login.loginButton') }}</a-button
                                        >
                  </div>
                  <div class="aui-flex">
                    <a class="aui-linek-code aui-flex-box" @click="codeHandleClick">{{ t('sys.login.qrSignInFormTitle') }}</a>
@@ -145,101 +146,101 @@
      <MiniCodelogin ref="codeRef" @go-back="goBack" @success="handleSuccess" />
    </div>
    <!-- ç¬¬ä¸‰æ–¹ç™»å½•相关弹框 -->
    <ThirdModal ref="thirdModalRef"></ThirdModal>
        <ThirdModal ref="thirdModalRef" />
  </div>
</template>
<script lang="ts" setup name="login-mini">
  import { getCaptcha, getCodeInfo } from '/@/api/sys/user';
  import { computed, onMounted, reactive, ref, toRaw, unref } from 'vue';
  import codeImg from '/@/assets/images/checkcode.png';
  import { Rule } from '/@/components/Form';
  import { useUserStore } from '/@/store/modules/user';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { useI18n } from '/@/hooks/web/useI18n';
  import { SmsEnum } from '/@/views/sys/login/useLogin';
  import ThirdModal from '/@/views/sys/login/ThirdModal.vue';
  import MiniForgotpad from './MiniForgotpad.vue';
  import MiniRegister from './MiniRegister.vue';
  import MiniCodelogin from './MiniCodelogin.vue';
  import logoImg from '/@/assets/loginmini/icon/lanpu_logo.png';
  import adTextImg from '/@/assets/loginmini/icon/jeecg_ad_text.png';
  import { AppLocalePicker, AppDarkModeToggle } from '/@/components/Application';
  import { useLocaleStore } from '/@/store/modules/locale';
  import { useDesign } from "/@/hooks/web/useDesign";
  import { useAppInject } from "/@/hooks/web/useAppInject";
  import { GithubFilled, WechatFilled, DingtalkCircleFilled, createFromIconfontCN } from '@ant-design/icons-vue';
    import { getCaptcha, getCodeInfo } from '/@/api/sys/user'
    import { computed, onMounted, reactive, ref, toRaw, unref } from 'vue'
    import codeImg from '/@/assets/images/checkcode.png'
    import { Rule } from '/@/components/Form'
    import { useUserStore } from '/@/store/modules/user'
    import { useMessage } from '/@/hooks/web/useMessage'
    import { useI18n } from '/@/hooks/web/useI18n'
    import { SmsEnum } from '/@/views/sys/login/useLogin'
    import ThirdModal from '/@/views/sys/login/ThirdModal.vue'
    import MiniForgotpad from './MiniForgotpad.vue'
    import MiniRegister from './MiniRegister.vue'
    import MiniCodelogin from './MiniCodelogin.vue'
    import logoImg from '/@/assets/loginmini/icon/lanpu_logo.png'
    import adTextImg from '/@/assets/loginmini/icon/jeecg_ad_text.png'
    import { AppLocalePicker, AppDarkModeToggle } from '/@/components/Application'
    import { useLocaleStore } from '/@/store/modules/locale'
    import { useDesign } from '/@/hooks/web/useDesign'
    import { useAppInject } from '/@/hooks/web/useAppInject'
    import { GithubFilled, WechatFilled, DingtalkCircleFilled, createFromIconfontCN } from '@ant-design/icons-vue'
  const IconFont = createFromIconfontCN({
    scriptUrl: '//at.alicdn.com/t/font_2316098_umqusozousr.js',
  });
  const { prefixCls } = useDesign('mini-login');
  const { notification, createMessage } = useMessage();
  const userStore = useUserStore();
  const { t } = useI18n();
  const localeStore = useLocaleStore();
  const showLocale = localeStore.getShowPicker;
    })
    const { prefixCls } = useDesign('mini-login')
    const { notification, createMessage } = useMessage()
    const userStore = useUserStore()
    const { t } = useI18n()
    const localeStore = useLocaleStore()
    const showLocale = localeStore.getShowPicker
  const randCodeData = reactive<any>({
    randCodeImage: '',
    requestCodeSuccess: false,
    checkKey: null,
  });
  const rememberMe = ref<string>('0');
    })
    const rememberMe = ref<string>('0')
  //手机号登录还是账号登录
  const activeIndex = ref<string>('accountLogin');
  const type = ref<string>('login');
    const activeIndex = ref<string>('accountLogin')
    const type = ref<string>('login')
  //账号登录表单字段
  const formData = reactive<any>({
    inputCode: '',
    username: '',
    password: '',
  });
    })
  //手机登录表单字段
  const phoneFormData = reactive<any>({
    mobile: '',
    smscode: '',
  });
  const loginRef = ref();
    })
    const loginRef = ref()
  //第三方登录弹窗
  const thirdModalRef = ref();
    const thirdModalRef = ref()
  //扫码登录
  const codeRef = ref();
    const codeRef = ref()
  //是否显示获取验证码
  const showInterval = ref<boolean>(true);
    const showInterval = ref<boolean>(true)
  //60s
  const timeRuning = ref<number>(60);
    const timeRuning = ref<number>(60)
  //定时器
  const timer = ref<any>(null);
    const timer = ref<any>(null)
  //忘记密码
  const forgotRef = ref();
    const forgotRef = ref()
  //注册
  const registerRef = ref();
  const loginLoading = ref<boolean>(false);
  const { getIsMobile } = useAppInject();
    const registerRef = ref()
    const loginLoading = ref<boolean>(false)
    const { getIsMobile } = useAppInject()
  defineProps({
    sessionTimeout: {
      type: Boolean,
    },
  });
    })
  /**
   * èŽ·å–éªŒè¯ç 
   */
  function handleChangeCheckCode() {
    formData.inputCode = '';
        formData.inputCode = ''
    randCodeData.checkKey = 1629428467008;
        randCodeData.checkKey = 1629428467008
    getCodeInfo(randCodeData.checkKey).then((res) => {
      randCodeData.randCodeImage = res;
      randCodeData.requestCodeSuccess = true;
    });
            randCodeData.randCodeImage = res
            randCodeData.requestCodeSuccess = true
        })
  }
  /**
   * åˆ‡æ¢ç™»å½•方式
   */
  function loginClick(type) {
    activeIndex.value = type;
        activeIndex.value = type
  }
  /**
@@ -247,24 +248,24 @@
   */
  async function loginHandleClick() {
    if (unref(activeIndex) === 'accountLogin') {
      accountLogin();
            accountLogin()
    } else {
      //手机号登录
      phoneLogin();
            phoneLogin()
    }
  }
  async function accountLogin() {
    if (!formData.username) {
      createMessage.warn(t('sys.login.accountPlaceholder'));
      return;
            createMessage.warn(t('sys.login.accountPlaceholder'))
            return
    }
    if (!formData.password) {
      createMessage.warn(t('sys.login.passwordPlaceholder'));
      return;
            createMessage.warn(t('sys.login.passwordPlaceholder'))
            return
    }
    try {
      loginLoading.value = true;
            loginLoading.value = true
      const { userInfo } = await userStore.login(
        toRaw({
          password: formData.password,
@@ -273,23 +274,23 @@
          checkKey: randCodeData.checkKey,
          mode: 'none', //不要默认的错误提示
        })
      );
            )
      if (userInfo) {
        notification.success({
          message: t('sys.login.loginSuccessTitle'),
          description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realname}`,
          duration: 3,
        });
                })
      }
    } catch (error) {
      notification.error({
        message: t('sys.api.errorTip'),
        description: error.message || t('sys.login.networkExceptionMsg'),
        duration: 3,
      });
      handleChangeCheckCode();
            })
            handleChangeCheckCode()
    } finally {
      loginLoading.value = false;
            loginLoading.value = false
    }
  }
@@ -298,35 +299,35 @@
   */
  async function phoneLogin() {
    if (!phoneFormData.mobile) {
      createMessage.warn(t('sys.login.mobilePlaceholder'));
      return;
            createMessage.warn(t('sys.login.mobilePlaceholder'))
            return
    }
    if (!phoneFormData.smscode) {
      createMessage.warn(t('sys.login.smsPlaceholder'));
      return;
            createMessage.warn(t('sys.login.smsPlaceholder'))
            return
    }
    try {
      loginLoading.value = true;
            loginLoading.value = true
      const { userInfo }: any = await userStore.phoneLogin({
        mobile: phoneFormData.mobile,
        captcha: phoneFormData.smscode,
        mode: 'none', //不要默认的错误提示
      });
            })
      if (userInfo) {
        notification.success({
          message: t('sys.login.loginSuccessTitle'),
          description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realname}`,
          duration: 3,
        });
                })
      }
    } catch (error) {
      notification.error({
        message: t('sys.api.errorTip'),
        description: error.message || t('sys.login.networkExceptionMsg'),
        duration: 3,
      });
            })
    } finally {
      loginLoading.value = false;
            loginLoading.value = false
    }
  }
@@ -335,24 +336,24 @@
   */
  async function getLoginCode() {
    if (!phoneFormData.mobile) {
      createMessage.warn(t('sys.login.mobilePlaceholder'));
      return;
            createMessage.warn(t('sys.login.mobilePlaceholder'))
            return
    }
    const result = await getCaptcha({ mobile: phoneFormData.mobile, smsmode: SmsEnum.FORGET_PASSWORD });
        const result = await getCaptcha({ mobile: phoneFormData.mobile, smsmode: SmsEnum.FORGET_PASSWORD })
    if (result) {
      const TIME_COUNT = 60;
            const TIME_COUNT = 60
      if (!unref(timer)) {
        timeRuning.value = TIME_COUNT;
        showInterval.value = false;
                timeRuning.value = TIME_COUNT
                showInterval.value = false
        timer.value = setInterval(() => {
          if (unref(timeRuning) > 0 && unref(timeRuning) <= TIME_COUNT) {
            timeRuning.value = timeRuning.value - 1;
                        timeRuning.value = timeRuning.value - 1
          } else {
            showInterval.value = true;
            clearInterval(unref(timer));
            timer.value = null;
                        showInterval.value = true
                        clearInterval(unref(timer))
                        timer.value = null
          }
        }, 1000);
                }, 1000)
      }
    }
  }
@@ -362,25 +363,25 @@
   * @param type
   */
  function onThirdLogin(type) {
    thirdModalRef.value.onThirdLogin(type);
        thirdModalRef.value.onThirdLogin(type)
  }
  /**
   * å¿˜è®°å¯†ç 
   */
  function forgetHandelClick() {
    type.value = 'forgot';
        type.value = 'forgot'
    setTimeout(() => {
      forgotRef.value.initForm();
    }, 300);
            forgotRef.value.initForm()
        }, 300)
  }
  /**
   * è¿”回登录页面
   */
  function goBack() {
    activeIndex.value = 'accountLogin';
    type.value = 'login';
        activeIndex.value = 'accountLogin'
        type.value = 'login'
  }
  /**
@@ -388,37 +389,37 @@
   * @param value
   */
  function handleSuccess(value) {
    Object.assign(formData, value);
    Object.assign(phoneFormData, { mobile: "", smscode: "" });
    type.value = 'login';
    activeIndex.value = 'accountLogin';
    handleChangeCheckCode();
        Object.assign(formData, value)
        Object.assign(phoneFormData, { mobile: '', smscode: '' })
        type.value = 'login'
        activeIndex.value = 'accountLogin'
        handleChangeCheckCode()
  }
  /**
   * æ³¨å†Œ
   */
  function registerHandleClick() {
    type.value = 'register';
        type.value = 'register'
    setTimeout(() => {
      registerRef.value.initForm();
    }, 300);
            registerRef.value.initForm()
        }, 300)
  }
  /**
   * æ³¨å†Œ
   */
  function codeHandleClick() {
    type.value = 'codeLogin';
        type.value = 'codeLogin'
    setTimeout(() => {
      codeRef.value.initFrom();
    }, 300);
            codeRef.value.initFrom()
        }, 300)
  }
  onMounted(() => {
    //加载验证码
    handleChangeCheckCode();
  });
        handleChangeCheckCode()
    })
</script>
<style lang="less" scoped>
@@ -505,7 +506,9 @@
    .app-iconify {
      color: #fff !important;
    }
    .aui-inputClear input,.aui-input-line input,.aui-choice{
            .aui-inputClear input,
            .aui-input-line input,
            .aui-choice {
      color: #c9d1d9 !important;
    }
@@ -526,7 +529,8 @@
    .aui-code-line{
      border-left: none !important;
    }
    .ant-checkbox-inner,.aui-success h3{
            .ant-checkbox-inner,
            .aui-success h3 {
      border-color: #c9d1d9;
    }
  }
stylelint.config.js
@@ -19,18 +19,7 @@
    'at-rule-no-unknown': [
      true,
      {
        ignoreAtRules: [
          'tailwind',
          'apply',
          'variants',
          'responsive',
          'screen',
          'function',
          'if',
          'each',
          'include',
          'mixin',
        ],
                ignoreAtRules: ['tailwind', 'apply', 'variants', 'responsive', 'screen', 'function', 'if', 'each', 'include', 'mixin'],
      },
    ],
    'no-empty-source': null,
@@ -68,4 +57,4 @@
    ],
  },
  ignoreFiles: ['**/*.js', '**/*.jsx', '**/*.tsx', '**/*.ts'],
};
}
vite.config.ts
@@ -1,35 +1,35 @@
import type { UserConfig, ConfigEnv } from 'vite';
import pkg from './package.json';
import dayjs from 'dayjs';
import { loadEnv } from 'vite';
import { resolve } from 'path';
import { generateModifyVars } from './build/generate/generateModifyVars';
import { createProxy } from './build/vite/proxy';
import { wrapperEnv } from './build/utils';
import { createVitePlugins } from './build/vite/plugin';
import { OUTPUT_DIR } from './build/constant';
import type { UserConfig, ConfigEnv } from 'vite'
import pkg from './package.json'
import dayjs from 'dayjs'
import { loadEnv } from 'vite'
import { resolve } from 'path'
import { generateModifyVars } from './build/generate/generateModifyVars'
import { createProxy } from './build/vite/proxy'
import { wrapperEnv } from './build/utils'
import { createVitePlugins } from './build/vite/plugin'
import { OUTPUT_DIR } from './build/constant'
function pathResolve(dir: string) {
  return resolve(process.cwd(), '.', dir);
    return resolve(process.cwd(), '.', dir)
}
const { dependencies, devDependencies, name, version } = pkg;
const { dependencies, devDependencies, name, version } = pkg
const __APP_INFO__ = {
  pkg: { dependencies, devDependencies, name, version },
  lastBuildTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
};
}
export default ({ command, mode }: ConfigEnv): UserConfig => {
  const root = process.cwd();
    const root = process.cwd()
  const env = loadEnv(mode, root);
    const env = loadEnv(mode, root)
  // The boolean type read by loadEnv is a string. This function can be converted to boolean type
  const viteEnv = wrapperEnv(env);
    const viteEnv = wrapperEnv(env)
  const { VITE_PORT, VITE_PUBLIC_PATH, VITE_PROXY, VITE_DROP_CONSOLE } = viteEnv;
    const { VITE_PORT, VITE_PUBLIC_PATH, VITE_PROXY, VITE_DROP_CONSOLE } = viteEnv
  const isBuild = command === 'build';
    const isBuild = command === 'build'
  return {
    base: VITE_PUBLIC_PATH,
@@ -100,13 +100,7 @@
        target: 'es2020',
      },
      // @iconify/iconify: The dependency is dynamically and virtually loaded by @purge-icons/generated, so it needs to be specified explicitly
      include: [
        '@vue/runtime-core',
        '@vue/shared',
        '@iconify/iconify',
        'ant-design-vue/es/locale/zh_CN',
        'ant-design-vue/es/locale/en_US',
      ],
            include: ['@vue/runtime-core', '@vue/shared', '@iconify/iconify', 'ant-design-vue/es/locale/zh_CN', 'ant-design-vue/es/locale/en_US'],
    },
  };
};
    }
}
windi.config.ts
@@ -1,5 +1,5 @@
import { defineConfig } from 'vite-plugin-windicss';
import { primaryColor } from './build/config/themeConfig';
import { defineConfig } from 'vite-plugin-windicss'
import { primaryColor } from './build/config/themeConfig'
export default defineConfig({
  darkMode: 'class',
@@ -21,7 +21,7 @@
      },
    },
  },
});
})
/**
 * Used for animation when the element is displayed
@@ -29,7 +29,7 @@
 */
function createEnterPlugin(maxOutput = 8) {
  const createCss = (index: number, d = 'x') => {
    const upd = d.toUpperCase();
        const upd = d.toUpperCase()
    return {
      [`*> .enter-${d}:nth-child(${index})`]: {
        transform: `translate${upd}(50px)`,
@@ -44,15 +44,15 @@
        'animation-fill-mode': 'forwards',
        'animation-delay': `${(index * 1) / 10}s`,
      },
    };
  };
        }
    }
  const handler = ({ addBase }) => {
    const addRawCss = {};
        const addRawCss = {}
    for (let index = 1; index < maxOutput; index++) {
      Object.assign(addRawCss, {
        ...createCss(index, 'x'),
        ...createCss(index, 'y'),
      });
            })
    }
    addBase({
      ...addRawCss,
@@ -68,7 +68,7 @@
          transform: 'translateY(0)',
        },
      },
    });
  };
  return { handler };
        })
    }
    return { handler }
}
yarn.lock
¶Ô±ÈÐÂÎļþ
ÎļþÌ«´ó