Files
shanxia2.0/miniprogram/pages/workbench/workbench.vue
T
2026-09-26 11:59:39 +08:00

159 lines
4.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
import { computed, ref } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { useUserStore } from '@/stores/user'
import { WORKBENCH_MODULES } from '@/config/workbench-menus'
import { PAGE_PATHS, WORKBENCH_ROUTE_MAP } from '@/config/api'
import { filterWorkbenchModules } from '@/utils/workbenchMenuFilter'
import { getSafeAreaStyle } from '@/utils/safeArea'
const safeAreaStyle = getSafeAreaStyle()
const userStore = useUserStore()
const modules = computed(() =>
filterWorkbenchModules(WORKBENCH_MODULES, {
menuAll: userStore.menuAll,
menuCodes: userStore.menuCodes
})
)
const loggingOut = ref(false)
const displayName = computed(() => {
const info = userStore.userInfo
if (!info) return '未登录'
return info.realName || info.username || '用户'
})
/** 三列宫格补齐空白格,避免末行空位露出网格底色 */
const menuPadCount = (len) => {
const rem = Number(len) % 3
return rem === 0 ? 0 : 3 - rem
}
onShow(async () => {
userStore.checkLoginStatus()
if (!userStore.isLoggedIn) {
uni.reLaunch({ url: PAGE_PATHS.login })
return
}
await userStore.fetchMenuCodes()
})
/** 含 web-view 的页用 redirectTo,避免真机 navigateTo:fail timeout 闪进又弹回工作台 */
const isMpWebviewRoute = (url) => String(url || '').includes('/pages/common/mp-webview')
const openPage = (url) => {
const failToast = () => uni.showToast({ title: '打开失败,请重试', icon: 'none' })
if (isMpWebviewRoute(url)) {
const ret = uni.redirectTo({
url,
fail: (err) => {
// 栈异常时再退到 reLaunch
const msg = String((err && err.errMsg) || '')
if (/fail/i.test(msg)) {
uni.reLaunch({ url, fail: failToast })
return
}
failToast()
}
})
if (ret && typeof ret.catch === 'function') ret.catch(() => {})
return
}
const fail = (err) => {
const msg = String((err && err.errMsg) || '')
if (/timeout/i.test(msg)) {
uni.redirectTo({ url, fail: failToast })
return
}
failToast()
}
const ret = uni.navigateTo({ url, fail })
if (ret && typeof ret.catch === 'function') {
ret.catch(() => {})
}
}
const openMenu = (module, menu) => {
if (!menu.enabled) {
uni.showToast({ title: '本期暂未开放', icon: 'none' })
return
}
const route = WORKBENCH_ROUTE_MAP[menu.code]
if (route) {
openPage(route)
return
}
const title = encodeURIComponent(menu.name || '')
const moduleTitle = encodeURIComponent(module.title || '')
const code = encodeURIComponent(menu.code || '')
openPage(`${PAGE_PATHS.bizPlaceholder}?title=${title}&module=${moduleTitle}&code=${code}`)
}
const handleLogout = async () => {
if (loggingOut.value) return
loggingOut.value = true
try {
await userStore.logout()
} finally {
loggingOut.value = false
}
}
</script>
<template>
<view class="mp-page mp-page--tab">
<view class="mp-header mp-header--workbench" :style="safeAreaStyle">
<view class="mp-header__body">
<view class="mp-header__titles">
<text class="mp-header__title">山峡化工工作台</text>
</view>
<view class="mp-header__user-stack">
<text class="mp-header__user-line">{{ displayName }},欢迎您</text>
<text
class="mp-header__logout"
:class="{ 'mp-header__logout--disabled': loggingOut }"
@click="handleLogout"
>
{{ loggingOut ? '退出中…' : '退出登录' }}
</text>
</view>
</view>
</view>
<view class="mp-section">
<view
v-for="mod in modules"
:key="mod.key"
class="mp-module-block"
:class="'mp-module-block--' + mod.key"
>
<view class="mp-module-block__head">
<text class="mp-module-block__icon">{{ mod.iconText }}</text>
<view class="mp-module-block__title-wrap">
<text class="mp-module-block__title">{{ mod.title }}</text>
<text class="mp-module-block__desc">{{ mod.desc }}</text>
</view>
</view>
<view class="mp-menu-grid">
<view
v-for="(menu, idx) in mod.menus"
:key="menu.code || menu.name + idx"
class="mp-menu-card"
:class="{ 'mp-menu-card--disabled': !menu.enabled }"
@click="openMenu(mod, menu)"
>
<view class="mp-menu-card__icon">{{ menu.icon || '' }}</view>
<text class="mp-menu-card__name">{{ menu.name }}</text>
</view>
<view
v-for="i in menuPadCount(mod.menus.length)"
:key="'pad-' + mod.key + '-' + i"
class="mp-menu-card mp-menu-card--pad"
/>
</view>
</view>
</view>
<app-env-badge />
</view>
</template>