diff --git a/src/api/login.js b/src/api/login.js index 4c635ff..e519dba 100644 --- a/src/api/login.js +++ b/src/api/login.js @@ -33,17 +33,27 @@ export function register(data) { }) } -// 获取用户详细信息 -export function getInfo() { +function getPermissionInfo(params = {}) { return request({ url: '/admin-api/system/auth/get-permission-info', method: 'get', params: { - clientType: 2 + clientType: 2, + ...params } }) } +// 获取用户详细信息 +export function getInfo() { + return getPermissionInfo() +} + +// 获取功能导航菜单 +export function getNavPermissionInfo() { + return getPermissionInfo() +} + // 退出方法 export function logout() { return request({ diff --git a/src/api/system/userNavMenu.js b/src/api/system/userNavMenu.js new file mode 100644 index 0000000..bd61513 --- /dev/null +++ b/src/api/system/userNavMenu.js @@ -0,0 +1,16 @@ +import request from '@/utils/request' + +export function getUserNavMenuList() { + return request({ + url: '/admin-api/system/user-nav-menu/list', + method: 'get' + }) +} + +export function updateUserNavMenuList(data) { + return request({ + url: '/admin-api/system/user-nav-menu/update-list', + method: 'put', + data + }) +} \ No newline at end of file diff --git a/src/components/common/NavBar.vue b/src/components/common/NavBar.vue index 4de5575..ace2e82 100644 --- a/src/components/common/NavBar.vue +++ b/src/components/common/NavBar.vue @@ -91,7 +91,7 @@ onShow(() => { function handleBack() { uni.navigateBack({ fail: () => { - uni.switchTab({ + uni.reLaunch({ url: '/pages/index' }) } @@ -103,7 +103,7 @@ function handleBack() { .custom-navbar { position: relative; width: 100%; - z-index: 999; + z-index: 0; } .navbar-body { diff --git a/src/components/common/PermissionMenuPage.vue b/src/components/common/PermissionMenuPage.vue index 4f6a8fd..f91d237 100644 --- a/src/components/common/PermissionMenuPage.vue +++ b/src/components/common/PermissionMenuPage.vue @@ -85,9 +85,7 @@ \ No newline at end of file diff --git a/src/components/dashboard/NavMenuEditor.vue b/src/components/dashboard/NavMenuEditor.vue new file mode 100644 index 0000000..a074ee3 --- /dev/null +++ b/src/components/dashboard/NavMenuEditor.vue @@ -0,0 +1,634 @@ + + + + + \ No newline at end of file diff --git a/src/components/dashboard/NavMenuMore.vue b/src/components/dashboard/NavMenuMore.vue new file mode 100644 index 0000000..8378cde --- /dev/null +++ b/src/components/dashboard/NavMenuMore.vue @@ -0,0 +1,225 @@ + + + + + \ No newline at end of file diff --git a/src/components/dashboard/NavSection.vue b/src/components/dashboard/NavSection.vue index 7962fc2..dfadf5c 100644 --- a/src/components/dashboard/NavSection.vue +++ b/src/components/dashboard/NavSection.vue @@ -1,46 +1,156 @@ + \ No newline at end of file diff --git a/src/locales/en-US.js b/src/locales/en-US.js index b14e8b6..e65bc5d 100644 --- a/src/locales/en-US.js +++ b/src/locales/en-US.js @@ -7,7 +7,12 @@ export default { moduleBuilding: 'This module is under construction', updateSuccess: 'Updated successfully', confirmLogout: 'Are you sure you want to log out?', - languageSwitched: 'Language switched' + languageSwitched: 'Language switched', + more: 'More', + reset: 'Reset', + complete: 'Done', + edit: 'Edit', + saveFailed: 'Save failed' }, tab: { home: 'Home', @@ -30,6 +35,12 @@ export default { welcome: 'Welcome to', subtitle: 'Besure Digital Intelligent Control Platform', functionNav: 'Function Navigation', + editNavMenu: 'Edit Shortcuts', + configuredNav: 'Added', + unconfiguredNav: 'Add More', + dragHint: 'Drag icons to reorder, icons above will be displayed in control center', + clickHint: 'Tap icons to add or remove from configuration', + allNavMenu: 'All Functions', productionOverview: 'Production Overview', qualityOverview: 'Quality Overview', productionPlan: 'Production Summary', diff --git a/src/locales/index.js b/src/locales/index.js index 9f37713..b7b0539 100644 --- a/src/locales/index.js +++ b/src/locales/index.js @@ -1,8 +1,6 @@ import { createI18n } from 'vue-i18n' import zhCN from './zh-CN' import enUS from './en-US' -import useUserStore from '@/store/modules/user' -import { syncTabBarMenus } from '@/utils/permissionMenu' const LOCALE_STORAGE_KEY = 'app_locale' const LOCALE_CHANGE_EVENT = 'app-locale-changed' @@ -85,26 +83,6 @@ const literalMap = { '点检记录详情': 'moldWorkOrder.detailTitle' } -export function applyTabBarLanguage() { - try { - const pages = getCurrentPages() - if (!pages || pages.length === 0) return - const currentPage = pages[pages.length - 1] - if (!currentPage) return - const route = currentPage.route || '' - const tabBarPages = ['pages/index', 'pages/report', 'pages/work', 'pages/mine'] - if (!tabBarPages.includes(route)) return - - syncTabBarMenus(useUserStore().menus, { - homeText: i18n.global.t('tab.home'), - reportFallback: i18n.global.t('tab.report'), - workFallback: i18n.global.t('tab.work'), - mineText: i18n.global.t('tab.mine') - }) - } catch (e) { - } -} - export function getCurrentLocale() { return i18n.global.locale.value } @@ -113,7 +91,6 @@ export function setLocale(locale) { const nextLocale = normalizeLocale(locale) i18n.global.locale.value = nextLocale uni.setStorageSync(LOCALE_STORAGE_KEY, nextLocale) - applyTabBarLanguage() uni.$emit(LOCALE_CHANGE_EVENT, nextLocale) return nextLocale } diff --git a/src/locales/zh-CN.js b/src/locales/zh-CN.js index 9389422..f72d755 100644 --- a/src/locales/zh-CN.js +++ b/src/locales/zh-CN.js @@ -7,7 +7,12 @@ export default { moduleBuilding: '模块建设中~', updateSuccess: '修改成功', confirmLogout: '确定注销并退出系统吗', - languageSwitched: '语言已切换' + languageSwitched: '语言已切换', + more: '更多', + reset: '重置', + complete: '完成', + edit: '编辑', + saveFailed: '保存失败' }, tab: { home: '首页', @@ -30,6 +35,12 @@ export default { welcome: '欢迎您使用', subtitle: '必硕数字化智能中控平台', functionNav: '功能导航', + editNavMenu: '编辑快捷开关', + configuredNav: '已添加', + unconfiguredNav: '添加更多', + dragHint: '拖动图标进行排序,上方图标将显示在控制中心', + clickHint: '点击图标添加到已配置或取消配置', + allNavMenu: '全部功能', productionOverview: '生产整体概况', qualityOverview: '质量概况', productionPlan: '生产概括', diff --git a/src/pages.json b/src/pages.json index e46527c..9c9bb75 100644 --- a/src/pages.json +++ b/src/pages.json @@ -625,36 +625,5 @@ ] } ], - "tabBar": { - "color": "#666666", - "selectedColor": "#1a3a5c", - "borderStyle": "white", - "backgroundColor": "#ffffff", - "list": [ - { - "pagePath": "pages/index", - "iconPath": "static/images/tabbar/home.png", - "selectedIconPath": "static/images/tabbar/home_.png", - "text": "首页" - }, - { - "pagePath": "pages/report", - "iconPath": "static/images/tabbar/report.png", - "selectedIconPath": "static/images/tabbar/report_.png", - "text": "报表" - }, - { - "pagePath": "pages/work", - "iconPath": "static/images/tabbar/work.png", - "selectedIconPath": "static/images/tabbar/work_.png", - "text": "管理" - }, - { - "pagePath": "pages/mine", - "iconPath": "static/images/tabbar/mine.png", - "selectedIconPath": "static/images/tabbar/mine_.png", - "text": "我的" - } - ] - } + "preloadRule": {} } \ No newline at end of file diff --git a/src/pages/index.vue b/src/pages/index.vue index aa2afe5..c739a8e 100644 --- a/src/pages/index.vue +++ b/src/pages/index.vue @@ -13,6 +13,8 @@ + + @@ -21,6 +23,7 @@ import { onMounted, onUnmounted, ref, computed } from 'vue' import { useI18n } from 'vue-i18n' import { onLocaleChange, offLocaleChange, setNavigationTitle } from '@/locales' import NavBar from '@/components/common/NavBar.vue' +import TabBar from '@/components/common/TabBar.vue' import BannerSection from '@/components/dashboard/BannerSection.vue' import NavSection from '@/components/dashboard/NavSection.vue' import StatsSection from '@/components/dashboard/StatsSection.vue' @@ -58,6 +61,7 @@ function goTop() { flex-direction: column; height: 100vh; background-color: #f0f2f5; + padding-bottom: 100rpx; } .main-scroll { diff --git a/src/pages/login.vue b/src/pages/login.vue index 5bee2fb..d465615 100644 --- a/src/pages/login.vue +++ b/src/pages/login.vue @@ -106,7 +106,7 @@ async function pwdLogin() { function loginSuccess(result) { userStore.getInfo().then(res => { - uni.switchTab({ + uni.reLaunch({ url: '/pages/index' }); }) diff --git a/src/pages/mine.vue b/src/pages/mine.vue index a62bf11..edb06c0 100644 --- a/src/pages/mine.vue +++ b/src/pages/mine.vue @@ -80,6 +80,7 @@ + @@ -89,6 +90,7 @@ import { useI18n } from 'vue-i18n' import useUserStore from '@/store/modules/user' import { onLocaleChange, offLocaleChange } from '@/locales' import NavBar from '@/components/common/NavBar.vue' +import TabBar from '@/components/common/TabBar.vue' const userStore = useUserStore() const name = userStore.name; diff --git a/src/pages/report.vue b/src/pages/report.vue index 89c1a61..e22ee2f 100644 --- a/src/pages/report.vue +++ b/src/pages/report.vue @@ -6,6 +6,7 @@ title="报表中心" subtitle="数据驱动决策 · 智能分析" /> + @@ -13,6 +14,7 @@ import { computed } from 'vue' import { useI18n } from 'vue-i18n' import NavBar from '@/components/common/NavBar.vue' +import TabBar from '@/components/common/TabBar.vue' import PermissionMenuPage from '@/components/common/PermissionMenuPage.vue' const { t } = useI18n() @@ -25,5 +27,6 @@ const pageTitle = computed(() => t('tab.report')) flex-direction: column; height: 100vh; background-color: #f5f6f7; + padding-bottom: 100rpx; } - + \ No newline at end of file diff --git a/src/pages/work.vue b/src/pages/work.vue index 26df729..3e7e4eb 100644 --- a/src/pages/work.vue +++ b/src/pages/work.vue @@ -8,6 +8,7 @@ :searchable="true" :show-go-top="true" /> + @@ -15,6 +16,7 @@ import { computed } from 'vue' import { useI18n } from 'vue-i18n' import NavBar from '@/components/common/NavBar.vue' +import TabBar from '@/components/common/TabBar.vue' import PermissionMenuPage from '@/components/common/PermissionMenuPage.vue' const { t } = useI18n() @@ -27,5 +29,6 @@ const pageTitle = computed(() => t('tab.work')) flex-direction: column; height: 100vh; background-color: #f5f6f7; + padding-bottom: 100rpx; } - + \ No newline at end of file diff --git a/src/plugins/tab.ts b/src/plugins/tab.ts index bdb4eb0..bdc04ec 100644 --- a/src/plugins/tab.ts +++ b/src/plugins/tab.ts @@ -23,7 +23,7 @@ export default { }, /** - * 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面 + * 自定义 tabbar 场景下,使用 reLaunch 替代官方 switchTab * @param url 页面路径 * @returns */ @@ -32,7 +32,7 @@ export default { console.log(!!params?url + '?' + tansParams(params):url); return new Promise((resolve, reject) => { - uni.switchTab({ + uni.reLaunch({ url: !!params?url + '?' + tansParams(params):url, success: resolve, fail: reject diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index e79594f..816e241 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -3,7 +3,6 @@ import { getToken, setToken, removeToken } from "@/utils/auth"; import defAva from "@/static/images/profile.jpg"; import { defineStore } from "pinia"; import { initAllDict } from "@/utils/dict"; -import { syncTabBarMenus } from "@/utils/permissionMenu"; export interface LoginForm { username: string; @@ -65,7 +64,6 @@ const useUserStore = defineStore("user", { } this.permissions = res.data.permissions; this.menus = Array.isArray(res.data.menus) ? res.data.menus : []; - syncTabBarMenus(this.menus); this.name = user.nickname; this.userId = user.id; this.avatar = avatar; diff --git a/src/utils/permissionMenu.js b/src/utils/permissionMenu.js index 94ef3de..df99ce5 100644 --- a/src/utils/permissionMenu.js +++ b/src/utils/permissionMenu.js @@ -64,6 +64,19 @@ function toArray(value) { return Array.isArray(value) ? value : [] } +function walkMenus(menus, visitor, parent = null) { + toArray(menus).forEach((menu, index) => { + if (!menu || typeof menu !== 'object') { + return + } + visitor(menu, parent, index) + const children = toArray(menu.children) + if (children.length > 0) { + walkMenus(children, visitor, menu) + } + }) +} + function normalizeMenuKey(value) { return String(value || '') .trim() @@ -112,6 +125,42 @@ export function getTopLevelMenus(menus) { return toArray(menus).filter((menu) => menu && typeof menu === 'object') } +export function flattenMenus(menus) { + const result = [] + walkMenus(menus, (menu, parent, index) => { + result.push({ + ...menu, + _parent: parent || null, + _levelIndex: index + }) + }) + return result +} + +export function getConfigurableNavMenus(menus) { + const dedupe = new Set() + return flattenMenus(menus).filter((menu) => { + if (menu.type !== 2 || menu.id == null || dedupe.has(menu.id)) { + return false + } + dedupe.add(menu.id) + return true + }) +} + +export function buildNavMenuViewModels(menus) { + return getConfigurableNavMenus(menus).map((menu, index) => { + const displayName = String(menu.name || menu.enName || '').trim() || `菜单${index + 1}` + return { + ...menu, + displayName, + route: resolveMenuUrl(menu), + symbol: getMenuSymbol(displayName, index), + accentColor: getModuleColor(index) + } + }) +} + export function getDynamicTabMenus(menus) { return getTopLevelMenus(menus).filter((menu) => !looksLikeHomeMenu(menu)) } @@ -167,17 +216,10 @@ export function getMenuSymbol(name, index) { export function syncTabBarMenus(menus, options = {}) { const dynamicMenus = getDynamicTabMenus(menus) - const labels = [ + return [ options.homeText || '首页', dynamicMenus[0]?.name || options.reportFallback || '报表', dynamicMenus[1]?.name || dynamicMenus[0]?.name || options.workFallback || '管理', options.mineText || '我的' ] - - labels.forEach((text, index) => { - uni.setTabBarItem({ - index, - text - }) - }) } \ No newline at end of file