From ecedab030b03213bb5595a57fdec7354897f6ecc Mon Sep 17 00:00:00 2001 From: "Mr.April" Date: Fri, 17 Apr 2026 15:12:42 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=8F=98=E6=9B=B4=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E4=BD=BF=E7=94=A8code=E4=B8=8D=E5=9C=A8?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=88=86=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/stores/config.ts | 92 +++++++++++++++++++++-------------- app/stores/interface/index.ts | 3 +- app/stores/system.ts | 66 ++++++++++++++++++++++++- nuxt.config.ts | 4 +- package.json | 8 +-- pnpm-lock.yaml | 81 ++++++++++++++++++++++++++++++ 6 files changed, 210 insertions(+), 44 deletions(-) diff --git a/app/stores/config.ts b/app/stores/config.ts index da8af6b..473dc79 100644 --- a/app/stores/config.ts +++ b/app/stores/config.ts @@ -1,5 +1,5 @@ import { defineStore } from 'pinia' -import { getWebGroupConfigs } from '~/api/site' +import { getConfigByCode } from '~/api/site' import { navigateTo } from 'nuxt/app' /** @@ -112,7 +112,7 @@ export const useConfigStore = defineStore('config', { agreement_show: 0 // 默认不显示用户协议 }, language: { - is_enabled: 1, // 默认启用多语言支持 + is_enabled: 0, // 默认不启用多语言支持 default_lang: 'zh-cn', // 默认语言为中文 available_langs: ['zh-cn', 'en'] // 可用语言 }, @@ -142,7 +142,7 @@ export const useConfigStore = defineStore('config', { // SEO配置默认值 seo_title: 'madong', // 默认SEO标题 - seo_keywords: ['madong', 'madong-admin', 'madong工作流'], // 默认SEO关键词数组 + seo_keywords: ['madong', 'madong官网','madong极速开发框架','madong快速开发框架','madong-admin', 'madong工作流','madong后台管理系统','madong开源','码动','码动开源'], // 默认SEO关键词数组 seo_description: 'madong通用快速开发框架是一个基于Vue3 + TypeScript + ElementPlus的快速开发框架,提供了一个完整的后台管理系统模板', // 默认SEO描述 site_name: 'madong', // 默认站点名称 site_url: '', // 默认站点URL(留空自动获取) @@ -153,60 +153,80 @@ export const useConfigStore = defineStore('config', { actions: { /** * 获取 Web 分组配置 - * @description 一次性获取所有 Web 分组配置(站点设置、搜索、统计分析、登录配置等) + * @description 并行获取所有 Web 分组配置(站点设置、搜索、统计分析、登录配置等) * @param router - 可选的路由器实例,用于页面跳转控制 */ async getWebGroupConfigs(router?: any) { try { - const response = await getWebGroupConfigs() - const data = response?.data || response || {} + // 并行获取所有配置 + const [ + loginConfigRes, + siteSettingRes, + searchConfigRes, + analyticsConfigRes, + paymentConfigRes + ] = await Promise.all([ + getConfigByCode('web_login_config'), + getConfigByCode('web_site_setting'), + getConfigByCode('web_search_config'), + getConfigByCode('web_analytics_config'), + getConfigByCode('web_payment_config') + ]) // 更新登录配置 - if (data.web_login_config && !Array.isArray(data.web_login_config)) { - this.login.is_username = parseInt(data.web_login_config.is_username) - this.login.is_mobile = parseInt(data.web_login_config.is_mobile) - this.login.is_auth_register = parseInt(data.web_login_config.is_auth_register) - this.login.is_bind_mobile = parseInt(data.web_login_config.is_bind_mobile) - this.login.is_wechat_scan = parseInt(data.web_login_config.is_wechat_scan) - this.login.agreement_show = parseInt(data.web_login_config.agreement_show) + const loginConfig = loginConfigRes?.data || loginConfigRes || {} + if (loginConfig && !Array.isArray(loginConfig)) { + this.login.is_username = parseInt(loginConfig.is_username) + this.login.is_mobile = parseInt(loginConfig.is_mobile) + this.login.is_auth_register = parseInt(loginConfig.is_auth_register) + this.login.is_bind_mobile = parseInt(loginConfig.is_bind_mobile) + this.login.is_wechat_scan = parseInt(loginConfig.is_wechat_scan) + this.login.agreement_show = parseInt(loginConfig.agreement_show) // 如果当前在关闭页面且有配置数据,自动跳转到首页 - if(data.web_login_config && router && router.currentRoute.value.path === '/site/close'){ + if (router && router.currentRoute.value.path === '/site/close') { navigateTo('/', { replace: true }) } } // 更新站点设置 - if (data.web_site_setting && !Array.isArray(data.web_site_setting)) { - this.siteSetting.copyright = data.web_site_setting.copyright || '' - this.siteSetting.icp = data.web_site_setting.icp || '' - this.siteSetting.icp_url = data.web_site_setting.icp_url || 'https://beian.miit.gov.cn/' - this.siteSetting.network_security = data.web_site_setting.network_security || '' - this.siteSetting.network_security_url = data.web_site_setting.network_security_url || '' - + const siteSetting = siteSettingRes?.data || siteSettingRes || {} + if (siteSetting && !Array.isArray(siteSetting)) { + this.siteSetting.copyright = siteSetting.copyright || '' + this.siteSetting.icp = siteSetting.icp || '' + this.siteSetting.icp_url = siteSetting.icp_url || 'https://beian.miit.gov.cn/' + this.siteSetting.network_security = siteSetting.network_security || '' + this.siteSetting.network_security_url = siteSetting.network_security_url || '' + // 更新SEO配置(支持数组形式) - this.siteSetting.seo_title = data.web_site_setting.seo_title || 'madong 通用快速框架' - this.siteSetting.seo_keywords = data.web_site_setting.seo_keywords || ['madong', 'madong-admin', 'ingenious','工作流引擎'] - this.siteSetting.seo_description = data.web_site_setting.seo_description || '专业开源服务平台' - this.siteSetting.site_name = data.web_site_setting.site_name || 'madong' - this.siteSetting.site_url = data.web_site_setting.site_url || (typeof window !== 'undefined' ? window.location.origin : '') - this.siteSetting.share_image = data.web_site_setting.share_image || '/images/share-default.png' + this.siteSetting.seo_title = siteSetting.seo_title || 'madong 通用快速框架' + this.siteSetting.seo_keywords = siteSetting.seo_keywords || ['madong', 'madong-admin', 'ingenious', '工作流引擎'] + this.siteSetting.seo_description = siteSetting.seo_description || '专业开源服务平台' + this.siteSetting.site_name = siteSetting.site_name || 'madong' + this.siteSetting.site_url = siteSetting.site_url || (typeof window !== 'undefined' ? window.location.origin : '') + this.siteSetting.share_image = siteSetting.share_image || '/images/share-default.png' } - // 更新搜索配置 - if (data.web_search_config && !Array.isArray(data.web_search_config)) { - this.search.keyword = data.web_search_config.keyword || '' - this.search.keyword_enabled = parseInt(data.web_search_config.keyword_enabled) + // 更新搜索配置 + const searchConfig = searchConfigRes?.data || searchConfigRes || {} + if (searchConfig && !Array.isArray(searchConfig)) { + this.search.keyword = searchConfig.keyword || '' + this.search.keyword_enabled = parseInt(searchConfig.keyword_enabled) } // 更新统计分析配置 - if (data.web_analytics_config && !Array.isArray(data.web_analytics_config)) { - this.analytics.baidu_tongji_code = data.web_analytics_config.baidu_tongji_code || '' - this.analytics.baidu_tongji_enabled = parseInt(data.web_analytics_config.baidu_tongji_enabled) + const analyticsConfig = analyticsConfigRes?.data || analyticsConfigRes || {} + if (analyticsConfig && !Array.isArray(analyticsConfig)) { + this.analytics.baidu_tongji_code = analyticsConfig.baidu_tongji_code || '' + this.analytics.baidu_tongji_enabled = parseInt(analyticsConfig.baidu_tongji_enabled) } - // 可继续添加其他配置的处理 - // 如有新的 web 分组配置,在此添加 + // 更新支付配置 + const paymentConfig = paymentConfigRes?.data || paymentConfigRes || {} + if (paymentConfig && !Array.isArray(paymentConfig)) { + this.payment.is_wechat_enabled = parseInt(paymentConfig.is_wechat_enabled) + this.payment.is_alipay_enabled = parseInt(paymentConfig.is_alipay_enabled) + } } catch (error) { console.error('获取 Web 分组配置失败:', error) } diff --git a/app/stores/interface/index.ts b/app/stores/interface/index.ts index ac5960a..dfbd5b3 100644 --- a/app/stores/interface/index.ts +++ b/app/stores/interface/index.ts @@ -41,7 +41,8 @@ export interface Menus { title: string url?: string icon?: string - meta: MenuMeta + meta?: MenuMeta + extra?: Record children?: Menus[] sort?: number belong?: string diff --git a/app/stores/system.ts b/app/stores/system.ts index 7e67b65..074bbf3 100644 --- a/app/stores/system.ts +++ b/app/stores/system.ts @@ -154,8 +154,8 @@ export const useSystemStore = defineStore('system', { // 根据 category 字段分类菜单 // category = 1: 导航菜单 (NAV) // category = 2: 会员菜单 (MEMBER) - const navMenuItems = allMenus.filter((menu: any) => menu.category === 1) || [] - const memberMenuItems = allMenus.filter((menu: any) => menu.category === 2) || [] + const navMenuItems = allMenus.filter((menu: any) => String(menu.category) === '1') || [] + const memberMenuItems = allMenus.filter((menu: any) => String(menu.category) === '2') || [] // 构建层级菜单树 const navMenu = this.buildMenuTree(navMenuItems) @@ -211,6 +211,7 @@ export const useSystemStore = defineStore('system', { permissions: item.meta?.permissions || item.code || [], ...(item.meta || {}) }, + extra: item.extra || {}, children: [] } // 统一 ID 类型为字符串,避免类型不匹配问题 @@ -280,6 +281,67 @@ export const useSystemStore = defineStore('system', { return processedMenu }, + /** + * 追加菜单到导航菜单 + * @param menu 菜单项 + * @param index 插入位置:正数从前面(0开始),负数从后面(-1最后,-2倒数第二),不传默认最后 + * @param checkExists 是否检查已存在(默认true) + */ + appendNavMenu(menu: Menus, index?: number, checkExists: boolean = true) { + if (!this.site.nav_menu) { + this.site.nav_menu = [] + } + // 检查是否已存在 + if (checkExists) { + const exists = this.site.nav_menu.some((m: Menus) => m.path === menu.path || m.id === menu.id) + if (exists) return false + } + + // 处理插入位置 + if (index === undefined) { + // 默认追加到最后 + this.site.nav_menu.push(menu) + } else if (index >= 0) { + // 正数:从前面插入到指定位置 + const insertIndex = Math.min(index, this.site.nav_menu.length) + this.site.nav_menu.splice(insertIndex, 0, menu) + } else { + // 负数:从后面倒数插入 + // -1 表示最后(等同于 push),-2 表示倒数第二 + const insertIndex = Math.max(this.site.nav_menu.length + index + 1, 0) + this.site.nav_menu.splice(insertIndex, 0, menu) + } + return true + }, + + /** + * 更新导航菜单项 + * @param path 菜单路径 + * @param updates 更新的属性 + */ + updateNavMenuItem(path: string, updates: Partial) { + const menu = this.site.nav_menu?.find((m: Menus) => m.path === path) + if (menu) { + Object.assign(menu, updates) + return true + } + return false + }, + + /** + * 移除导航菜单项 + * @param path 菜单路径 + */ + removeNavMenu(path: string) { + if (!this.site.nav_menu) return false + const index = this.site.nav_menu.findIndex((m: Menus) => m.path === path) + if (index > -1) { + this.site.nav_menu.splice(index, 1) + return true + } + return false + }, + /** * 转换菜单类型 */ diff --git a/nuxt.config.ts b/nuxt.config.ts index 54f188c..7516d6c 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -17,7 +17,7 @@ export default defineNuxtConfig({ }, app: { - baseURL: '/web', + baseURL: '/', head: { htmlAttrs: { lang: 'zh-cn' @@ -95,5 +95,5 @@ export default defineNuxtConfig({ importStyle: 'scss', themes: ['dark'], }, - ssr: true, + ssr: false, }) diff --git a/package.json b/package.json index 059db91..882375d 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,8 @@ "pinia-plugin-persistedstate": "^4.7.1", "qrcode": "^1.5.4", "qs": "^6.14.1", - "vue-i18n": "^11.2.8" + "vue-i18n": "^11.2.8", + "axios": "^1.6.0" }, "devDependencies": { "@element-plus/nuxt": "^1.1.4", @@ -59,7 +60,8 @@ "sass": "^1.89.2", "typescript": "^5.9.2", "vite-tsconfig-paths": "^6.0.4", - "vue-tsc": "^3.0.5" + "vue-tsc": "^3.0.5", + "axios": "^1.6.0" }, "peerDependencies": { "pinia": "^2.1.6" @@ -73,4 +75,4 @@ ] } } -} \ No newline at end of file +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 77bdd44..a4c8132 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: '@wangeditor/editor': specifier: ^5.1.23 version: 5.1.23 + axios: + specifier: ^1.6.0 + version: 1.15.0 element-plus: specifier: ^2.10.5 version: 2.13.2(vue@3.5.28(typescript@5.9.3)) @@ -2365,6 +2368,9 @@ packages: async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + autoprefixer@10.4.24: resolution: {integrity: sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==} engines: {node: ^10 || ^12 || >=14} @@ -2372,6 +2378,9 @@ packages: peerDependencies: postcss: ^8.1.0 + axios@1.15.0: + resolution: {integrity: sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==} + b4a@1.7.4: resolution: {integrity: sha512-u20zJLDaSWpxaZ+zaAkEIB2dZZ1o+DF4T/MRbmsvGp9nletHOyiai19OzX1fF8xUBYsO1bPXxODvcd0978pnug==} peerDependencies: @@ -2559,6 +2568,10 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -2764,6 +2777,10 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + denque@2.1.0: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} engines: {node: '>=0.10'} @@ -2877,6 +2894,10 @@ packages: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + es5-ext@0.10.64: resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} engines: {node: '>=0.10'} @@ -3164,6 +3185,15 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + font-awesome@4.7.0: resolution: {integrity: sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg==} engines: {node: '>=0.10.3'} @@ -3172,6 +3202,10 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} @@ -3300,6 +3334,10 @@ packages: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -4322,6 +4360,10 @@ packages: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} @@ -8017,6 +8059,8 @@ snapshots: async@3.2.6: {} + asynckit@0.4.0: {} + autoprefixer@10.4.24(postcss@8.5.6): dependencies: browserslist: 4.28.1 @@ -8026,6 +8070,14 @@ snapshots: postcss: 8.5.6 postcss-value-parser: 4.2.0 + axios@1.15.0: + dependencies: + follow-redirects: 1.16.0 + form-data: 4.0.5 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + b4a@1.7.4: {} balanced-match@1.0.2: {} @@ -8225,6 +8277,10 @@ snapshots: colorette@2.0.20: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + commander@11.1.0: {} commander@2.20.3: {} @@ -8404,6 +8460,8 @@ snapshots: defu@6.1.4: {} + delayed-stream@1.0.0: {} + denque@2.1.0: {} depd@2.0.0: {} @@ -8509,6 +8567,13 @@ snapshots: dependencies: es-errors: 1.3.0 + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + es5-ext@0.10.64: dependencies: es6-iterator: 2.0.3 @@ -8886,6 +8951,8 @@ snapshots: flatted@3.3.3: {} + follow-redirects@1.16.0: {} + font-awesome@4.7.0: {} foreground-child@3.3.1: @@ -8893,6 +8960,14 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + fraction.js@5.3.4: {} fresh@2.0.0: {} @@ -9023,6 +9098,10 @@ snapshots: has-symbols@1.1.0: {} + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -10205,6 +10284,8 @@ snapshots: kleur: 3.0.3 sisteransi: 1.0.5 + proxy-from-env@2.1.0: {} + punycode.js@2.3.1: {} punycode@2.3.1: {}