Selaa lähdekoodia

运营端小程序补货员页面调试,PC端前端框架版本升级

skyline 2 viikkoa sitten
vanhempi
säilyke
6c4321d85d

+ 10 - 9
haha-admin-mp/src/api/replenisher.ts

@@ -11,11 +11,12 @@ export interface ReplenisherQuery {
 }
 
 export interface ReplenisherForm {
-  id?: number;
+  id?: string;
   name: string;
   phone?: string;
   employeeId?: string;
   status?: number;
+  wechatOpenid?: string;
 }
 
 export interface ReplenisherListResponse {
@@ -33,7 +34,7 @@ export function getReplenisherList(params: ReplenisherQuery): Promise<Replenishe
 /**
  * 获取补货员详情
  */
-export function getReplenisherById(id: number): Promise<any> {
+export function getReplenisherById(id: string): Promise<any> {
   return get(`/replenishers/${id}`);
 }
 
@@ -47,48 +48,48 @@ export function createReplenisher(data: ReplenisherForm): Promise<void> {
 /**
  * 更新补货员
  */
-export function updateReplenisher(id: number, data: Partial<ReplenisherForm>): Promise<void> {
+export function updateReplenisher(id: string, data: Partial<ReplenisherForm>): Promise<void> {
   return put(`/replenishers/${id}`, data);
 }
 
 /**
  * 切换补货员状态
  */
-export function updateReplenisherStatus(id: number, status: number): Promise<void> {
+export function updateReplenisherStatus(id: string, status: number): Promise<void> {
   return put(`/replenishers/${id}/status`, { status });
 }
 
 /**
  * 删除补货员
  */
-export function deleteReplenisher(id: number): Promise<void> {
+export function deleteReplenisher(id: string): Promise<void> {
   return del(`/replenishers/${id}`);
 }
 
 /**
  * 获取补货员已绑定的设备列表
  */
-export function getBoundDevices(id: number): Promise<string[]> {
+export function getBoundDevices(id: string): Promise<string[]> {
   return get(`/replenishers/${id}/devices`);
 }
 
 /**
  * 绑定设备
  */
-export function bindDevices(id: number, deviceIds: string[]): Promise<void> {
+export function bindDevices(id: string, deviceIds: string[]): Promise<void> {
   return post(`/replenishers/${id}/devices`, { deviceIds });
 }
 
 /**
  * 解绑设备
  */
-export function unbindDevice(replenisherId: number, deviceId: string): Promise<void> {
+export function unbindDevice(replenisherId: string, deviceId: string): Promise<void> {
   return del(`/replenishers/${replenisherId}/devices/${deviceId}`);
 }
 
 /**
  * 生成微信绑定码
  */
-export function generateBindingCode(id: number): Promise<{ bindingCode: string }> {
+export function generateBindingCode(id: string): Promise<{ bindingCode: string }> {
   return post(`/replenishers/${id}/binding-code`);
 }

+ 2 - 2
haha-admin-mp/src/pages/replenisher/bind-device.vue

@@ -88,7 +88,7 @@ import NavBar from '@/components/NavBar.vue';
 import { getBoundDevices, bindDevices, unbindDevice } from '@/api/replenisher';
 import { getEnabledShops, getShopDevices } from '@/api/shop';
 
-const replenisherId = ref<number>(0);
+const replenisherId = ref<string>('');
 const replenisherName = ref('');
 const loading = ref(true);
 const saving = ref(false);
@@ -170,7 +170,7 @@ onMounted(async () => {
   const pages = getCurrentPages();
   const page = pages[pages.length - 1];
   const options = (page as any).options || {};
-  replenisherId.value = Number(options.id) || 0;
+  replenisherId.value = options.id || '';
   replenisherName.value = decodeURIComponent(options.name || '');
 
   if (!replenisherId.value) {

+ 3 - 3
haha-admin-mp/src/pages/replenisher/form.vue

@@ -150,7 +150,7 @@ import {
 } from '@/api/replenisher';
 
 const isEdit = ref(false);
-const editId = ref<number | null>(null);
+const editId = ref<string | null>(null);
 const saving = ref(false);
 const boundDeviceCount = ref(0);
 
@@ -165,7 +165,7 @@ const form = reactive<ReplenisherForm>({
 const showCodePanel = ref(false);
 const bindingCode = ref('');
 
-const loadDetail = async (id: number) => {
+const loadDetail = async (id: string) => {
   try {
     const data = await getReplenisherById(id);
     if (data) {
@@ -286,7 +286,7 @@ onMounted(() => {
   const pages = getCurrentPages();
   const page = pages[pages.length - 1];
   const options = (page as any).options || {};
-  const id = options.id ? Number(options.id) : null;
+  const id = options.id || null;
 
   if (id) {
     isEdit.value = true;

+ 1 - 1
haha-admin-mp/src/pages/replenisher/list.vue

@@ -220,7 +220,7 @@ const handleSearch = () => {
   fetchList();
 };
 
-const goForm = (id?: number) => {
+const goForm = (id?: string) => {
   const url = id != null ? `/pages/replenisher/form?id=${id}` : '/pages/replenisher/form';
   uni.navigateTo({ url });
 };

+ 1 - 11
haha-admin-web/build/cdn.ts

@@ -4,6 +4,7 @@ import { Plugin as importToCDN } from "vite-plugin-cdn-import";
  * @description 打包时采用`cdn`模式,仅限外网使用(默认不采用,如果需要采用cdn模式,请在 .env.production 文件,将 VITE_CDN 设置成true)
  * 平台采用国内cdn:https://www.bootcdn.cn,当然你也可以选择 https://unpkg.com 或者 https://www.jsdelivr.com
  * 注意:上面提到的仅限外网使用也不是完全肯定的,如果你们公司内网部署的有相关js、css文件,也可以将下面配置对应改一下,整一套内网版cdn
+ * 注意:最新版pinia不再依赖vue-demi,但其生成的iife文件有问题,待问题修复后再将pinia加入CDN模式
  */
 export const cdn = importToCDN({
   //(prodUrl解释: name: 对应下面modules的name,version: 自动读取本地package.json中dependencies依赖中对应包的版本号,path: 对应下面modules的path,当然也可写完整路径,会替换prodUrl)
@@ -24,17 +25,6 @@ export const cdn = importToCDN({
       var: "VueI18n",
       path: "vue-i18n.runtime.global.prod.min.js"
     },
-    // 项目中没有直接安装vue-demi,但是pinia用到了,所以需要在引入pinia前引入vue-demi(https://github.com/vuejs/pinia/blob/v2/packages/pinia/package.json#L77)
-    {
-      name: "vue-demi",
-      var: "VueDemi",
-      path: "index.iife.min.js"
-    },
-    {
-      name: "pinia",
-      var: "Pinia",
-      path: "pinia.iife.min.js"
-    },
     {
       name: "element-plus",
       var: "ElementPlus",

+ 3 - 4
haha-admin-web/build/plugins.ts

@@ -1,4 +1,3 @@
-import { cdn } from "./cdn";
 import vue from "@vitejs/plugin-vue";
 import { pathResolve } from "./utils";
 import { viteBuildInfo } from "./info";
@@ -15,10 +14,10 @@ import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
 import { codeInspectorPlugin } from "code-inspector-plugin";
 import { vitePluginFakeServer } from "vite-plugin-fake-server";
 
-export function getPluginsList(
+export async function getPluginsList(
   VITE_CDN: boolean,
   VITE_COMPRESSION: ViteCompression
-): PluginOption[] {
+): Promise<PluginOption[]> {
   const lifecycle = process.env.npm_lifecycle_event;
   return [
     tailwindcss(),
@@ -65,7 +64,7 @@ export function getPluginsList(
       compiler: "vue3",
       scale: 1
     }),
-    VITE_CDN ? cdn : null,
+    VITE_CDN ? (await import("./cdn")).cdn : null,
     configCompressPlugin(VITE_COMPRESSION),
     // 线上环境删除console
     removeConsole({ external: ["src/assets/iconfont/iconfont.js"] }),

+ 0 - 1
haha-admin-web/eslint.config.js

@@ -19,7 +19,6 @@ export default defineConfig([
     ...js.configs.recommended,
     languageOptions: {
       globals: {
-        // types/index.d.ts
         RefType: "readonly",
         EmitType: "readonly",
         TargetContext: "readonly",

+ 66 - 67
haha-admin-web/package.json

@@ -4,21 +4,21 @@
   "private": true,
   "type": "module",
   "scripts": {
-    "dev": "cross-env NODE_OPTIONS=--max-old-space-size=4096 vite",
+    "dev": "NODE_OPTIONS=--max-old-space-size=4096 vite",
     "serve": "pnpm dev",
-    "build": "rimraf dist && cross-env NODE_OPTIONS=--max-old-space-size=8192 vite build && generate-version-file",
+    "build": "rimraf dist && NODE_OPTIONS=--max-old-space-size=8192 vite build && generate-version-file",
     "build:staging": "rimraf dist && vite build --mode staging",
     "report": "rimraf dist && vite build",
     "preview": "vite preview",
     "preview:build": "pnpm build && vite preview",
-    "typecheck": "tsc --noEmit && vue-tsc --noEmit --skipLibCheck",
+    "typecheck": "vue-tsc --noEmit --skipLibCheck",
     "svgo": "svgo -f . -r",
     "clean:cache": "rimraf .eslintcache && rimraf pnpm-lock.yaml && rimraf node_modules && pnpm store prune && pnpm install",
-    "lint:eslint": "eslint --cache --max-warnings 0  \"{src,mock,build}/**/*.{vue,js,ts,tsx}\" --fix",
+    "lint:eslint": "eslint --cache --max-warnings 0 src mock build --fix",
     "lint:prettier": "prettier --write  \"src/**/*.{js,ts,json,tsx,css,scss,vue,html,md}\"",
     "lint:stylelint": "stylelint --cache --fix \"**/*.{html,vue,css,scss}\" --cache-location node_modules/.cache/stylelint/",
     "lint": "pnpm lint:eslint && pnpm lint:prettier && pnpm lint:stylelint",
-    "prepare": "cd .. && husky haha-admin-web/.husky",
+    "prepare": "husky",
     "preinstall": "npx only-allow pnpm"
   },
   "keywords": [
@@ -53,29 +53,29 @@
     "@logicflow/extension": "^1.2.28",
     "@pureadmin/descriptions": "^1.2.1",
     "@pureadmin/table": "^3.3.0",
-    "@pureadmin/utils": "^2.6.3",
+    "@pureadmin/utils": "^2.6.4",
     "@vue-flow/background": "^1.3.2",
-    "@vue-flow/core": "^1.48.0",
-    "@vueuse/core": "^14.1.0",
+    "@vue-flow/core": "^1.48.2",
+    "@vueuse/core": "^14.2.1",
     "@vueuse/motion": "^3.0.3",
     "@wangeditor/editor": "^5.1.23",
     "@wangeditor/editor-for-vue": "^5.1.12",
     "@zxcvbn-ts/core": "^3.0.4",
     "animate.css": "^4.1.1",
-    "axios": "^1.13.2",
+    "axios": "1.14.0",
     "china-area-data": "^5.0.1",
-    "codemirror": "^5.65.20",
+    "codemirror": "^5.65.21",
     "codemirror-editor-vue3": "^2.8.0",
     "cropperjs": "^1.6.2",
-    "dayjs": "^1.11.19",
-    "deep-chat": "^2.3.0",
+    "dayjs": "^1.11.20",
+    "deep-chat": "^2.4.2",
     "echarts": "^6.0.0",
     "el-table-infinite-scroll": "^3.0.8",
-    "element-plus": "^2.12.0",
+    "element-plus": "^2.13.7",
     "highlight.js": "^11.11.1",
     "intro.js": "^7.2.0",
     "js-cookie": "^3.0.5",
-    "jsbarcode": "^3.12.1",
+    "jsbarcode": "^3.12.3",
     "localforage": "^1.10.0",
     "mint-filter": "^4.0.3",
     "mitt": "^3.0.1",
@@ -83,96 +83,95 @@
     "nprogress": "^0.2.0",
     "path-browserify": "^1.0.1",
     "pinia": "^3.0.4",
-    "pinyin-pro": "^3.27.0",
+    "pinyin-pro": "^3.28.1",
     "plus-pro-components": "^0.1.30",
     "qrcode": "^1.5.4",
-    "qs": "^6.14.0",
+    "qs": "^6.15.1",
     "responsive-storage": "^2.2.0",
-    "sortablejs": "^1.15.6",
-    "swiper": "^12.0.3",
+    "sortablejs": "^1.15.7",
+    "swiper": "^12.1.3",
     "typeit": "^8.8.7",
     "v-contextmenu": "^3.2.0",
-    "v3-infinite-loading": "^1.3.2",
     "vditor": "^3.11.2",
     "version-rocket": "^1.7.4",
-    "vue": "^3.5.25",
-    "vue-i18n": "^11.2.2",
+    "vue": "^3.5.33",
+    "vue-i18n": "^11.4.0",
     "vue-json-pretty": "^2.6.0",
-    "vue-pdf-embed": "^2.1.3",
-    "vue-router": "^4.6.3",
+    "vue-pdf-embed": "^2.1.4",
+    "vue-router": "^5.0.6",
     "vue-tippy": "^6.7.1",
     "vue-types": "^6.0.0",
-    "vue-virtual-scroller": "2.0.0-beta.8",
+    "vue-virtual-scroller": "2.0.0-beta.10",
     "vue-waterfall-plugin-next": "^2.6.9",
-    "vue3-danmaku": "^1.6.6",
+    "vue3-danmaku": "^1.6.7",
     "vue3-puzzle-vcode": "^1.1.7",
     "vuedraggable": "^4.1.0",
     "vxe-table": "4.6.25",
-    "wavesurfer.js": "^7.12.1",
-    "xgplayer": "^3.0.23",
+    "wavesurfer.js": "^7.12.6",
+    "xgplayer": "^3.0.24",
     "xlsx": "^0.18.5"
   },
   "devDependencies": {
-    "@commitlint/cli": "^20.2.0",
-    "@commitlint/config-conventional": "^20.2.0",
-    "@commitlint/types": "^20.2.0",
-    "@eslint/js": "^9.39.1",
-    "@faker-js/faker": "^10.1.0",
-    "@iconify/json": "^2.2.416",
+    "@commitlint/cli": "^20.5.2",
+    "@commitlint/config-conventional": "^20.5.0",
+    "@commitlint/types": "^20.5.0",
+    "@eslint/js": "^10.0.1",
+    "@faker-js/faker": "^10.4.0",
+    "@iconify/json": "^2.2.467",
     "@iconify/vue": "4.2.0",
-    "@intlify/unplugin-vue-i18n": "^11.0.1",
-    "@tailwindcss/vite": "^4.1.17",
+    "@intlify/unplugin-vue-i18n": "^11.1.2",
+    "@tailwindcss/vite": "^4.2.4",
     "@types/codemirror": "^5.60.17",
-    "@types/dagre": "^0.7.53",
+    "@types/dagre": "^0.7.54",
     "@types/intro.js": "^5.1.5",
     "@types/js-cookie": "^3.0.6",
-    "@types/node": "^20.19.26",
+    "@types/node": "^20.19.39",
     "@types/nprogress": "^0.2.3",
     "@types/path-browserify": "^1.0.3",
     "@types/qrcode": "^1.5.6",
-    "@types/qs": "^6.14.0",
+    "@types/qs": "^6.15.0",
     "@types/sortablejs": "^1.15.9",
-    "@vitejs/plugin-vue": "^6.0.2",
-    "@vitejs/plugin-vue-jsx": "^5.1.2",
+    "@vitejs/plugin-vue": "^6.0.6",
+    "@vitejs/plugin-vue-jsx": "^5.1.5",
     "boxen": "^8.0.1",
-    "code-inspector-plugin": "^1.3.0",
-    "cross-env": "^10.1.0",
-    "cssnano": "^7.1.2",
+    "code-inspector-plugin": "^1.5.1",
+    "cssnano": "^7.1.7",
     "dagre": "^0.8.5",
-    "eslint": "^9.39.1",
+    "eslint": "^10.2.1",
     "eslint-config-prettier": "^10.1.8",
-    "eslint-plugin-prettier": "^5.5.4",
-    "eslint-plugin-vue": "^10.6.2",
+    "eslint-plugin-better-tailwindcss": "^4.4.1",
+    "eslint-plugin-prettier": "^5.5.5",
+    "eslint-plugin-vue": "^10.9.0",
     "gradient-string": "^3.0.0",
     "husky": "^9.1.7",
-    "lint-staged": "^16.2.7",
-    "postcss": "^8.5.6",
-    "postcss-html": "^1.8.0",
+    "lint-staged": "^16.4.0",
+    "postcss": "^8.5.12",
+    "postcss-html": "^1.8.1",
     "postcss-load-config": "^6.0.1",
     "postcss-scss": "^4.0.9",
-    "prettier": "^3.7.4",
-    "rimraf": "^6.1.2",
-    "rollup-plugin-visualizer": "^6.0.5",
-    "sass": "^1.95.1",
-    "stylelint": "^16.26.1",
-    "stylelint-config-recess-order": "^7.4.0",
+    "prettier": "^3.8.3",
+    "rimraf": "^6.1.3",
+    "rollup-plugin-visualizer": "^6.0.11",
+    "sass": "^1.99.0",
+    "stylelint": "^17.9.1",
+    "stylelint-config-recess-order": "^7.7.0",
     "stylelint-config-recommended-vue": "^1.6.1",
-    "stylelint-config-standard-scss": "^14.0.0",
+    "stylelint-config-standard-scss": "^17.0.0",
     "stylelint-prettier": "^5.0.3",
-    "svgo": "^4.0.0",
-    "tailwindcss": "^4.1.17",
-    "typescript": "^5.9.3",
-    "typescript-eslint": "^8.49.0",
-    "unplugin-icons": "^22.5.0",
-    "vite": "^7.2.7",
+    "svgo": "^4.0.1",
+    "tailwindcss": "^4.2.4",
+    "typescript": "^6.0.3",
+    "typescript-eslint": "^8.59.1",
+    "unplugin-icons": "^23.0.1",
+    "vite": "^8.0.10",
     "vite-plugin-cdn-import": "^1.0.1",
     "vite-plugin-compression": "^0.5.1",
-    "vite-plugin-fake-server": "^2.2.2",
+    "vite-plugin-fake-server": "^2.2.3",
     "vite-plugin-remove-console": "^2.2.0",
-    "vite-plugin-router-warn": "^1.0.0",
-    "vite-svg-loader": "^5.1.0",
-    "vue-eslint-parser": "^10.2.0",
-    "vue-tsc": "^3.1.8"
+    "vite-plugin-router-warn": "^2.0.0",
+    "vite-svg-loader": "^5.1.1",
+    "vue-eslint-parser": "^10.4.0",
+    "vue-tsc": "^3.2.7"
   },
   "engines": {
     "node": "^20.19.0 || >=22.13.0",

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 369 - 228
haha-admin-web/pnpm-lock.yaml


+ 3 - 2
haha-admin-web/public/platform-config.json

@@ -1,5 +1,5 @@
 {
-  "Version": "6.3.0",
+  "Version": "7.0.0",
   "Title": "富玉餐饮管理",
   "FixedHeader": true,
   "HiddenSideBar": false,
@@ -18,7 +18,8 @@
   "SidebarStatus": true,
   "EpThemeColor": "#409EFF",
   "ShowLogo": true,
-  "ShowModel": "smart",
+  "Watermark": false,
+  "TagsStyle": "smart",
   "MenuArrowIconNoTransition": false,
   "CachingAsyncRoutes": false,
   "TooltipEffect": "light",

+ 5 - 0
haha-admin-web/src/components/RePerms/index.ts

@@ -0,0 +1,5 @@
+import perms from "./src/perms";
+
+const Perms = perms;
+
+export { Perms };

+ 20 - 0
haha-admin-web/src/components/RePerms/src/perms.tsx

@@ -0,0 +1,20 @@
+import { defineComponent, Fragment } from "vue";
+import { hasPerms } from "@/utils/auth";
+
+export default defineComponent({
+  name: "Perms",
+  props: {
+    value: {
+      type: undefined,
+      default: []
+    }
+  },
+  setup(props, { slots }) {
+    return () => {
+      if (!slots) return null;
+      return hasPerms(props.value) ? (
+        <Fragment>{slots.default?.()}</Fragment>
+      ) : null;
+    };
+  }
+});

+ 3 - 3
haha-admin-web/src/layout/components/lay-content/index.vue

@@ -13,7 +13,7 @@ const props = defineProps({
 });
 
 const { t } = useI18n();
-const { showModel } = useTags();
+const { tagsStyle } = useTags();
 const { $storage, $config } = useGlobal<GlobalPropertiesApi>();
 
 const isKeepAlive = computed(() => {
@@ -54,13 +54,13 @@ const getSectionStyle = computed(() => {
   return [
     hideTabs.value && layout ? "padding-top: 48px;" : "",
     !hideTabs.value && layout
-      ? showModel.value == "chrome"
+      ? tagsStyle.value == "chrome"
         ? "padding-top: 85px;"
         : "padding-top: 81px;"
       : "",
     hideTabs.value && !layout.value ? "padding-top: 48px;" : "",
     !hideTabs.value && !layout.value
-      ? showModel.value == "chrome"
+      ? tagsStyle.value == "chrome"
         ? "padding-top: 85px;"
         : "padding-top: 81px;"
       : "",

+ 4 - 4
haha-admin-web/src/layout/components/lay-setting/index.vue

@@ -54,7 +54,7 @@ if (unref(layoutTheme)) {
 }
 
 /** 默认灵动模式 */
-const markValue = ref($storage.configure?.showModel ?? "smart");
+const markValue = ref($storage.configure?.tagsStyle ?? "smart");
 
 const logoVal = ref($storage.configure?.showLogo ?? true);
 
@@ -63,7 +63,7 @@ const settings = reactive({
   weakVal: $storage.configure.weak,
   tabsVal: $storage.configure.hideTabs,
   showLogo: $storage.configure.showLogo,
-  showModel: $storage.configure.showModel,
+  tagsStyle: $storage.configure.tagsStyle,
   hideFooter: $storage.configure.hideFooter,
   multiTagsCache: $storage.configure.multiTagsCache,
   stretch: $storage.configure.stretch
@@ -125,8 +125,8 @@ const multiTagsCacheChange = () => {
 function onChange({ option }) {
   const { value } = option;
   markValue.value = value;
-  storageConfigureChange("showModel", value);
-  emitter.emit("tagViewsShowModel", value);
+  storageConfigureChange("tagsStyle", value);
+  emitter.emit("tagViewsTagsStyle", value);
 }
 
 /** 侧边栏Logo */

+ 9 - 9
haha-admin-web/src/layout/components/lay-tag/index.vue

@@ -36,7 +36,7 @@ const {
   tagsViews,
   buttonTop,
   buttonLeft,
-  showModel,
+  tagsStyle,
   translateX,
   isFixedTag,
   pureSetting,
@@ -542,8 +542,8 @@ onMounted(() => {
   });
 
   // 改变标签风格
-  emitter.on("tagViewsShowModel", key => {
-    showModel.value = key;
+  emitter.on("tagViewsTagsStyle", key => {
+    tagsStyle.value = key;
   });
 
   //  接收侧边栏切换传递过来的参数
@@ -559,9 +559,9 @@ onMounted(() => {
 });
 
 onBeforeUnmount(() => {
-  // 解绑`tagViewsChange`、`tagViewsShowModel`、`changLayoutRoute`公共事件,防止多次触发
+  // 解绑`tagViewsChange`、`tagViewsTagsStyle`、`changLayoutRoute`公共事件,防止多次触发
   emitter.off("tagViewsChange");
-  emitter.off("tagViewsShowModel");
+  emitter.off("tagViewsTagsStyle");
   emitter.off("changLayoutRoute");
 });
 </script>
@@ -574,7 +574,7 @@ onBeforeUnmount(() => {
     <div
       ref="scrollbarDom"
       class="scroll-container"
-      :class="showModel === 'chrome' && 'chrome-scroll-container'"
+      :class="tagsStyle === 'chrome' && 'chrome-scroll-container'"
       @wheel.prevent="handleWheel"
     >
       <div ref="tabDom" class="tab select-none" :style="getTabStyle">
@@ -585,7 +585,7 @@ onBeforeUnmount(() => {
           :class="[
             'scroll-item is-closable',
             linkIsActive(item),
-            showModel === 'chrome' && 'chrome-item',
+            tagsStyle === 'chrome' && 'chrome-item',
             isFixedTag(item) && 'fixed-tag'
           ]"
           @contextmenu.prevent="openMenu(item, $event)"
@@ -593,7 +593,7 @@ onBeforeUnmount(() => {
           @mouseleave.prevent="onMouseleave(index)"
           @click="tagOnClick(item)"
         >
-          <template v-if="showModel !== 'chrome'">
+          <template v-if="tagsStyle !== 'chrome'">
             <span
               class="tag-title dark:text-text_color_primary! dark:hover:text-primary!"
             >
@@ -612,7 +612,7 @@ onBeforeUnmount(() => {
               <IconifyIconOffline :icon="Close" />
             </span>
             <span
-              v-if="showModel !== 'card'"
+              v-if="tagsStyle !== 'card'"
               :ref="'schedule' + index"
               :class="[scheduleIsActive(item)]"
             />

+ 1 - 1
haha-admin-web/src/layout/hooks/useLayout.ts

@@ -40,7 +40,7 @@ export function useLayout() {
         hideTabs: $config?.HideTabs ?? false,
         hideFooter: $config.HideFooter ?? true,
         showLogo: $config?.ShowLogo ?? true,
-        showModel: $config?.ShowModel ?? "smart",
+        tagsStyle: $config?.TagsStyle ?? "smart",
         multiTagsCache: $config?.MultiTagsCache ?? false,
         stretch: $config?.Stretch ?? false
       };

+ 7 - 7
haha-admin-web/src/layout/hooks/useTag.ts

@@ -45,10 +45,10 @@ export function useTags() {
   const isScrolling = ref(false);
 
   /** 显示模式,默认灵动模式 */
-  const showModel = ref(
+  const tagsStyle = ref(
     storageLocal().getItem<StorageConfigs>(
       `${responsiveStorageNameSpace()}configure`
-    )?.showModel || "smart"
+    )?.tagsStyle || "smart"
   );
   /** 是否隐藏标签页,默认显示 */
   const showTags =
@@ -175,7 +175,7 @@ export function useTags() {
   /** 鼠标移入添加激活样式 */
   function onMouseenter(index) {
     if (index) activeIndex.value = index;
-    if (unref(showModel) === "smart") {
+    if (unref(tagsStyle) === "smart") {
       if (hasClass(instance.refs["schedule" + index][0], "schedule-active"))
         return;
       toggleClass(true, "schedule-in", instance.refs["schedule" + index][0]);
@@ -190,7 +190,7 @@ export function useTags() {
   /** 鼠标移出恢复默认样式 */
   function onMouseleave(index) {
     activeIndex.value = -1;
-    if (unref(showModel) === "smart") {
+    if (unref(tagsStyle) === "smart") {
       if (hasClass(instance.refs["schedule" + index][0], "schedule-active"))
         return;
       toggleClass(false, "schedule-in", instance.refs["schedule" + index][0]);
@@ -209,11 +209,11 @@ export function useTags() {
   }
 
   onMounted(() => {
-    if (!showModel.value) {
+    if (!tagsStyle.value) {
       const configure = storageLocal().getItem<StorageConfigs>(
         `${responsiveStorageNameSpace()}configure`
       );
-      configure.showModel = "card";
+      configure.tagsStyle = "card";
       storageLocal().setItem(
         `${responsiveStorageNameSpace()}configure`,
         configure
@@ -229,7 +229,7 @@ export function useTags() {
     showTags,
     instance,
     multiTags,
-    showModel,
+    tagsStyle,
     tagsViews,
     buttonTop,
     buttonLeft,

+ 2 - 0
haha-admin-web/src/main.ts

@@ -44,7 +44,9 @@ app.component("FontIcon", FontIcon);
 
 // 全局注册按钮级别权限组件
 import { Auth } from "@/components/ReAuth";
+import { Perms } from "@/components/RePerms";
 app.component("Auth", Auth);
+app.component("Perms", Perms);
 
 // 全局注册vue-tippy
 import "tippy.js/dist/tippy.css";

+ 10 - 9
haha-admin-web/src/router/index.ts

@@ -120,7 +120,7 @@ const whiteList = ["/login"];
 
 const { VITE_HIDE_HOME } = import.meta.env;
 
-router.beforeEach((to: ToRouteType, _from, next) => {
+router.beforeEach((to: ToRouteType, _from) => {
   to.meta.loaded = loadedPaths.has(to.path);
 
   if (!to.meta.loaded) {
@@ -147,24 +147,25 @@ router.beforeEach((to: ToRouteType, _from, next) => {
   }
   /** 如果已经登录并存在登录信息后不能跳转到路由白名单,而是继续保持在当前页面 */
   function toCorrectRoute() {
-    whiteList.includes(to.fullPath) ? next(_from.fullPath) : next();
+    return whiteList.includes(to.fullPath) ? _from.fullPath : undefined;
   }
   if (Cookies.get(multipleTabsKey) && userInfo) {
     // 无权限跳转403页面
     if (to.meta?.roles && !isOneOfArray(to.meta?.roles, userInfo?.roles)) {
-      next({ path: "/error/403" });
+      return { path: "/error/403" };
     }
     // 开启隐藏首页后在浏览器地址栏手动输入首页welcome路由则跳转到404页面
     if (VITE_HIDE_HOME === "true" && to.fullPath === "/welcome") {
-      next({ path: "/error/404" });
+      return { path: "/error/404" };
     }
     if (_from?.name) {
       // name为超链接
       if (externalLink) {
         openLink(to?.name as string);
         NProgress.done();
+        return false;
       } else {
-        toCorrectRoute();
+        return toCorrectRoute();
       }
     } else {
       // 刷新
@@ -204,18 +205,18 @@ router.beforeEach((to: ToRouteType, _from, next) => {
           if (isAllEmpty(to.name)) router.push(to.fullPath);
         });
       }
-      toCorrectRoute();
+      return toCorrectRoute();
     }
   } else {
     if (to.path !== "/login") {
       if (whiteList.indexOf(to.path) !== -1) {
-        next();
+        return true;
       } else {
         removeToken();
-        next({ path: "/login" });
+        return { path: "/login" };
       }
     } else {
-      next();
+      return true;
     }
   }
 });

+ 1 - 1
haha-admin-web/src/utils/mitt.ts

@@ -8,7 +8,7 @@ type Events = {
   logoChange: boolean;
   tagViewsChange: string;
   changLayoutRoute: string;
-  tagViewsShowModel: string;
+  tagViewsTagsStyle: string;
   imageInfo: {
     img: HTMLImageElement;
     height: number;

+ 1 - 1
haha-admin-web/src/utils/responsive.ts

@@ -29,7 +29,7 @@ export const injectResponsiveStorage = (app: App, config: PlatformConfigs) => {
         hideTabs: config.HideTabs ?? false,
         hideFooter: config.HideFooter ?? true,
         showLogo: config.ShowLogo ?? true,
-        showModel: config.ShowModel ?? "smart",
+        tagsStyle: config.TagsStyle ?? "smart",
         multiTagsCache: config.MultiTagsCache ?? false,
         stretch: config.Stretch ?? false
       }

+ 5 - 6
haha-admin-web/tsconfig.json

@@ -7,15 +7,13 @@
     "strictFunctionTypes": false,
     "noImplicitThis": true,
     "jsx": "preserve",
-    "importHelpers": true,
-    "experimentalDecorators": true,
+    "jsxImportSource": "vue",
     "skipLibCheck": true,
     "esModuleInterop": true,
     "isolatedModules": true,
     "allowSyntheticDefaultImports": true,
     "forceConsistentCasingInFileNames": true,
     "sourceMap": true,
-    "baseUrl": ".",
     "allowJs": false,
     "resolveJsonModule": true,
     "lib": [
@@ -24,10 +22,10 @@
     ],
     "paths": {
       "@/*": [
-        "src/*"
+        "./src/*"
       ],
       "@build/*": [
-        "build/*"
+        "./build/*"
       ]
     },
     "types": [
@@ -41,6 +39,7 @@
   },
   "include": [
     "mock/*.ts",
+    "build/*.ts",
     "src/**/*.ts",
     "src/**/*.tsx",
     "src/**/*.vue",
@@ -52,4 +51,4 @@
     "**/*.js",
     "node_modules"
   ]
-}
+}

+ 5 - 5
haha-admin-web/types/directives.d.ts

@@ -2,26 +2,26 @@ import type { Directive } from "vue";
 import type { CopyEl, OptimizeOptions, RippleOptions } from "@/directives";
 
 declare module "vue" {
-  export interface ComponentCustomProperties {
+  interface GlobalDirectives {
     /** `Loading` 动画加载指令,具体看:https://element-plus.org/zh-CN/component/loading.html#%E6%8C%87%E4%BB%A4 */
     vLoading: Directive<Element, boolean>;
     /** 按钮权限指令(根据路由`meta`中的`auths`字段进行判断)*/
-    vAuth: Directive<HTMLElement, string | Array<string>>;
+    vAuth: Directive<HTMLElement, string | string[]>;
     /** 文本复制指令(默认双击复制) */
     vCopy: Directive<CopyEl, string>;
     /** 长按指令 */
-    vLongpress: Directive<HTMLElement, Function>;
+    vLongpress: Directive<HTMLElement, () => void>;
     /** 防抖、节流指令 */
     vOptimize: Directive<HTMLElement, OptimizeOptions>;
     /** 按钮权限指令(根据登录接口返回的`permissions`字段进行判断)*/
-    vPerms: Directive<HTMLElement, string | Array<string>>;
+    vPerms: Directive<HTMLElement, string | string[]>;
     /**
      * `v-ripple`指令,用法如下:
      * 1. `v-ripple`代表启用基本的`ripple`功能
      * 2. `v-ripple="{ class: 'text-red' }"`代表自定义`ripple`颜色,支持`tailwindcss`,生效样式是`color`
      * 3. `v-ripple.center`代表从中心扩散
      */
-    vRipple: Directive<HTMLElement, RippleOptions>;
+    vRipple: Directive<HTMLElement, RippleOptions | boolean | undefined>;
   }
 }
 

+ 34 - 127
haha-admin-web/types/global-components.d.ts

@@ -1,134 +1,41 @@
+import type { IconifyIcon } from "@iconify/types";
+import type { iconType } from "../src/components/ReIcon/src/types";
+import type { Component, DefineComponent, HTMLAttributes } from "vue";
+
+type IconifyIconOfflineProps = {
+  icon?: IconifyIcon | string | Component;
+} & iconType &
+  HTMLAttributes;
+
+type IconifyIconOnlineProps = {
+  icon?: string;
+} & iconType &
+  HTMLAttributes;
+
+type FontIconProps = {
+  icon?: string;
+  /** `unicode` 引用模式 */
+  uni?: boolean;
+  /** `svg symbol` 引用模式 */
+  svg?: boolean;
+  iconType?: "uni" | "svg";
+} & HTMLAttributes;
+
+/** 权限控制组件公共 `Props` */
+type AuthorityProps = {
+  value?: string | string[];
+};
+
 declare module "vue" {
   /**
-   * 自定义全局组件获得 Volar 提示(自定义的全局组件需要在这里声明下才能获得 Volar 类型提示哦)
+   * 自定义全局组件获得 `Volar` 提示
    */
   export interface GlobalComponents {
-    IconifyIconOffline: (typeof import("../src/components/ReIcon"))["IconifyIconOffline"];
-    IconifyIconOnline: (typeof import("../src/components/ReIcon"))["IconifyIconOnline"];
-    FontIcon: (typeof import("../src/components/ReIcon"))["FontIcon"];
-    Auth: (typeof import("../src/components/ReAuth"))["Auth"];
-    Perms: (typeof import("../src/components/RePerms"))["Perms"];
-  }
-}
-
-/**
- * TODO https://github.com/element-plus/element-plus/blob/dev/global.d.ts#L2
- * No need to install @vue/runtime-core
- */
-declare module "vue" {
-  export interface GlobalComponents {
-    ElAffix: (typeof import("element-plus"))["ElAffix"];
-    ElAlert: (typeof import("element-plus"))["ElAlert"];
-    ElAside: (typeof import("element-plus"))["ElAside"];
-    ElAutocomplete: (typeof import("element-plus"))["ElAutocomplete"];
-    ElAvatar: (typeof import("element-plus"))["ElAvatar"];
-    ElAnchor: (typeof import("element-plus"))["ElAnchor"];
-    ElAnchorLink: (typeof import("element-plus"))["ElAnchorLink"];
-    ElBacktop: (typeof import("element-plus"))["ElBacktop"];
-    ElBadge: (typeof import("element-plus"))["ElBadge"];
-    ElBreadcrumb: (typeof import("element-plus"))["ElBreadcrumb"];
-    ElBreadcrumbItem: (typeof import("element-plus"))["ElBreadcrumbItem"];
-    ElButton: (typeof import("element-plus"))["ElButton"];
-    ElButtonGroup: (typeof import("element-plus"))["ElButtonGroup"];
-    ElCalendar: (typeof import("element-plus"))["ElCalendar"];
-    ElCard: (typeof import("element-plus"))["ElCard"];
-    ElCarousel: (typeof import("element-plus"))["ElCarousel"];
-    ElCarouselItem: (typeof import("element-plus"))["ElCarouselItem"];
-    ElCascader: (typeof import("element-plus"))["ElCascader"];
-    ElCascaderPanel: (typeof import("element-plus"))["ElCascaderPanel"];
-    ElCheckbox: (typeof import("element-plus"))["ElCheckbox"];
-    ElCheckboxButton: (typeof import("element-plus"))["ElCheckboxButton"];
-    ElCheckboxGroup: (typeof import("element-plus"))["ElCheckboxGroup"];
-    ElCol: (typeof import("element-plus"))["ElCol"];
-    ElCollapse: (typeof import("element-plus"))["ElCollapse"];
-    ElCollapseItem: (typeof import("element-plus"))["ElCollapseItem"];
-    ElCollapseTransition: (typeof import("element-plus"))["ElCollapseTransition"];
-    ElColorPicker: (typeof import("element-plus"))["ElColorPicker"];
-    ElContainer: (typeof import("element-plus"))["ElContainer"];
-    ElConfigProvider: (typeof import("element-plus"))["ElConfigProvider"];
-    ElDatePicker: (typeof import("element-plus"))["ElDatePicker"];
-    ElDialog: (typeof import("element-plus"))["ElDialog"];
-    ElDivider: (typeof import("element-plus"))["ElDivider"];
-    ElDrawer: (typeof import("element-plus"))["ElDrawer"];
-    ElDropdown: (typeof import("element-plus"))["ElDropdown"];
-    ElDropdownItem: (typeof import("element-plus"))["ElDropdownItem"];
-    ElDropdownMenu: (typeof import("element-plus"))["ElDropdownMenu"];
-    ElEmpty: (typeof import("element-plus"))["ElEmpty"];
-    ElFooter: (typeof import("element-plus"))["ElFooter"];
-    ElForm: (typeof import("element-plus"))["ElForm"];
-    ElFormItem: (typeof import("element-plus"))["ElFormItem"];
-    ElHeader: (typeof import("element-plus"))["ElHeader"];
-    ElIcon: (typeof import("element-plus"))["ElIcon"];
-    ElImage: (typeof import("element-plus"))["ElImage"];
-    ElImageViewer: (typeof import("element-plus"))["ElImageViewer"];
-    ElInput: (typeof import("element-plus"))["ElInput"];
-    ElInputNumber: (typeof import("element-plus"))["ElInputNumber"];
-    ElLink: (typeof import("element-plus"))["ElLink"];
-    ElMain: (typeof import("element-plus"))["ElMain"];
-    ElMenu: (typeof import("element-plus"))["ElMenu"];
-    ElMenuItem: (typeof import("element-plus"))["ElMenuItem"];
-    ElMenuItemGroup: (typeof import("element-plus"))["ElMenuItemGroup"];
-    ElOption: (typeof import("element-plus"))["ElOption"];
-    ElOptionGroup: (typeof import("element-plus"))["ElOptionGroup"];
-    ElPageHeader: (typeof import("element-plus"))["ElPageHeader"];
-    ElPagination: (typeof import("element-plus"))["ElPagination"];
-    ElPopconfirm: (typeof import("element-plus"))["ElPopconfirm"];
-    ElPopper: (typeof import("element-plus"))["ElPopper"];
-    ElPopover: (typeof import("element-plus"))["ElPopover"];
-    ElProgress: (typeof import("element-plus"))["ElProgress"];
-    ElRadio: (typeof import("element-plus"))["ElRadio"];
-    ElRadioButton: (typeof import("element-plus"))["ElRadioButton"];
-    ElRadioGroup: (typeof import("element-plus"))["ElRadioGroup"];
-    ElRate: (typeof import("element-plus"))["ElRate"];
-    ElRow: (typeof import("element-plus"))["ElRow"];
-    ElScrollbar: (typeof import("element-plus"))["ElScrollbar"];
-    ElSelect: (typeof import("element-plus"))["ElSelect"];
-    ElSlider: (typeof import("element-plus"))["ElSlider"];
-    ElStep: (typeof import("element-plus"))["ElStep"];
-    ElSteps: (typeof import("element-plus"))["ElSteps"];
-    ElSubMenu: (typeof import("element-plus"))["ElSubMenu"];
-    ElSwitch: (typeof import("element-plus"))["ElSwitch"];
-    ElTabPane: (typeof import("element-plus"))["ElTabPane"];
-    ElTable: (typeof import("element-plus"))["ElTable"];
-    ElTableColumn: (typeof import("element-plus"))["ElTableColumn"];
-    ElTabs: (typeof import("element-plus"))["ElTabs"];
-    ElTag: (typeof import("element-plus"))["ElTag"];
-    ElText: (typeof import("element-plus"))["ElText"];
-    ElTimePicker: (typeof import("element-plus"))["ElTimePicker"];
-    ElTimeSelect: (typeof import("element-plus"))["ElTimeSelect"];
-    ElTimeline: (typeof import("element-plus"))["ElTimeline"];
-    ElTimelineItem: (typeof import("element-plus"))["ElTimelineItem"];
-    ElTooltip: (typeof import("element-plus"))["ElTooltip"];
-    ElTransfer: (typeof import("element-plus"))["ElTransfer"];
-    ElTree: (typeof import("element-plus"))["ElTree"];
-    ElTreeV2: (typeof import("element-plus"))["ElTreeV2"];
-    ElTreeSelect: (typeof import("element-plus"))["ElTreeSelect"];
-    ElUpload: (typeof import("element-plus"))["ElUpload"];
-    ElSpace: (typeof import("element-plus"))["ElSpace"];
-    ElSkeleton: (typeof import("element-plus"))["ElSkeleton"];
-    ElSkeletonItem: (typeof import("element-plus"))["ElSkeletonItem"];
-    ElStatistic: (typeof import("element-plus"))["ElStatistic"];
-    ElCheckTag: (typeof import("element-plus"))["ElCheckTag"];
-    ElDescriptions: (typeof import("element-plus"))["ElDescriptions"];
-    ElDescriptionsItem: (typeof import("element-plus"))["ElDescriptionsItem"];
-    ElResult: (typeof import("element-plus"))["ElResult"];
-    ElSelectV2: (typeof import("element-plus"))["ElSelectV2"];
-    ElWatermark: (typeof import("element-plus"))["ElWatermark"];
-    ElTour: (typeof import("element-plus"))["ElTour"];
-    ElTourStep: (typeof import("element-plus"))["ElTourStep"];
-    ElSegmented: (typeof import("element-plus"))["ElSegmented"];
-  }
-
-  interface ComponentCustomProperties {
-    $storage: ResponsiveStorage;
-    $message: (typeof import("element-plus"))["ElMessage"];
-    $notify: (typeof import("element-plus"))["ElNotification"];
-    $msgbox: (typeof import("element-plus"))["ElMessageBox"];
-    $messageBox: (typeof import("element-plus"))["ElMessageBox"];
-    $alert: (typeof import("element-plus"))["ElMessageBox"]["alert"];
-    $confirm: (typeof import("element-plus"))["ElMessageBox"]["confirm"];
-    $prompt: (typeof import("element-plus"))["ElMessageBox"]["prompt"];
-    $loading: (typeof import("element-plus"))["ElLoadingService"];
+    IconifyIconOffline: DefineComponent<IconifyIconOfflineProps>;
+    IconifyIconOnline: DefineComponent<IconifyIconOnlineProps>;
+    FontIcon: DefineComponent<FontIconProps>;
+    Auth: DefineComponent<AuthorityProps>;
+    Perms: DefineComponent<AuthorityProps>;
   }
 }
 

+ 9 - 3
haha-admin-web/types/global.d.ts

@@ -102,7 +102,9 @@ declare global {
     SidebarStatus?: boolean;
     EpThemeColor?: string;
     ShowLogo?: boolean;
-    ShowModel?: string;
+    Watermark?: boolean;
+    WatermarkText?: string;
+    TagsStyle?: string;
     MenuArrowIconNoTransition?: boolean;
     CachingAsyncRoutes?: boolean;
     TooltipEffect?: Effect;
@@ -142,7 +144,9 @@ declare global {
     themeColor?: string;
     themeMode?: string;
     showLogo?: boolean;
-    showModel?: string;
+    watermark?: boolean;
+    watermarkText?: string;
+    tagsStyle?: string;
     menuSearchHistory?: number;
     mapConfigure?: {
       amapKey?: string;
@@ -177,7 +181,9 @@ declare global {
       hideTabs?: boolean;
       hideFooter?: boolean;
       showLogo?: boolean;
-      showModel?: string;
+      watermark?: boolean;
+      watermarkText?: string;
+      tagsStyle?: string;
       multiTagsCache?: boolean;
       stretch?: boolean | number;
     };

+ 3 - 7
haha-admin-web/types/shims-vue.d.ts

@@ -5,11 +5,7 @@ declare module "*.vue" {
   export default component;
 }
 
-declare module "*.scss" {
-  const scss: Record<string, string>;
-  export default scss;
-}
-
 declare module "vue3-puzzle-vcode";
-declare module "vue-virtual-scroller";
-declare module "vuedraggable/src/vuedraggable";
+declare module "swiper/css";
+declare module "swiper/css/navigation";
+declare module "swiper/css/pagination";

+ 8 - 10
haha-admin-web/vite.config.ts

@@ -9,7 +9,7 @@ import {
   __APP_INFO__
 } from "./build/utils";
 
-export default ({ mode }: ConfigEnv): UserConfigExport => {
+export default async ({ mode }: ConfigEnv): Promise<UserConfigExport> => {
   const { VITE_CDN, VITE_PORT, VITE_COMPRESSION, VITE_PUBLIC_PATH } =
     wrapperEnv(loadEnv(mode, root));
   
@@ -60,37 +60,35 @@ export default ({ mode }: ConfigEnv): UserConfigExport => {
     resolve: {
       alias
     },
-    // 服务端渲染
     server: {
-      port: 8888,
+      port: VITE_PORT,
       host: "0.0.0.0",
       proxy: proxyConfig,
-      // 预热文件以提前转换和缓存结果,降低启动期间的初始页面加载时长并防止转换瀑布
       warmup: {
         clientFiles: ["./index.html", "./src/{views,components}/*"]
       }
     },
-    plugins: getPluginsList(VITE_CDN, VITE_COMPRESSION),
-    // https://cn.vitejs.dev/config/dep-optimization-options.html#dep-optimization-options
+    plugins: await getPluginsList(VITE_CDN, VITE_COMPRESSION),
     optimizeDeps: {
       include,
       exclude
     },
     build: {
-      // https://cn.vitejs.dev/guide/build.html#browser-compatibility
       target: "es2015",
       sourcemap: false,
-      // 消除打包大小超过500kb警告
       chunkSizeWarningLimit: 4000,
-      rollupOptions: {
+      rolldownOptions: {
         input: {
           index: pathResolve("./index.html", import.meta.url)
         },
-        // 静态资源分类打包
         output: {
           chunkFileNames: "static/js/[name]-[hash].js",
           entryFileNames: "static/js/[name]-[hash].js",
           assetFileNames: "static/[ext]/[name]-[hash].[ext]"
+        },
+        checks: {
+          pluginTimings: false,
+          toleratedTransform: false
         }
       }
     },

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä