feat:tabbar
This commit is contained in:
1 parent
f4adf95e7a
commit
6d267bcfc5
11 files changed
+142
-26
No files matched your search
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "",
|
||||
"appid": "",
|
||||
"appid": "wx11771c7bf2913cb2",
|
||||
"description": "",
|
||||
"versionName": "1.0.0",
|
||||
"versionCode": "100",
|
||||
@@ -50,7 +50,7 @@
|
||||
"quickapp": {},
|
||||
/* 小程序特有相关 */
|
||||
"mp-weixin": {
|
||||
"appid": "",
|
||||
"appid": "wx11771c7bf2913cb2",
|
||||
"setting": {
|
||||
"urlCheck": false
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<crud-layout title="通知公告" :bg="filePath(SERVICE_IMAGE.blueBg)">
|
||||
<view class="h-30rpx" />
|
||||
<view class="notice-container">
|
||||
<view class="notice-list">
|
||||
<view v-if="noticeList.length === 0" class="empty-tip"> 暂无公告 </view>
|
||||
|
||||
@@ -73,6 +73,8 @@ const doMenu = async (v: any) => {
|
||||
// 是否是具体页面
|
||||
const routePath = v.page.split("?")[0]
|
||||
if (v.page.startsWith("/") && __ROUTES__.some((route) => route.path === routePath)) {
|
||||
// 直接页面入口也要先组装所属业务 Tabbar,再进入目标页面。
|
||||
await tabbarStore.componetTabbarList(v.page)
|
||||
router.jump(v.page)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,24 +1,55 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from "vue"
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app"
|
||||
import { reactive } from "vue"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
|
||||
const state = reactive({
|
||||
url: ""
|
||||
url: "",
|
||||
})
|
||||
|
||||
onLoad((options: any) => {
|
||||
if (options.url) {
|
||||
state.url = decodeURIComponent(options.url)
|
||||
// 只记录地址结构,不输出 token,便于定位微信 WebView 域名校验问题。
|
||||
try {
|
||||
const url = new URL(state.url)
|
||||
console.log("[web-view] 加载地址:", {
|
||||
origin: url.origin,
|
||||
pathname: url.pathname,
|
||||
queryKeys: Array.from(url.searchParams.keys()),
|
||||
})
|
||||
} catch (error) {
|
||||
console.error("[web-view] 地址解析失败:", error)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const handleWebViewLoad = (event: any) => {
|
||||
console.log("[web-view] 加载完成:", event?.detail?.src || state.url)
|
||||
}
|
||||
|
||||
const handleWebViewError = (event: any) => {
|
||||
console.error("[web-view] 加载失败:", {
|
||||
url: state.url,
|
||||
detail: event?.detail,
|
||||
})
|
||||
uni.showToast({ title: "第三方页面加载失败,请检查业务域名配置", icon: "none" })
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<crud-layout mainIsScroll tabBarType="just-flot-back">
|
||||
<web-view :update-title="false" :fullscreen="false" :webview-styles="{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: '#fff'
|
||||
}" :src="state.url" />
|
||||
<web-view class="mall-web-view" :update-title="false" :fullscreen="false" @load="handleWebViewLoad"
|
||||
@error="handleWebViewError" :webview-styles="{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: '#fff'
|
||||
}" :src="state.url" />
|
||||
</crud-layout>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mall-web-view {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -33,8 +33,18 @@ function normalizeMallUrl(rawUrl: string) {
|
||||
|
||||
const [, origin, rawPathname = "/", search = "", hash = ""] = matched
|
||||
const queryItems = search.slice(1).split("&").filter(Boolean)
|
||||
const queryKeys = queryItems.map((item) => decodeURIComponent(item.split("=")[0] || ""))
|
||||
const hasToken = queryItems.some((item) => /^token=.+/i.test(item))
|
||||
const decodeQueryPart = (value: string) => {
|
||||
try {
|
||||
return decodeURIComponent(value)
|
||||
} catch {
|
||||
return value
|
||||
}
|
||||
}
|
||||
const queryKeys = queryItems.map((item) => decodeQueryPart(item.split("=")[0] || ""))
|
||||
const hasToken = queryItems.some((item) => {
|
||||
const [key, ...valueParts] = item.split("=")
|
||||
return decodeQueryPart(key || "").toLowerCase() === "token" && valueParts.join("=")
|
||||
})
|
||||
let pathname = rawPathname
|
||||
|
||||
// 宁波银行正常登录页是 /h5/thirdApp;部分环境会错误返回带 token 的根路径。
|
||||
@@ -51,7 +61,22 @@ function normalizeMallUrl(rawUrl: string) {
|
||||
if (pathname === "/" || !hasToken) {
|
||||
throw new Error("商城登录地址异常,请联系管理员")
|
||||
}
|
||||
return `${origin}${pathname}${search}${hash}`
|
||||
|
||||
// 宁波银行 H5 通过 platform 判断是否运行在微信小程序中。设置为 XR 后,
|
||||
// H5 左上角返回按钮会调用 wx.miniProgram.navigateBack(),直接返回小程序上一页,
|
||||
// 不会先消耗宁波银行 H5 自己的 history。覆盖旧值,避免后端返回其他平台参数。
|
||||
const queryWithoutPlatform = queryItems.filter((item) => {
|
||||
const key = decodeQueryPart(item.split("=")[0] || "").toLowerCase()
|
||||
return key !== "platform"
|
||||
})
|
||||
queryWithoutPlatform.push("platform=XR")
|
||||
const normalizedSearch = `?${queryWithoutPlatform.join("&")}`
|
||||
console.log("[happyMall] 跳转平台:", {
|
||||
platform: "XR",
|
||||
queryKeys: queryWithoutPlatform.map((item) => decodeQueryPart(item.split("=")[0] || "")),
|
||||
})
|
||||
|
||||
return `${origin}${pathname}${normalizedSearch}${hash}`
|
||||
}
|
||||
|
||||
onLoad(async () => {
|
||||
|
||||
@@ -93,6 +93,10 @@ function initBackStyle() {
|
||||
function tabbarChange(index: number) {
|
||||
const target = tabbarStore.tabbarList[index]
|
||||
if (!target) return
|
||||
if (target.pagePath === "/pages/root/dashboard") {
|
||||
// 从业务导航返回工作台时,让首页根 Tabbar 同步选中“首页”。
|
||||
tabbarStore.setRootActiveIndex(0)
|
||||
}
|
||||
jump(target.pagePath, {}, 3)
|
||||
}
|
||||
|
||||
|
||||
+65
-12
@@ -118,16 +118,62 @@ const TABBAR_CONSTANT: Array<TabbarItem> = [
|
||||
launchParam: ["integrated"],
|
||||
auth: ["user"],
|
||||
},
|
||||
{
|
||||
pagePath: "/pages/integrated/notice/index",
|
||||
text: "通知公告",
|
||||
iconPath: "/static/tabbar/notice.png",
|
||||
selectedIconPath: "/static/tabbar/notice-select.png",
|
||||
launchParam: ["notice"],
|
||||
auth: ["user"],
|
||||
},
|
||||
{
|
||||
pagePath: "/pages/integrated/feedback/index",
|
||||
text: "意见反馈",
|
||||
iconPath: "/static/tabbar/feedback.png",
|
||||
selectedIconPath: "/static/tabbar/feedback-select.png",
|
||||
launchParam: ["feedback"],
|
||||
auth: ["user"],
|
||||
},
|
||||
{
|
||||
pagePath: "/pages/tabbar/my",
|
||||
text: "我的",
|
||||
iconPath: "/static/tabbar/my.png",
|
||||
selectedIconPath: "/static/tabbar/my-select.png",
|
||||
launchParam: ["canteen", "selfMerchant", "onlineShop", "coopMerchant", "integrated", "prosperityShop", "prosperityShopMchList"],
|
||||
launchParam: [
|
||||
"canteen",
|
||||
"selfMerchant",
|
||||
"onlineShop",
|
||||
"coopMerchant",
|
||||
"integrated",
|
||||
"prosperityShop",
|
||||
"prosperityShopMchList",
|
||||
"notice",
|
||||
"feedback",
|
||||
],
|
||||
auth: ["user", "merchant", "doorAdmin"],
|
||||
},
|
||||
]
|
||||
|
||||
const WORKBENCH_TABBAR_ITEM: TabbarItem = {
|
||||
pagePath: "/pages/root/dashboard",
|
||||
text: "工作台",
|
||||
iconPath: "/static/tabbar/home.png",
|
||||
selectedIconPath: "/static/tabbar/home-select.png",
|
||||
launchParam: [],
|
||||
auth: [],
|
||||
}
|
||||
|
||||
function getTabbarLaunchParam(url?: string) {
|
||||
const launchParam = getLaunchParam(url)
|
||||
if (launchParam) return launchParam
|
||||
if (!url) return ""
|
||||
|
||||
// 常用功能也可能直接配置 Tabbar 页面路径,需要由页面反推出所属业务场景。
|
||||
const pagePath = url.split("?")[0]
|
||||
const tabbarItem = TABBAR_CONSTANT.find((item) => item.pagePath === pagePath)
|
||||
return tabbarItem?.launchParam[0] || ""
|
||||
}
|
||||
|
||||
const defaultRootTabbarList: Array<TabbarItem> = [
|
||||
{
|
||||
pagePath: "/pages/root/dashboard",
|
||||
@@ -166,13 +212,17 @@ export const useTabbarStore = defineStore("tabbarStore", {
|
||||
}),
|
||||
getters: {
|
||||
isDashboardPage(state) {
|
||||
return `/${state.currentRoute}` === "/pages/root/dashboard" || `/${state.currentRoute}` === "/pages/tabbar/my"
|
||||
const currentRoute = state.currentRoute.startsWith("/") ? state.currentRoute : `/${state.currentRoute}`
|
||||
return currentRoute === "/pages/root/dashboard" || currentRoute === "/pages/tabbar/my"
|
||||
},
|
||||
isTabbar(state) {
|
||||
return state.tabbarList.some((item) => item.pagePath === `/${state.currentRoute}`)
|
||||
const currentRoute = state.currentRoute.startsWith("/") ? state.currentRoute : `/${state.currentRoute}`
|
||||
// 工作台只作为业务 Tabbar 的返回入口,进入页面后仍展示首页自己的根 Tabbar。
|
||||
return currentRoute !== WORKBENCH_TABBAR_ITEM.pagePath && state.tabbarList.some((item) => item.pagePath === currentRoute)
|
||||
},
|
||||
activeIndex(state) {
|
||||
return state.tabbarList.findIndex((item) => item.pagePath === `/${state.currentRoute}`)
|
||||
const currentRoute = state.currentRoute.startsWith("/") ? state.currentRoute : `/${state.currentRoute}`
|
||||
return state.tabbarList.findIndex((item) => item.pagePath === currentRoute)
|
||||
},
|
||||
pageTabbarList(state) {
|
||||
return state.tabbarList.map((item) => {
|
||||
@@ -196,22 +246,25 @@ export const useTabbarStore = defineStore("tabbarStore", {
|
||||
},
|
||||
actions: {
|
||||
async componetTabbarList(launchParam?: string) {
|
||||
let _launchParam = ""
|
||||
if (launchParam) {
|
||||
_launchParam = getLaunchParam(launchParam)
|
||||
} else {
|
||||
_launchParam = getLaunchParam()
|
||||
}
|
||||
if (this.launchParam === _launchParam) return
|
||||
const _launchParam = getTabbarLaunchParam(launchParam)
|
||||
const hasMyTabbar = this.tabbarList.some((item) => item.pagePath === "/pages/tabbar/my")
|
||||
const hasWorkbenchTabbar = this.tabbarList.some((item) => item.pagePath === WORKBENCH_TABBAR_ITEM.pagePath)
|
||||
// 热更新或旧状态中可能已有相同场景但尚未加入工作台,此时仍需重新组装。
|
||||
if (this.launchParam === _launchParam && (!hasMyTabbar || hasWorkbenchTabbar)) return
|
||||
const appInfo = await getAppInfo()
|
||||
if (!_launchParam || !appInfo) return
|
||||
const tabbarList: Array<TabbarItem> = []
|
||||
TABBAR_CONSTANT.forEach((item, index) => {
|
||||
TABBAR_CONSTANT.forEach((item) => {
|
||||
const visible = item.launchParam.includes(_launchParam)
|
||||
if (visible) {
|
||||
tabbarList.push(item)
|
||||
}
|
||||
})
|
||||
const myTabbarIndex = tabbarList.findIndex((item) => item.pagePath === "/pages/tabbar/my")
|
||||
if (myTabbarIndex !== -1) {
|
||||
// 仅对带“我的”的业务导航生效,并保证“工作台”紧邻其左侧。
|
||||
tabbarList.splice(myTabbarIndex, 0, WORKBENCH_TABBAR_ITEM)
|
||||
}
|
||||
this.tabbarList = tabbarList
|
||||
this.launchParam = _launchParam
|
||||
},
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
Reference in new issue
Block a user