Просмотр исходного кода

feat(miniprogram): add reusable web-view shell for H5 business pages.

Co-authored-by: Cursor <cursoragent@cursor.com>
wuzilong 1 месяц назад
Родитель
Сommit
57a831a36f

+ 6 - 3
miniprogram/config/api.js

@@ -24,7 +24,8 @@ export const AUTH_API = {
   LOGOUT: '/web/auth/logout',
   CURRENT_USER: '/web/auth/current-user',
   REFRESH_TOKEN: '/web/auth/refresh-token',
-  MENU_CODES: '/web/auth/menu-codes'
+  MENU_CODES: '/web/auth/menu-codes',
+  MP_WEBVIEW_TICKET: '/web/auth/mp-webview-ticket'
 }
 
 /**
@@ -69,7 +70,8 @@ export const PAGE_PATHS = {
   plTransportPlan: '/pages/pl/transport-plan/list',
   plTransportPlanDetail: '/pages/pl/transport-plan/detail',
   plDriverPlan: '/pages/pl/driver-plan/list',
-  plDriverPlanDetail: '/pages/pl/driver-plan/detail'
+  plDriverPlanDetail: '/pages/pl/driver-plan/detail',
+  mpWebview: '/pages/common/mp-webview'
 }
 
 /** 工作台菜单 code → 页面路径 */
@@ -89,7 +91,8 @@ export const WORKBENCH_ROUTE_MAP = {
   'bx-wf-reimburse': PAGE_PATHS.bxWfReimburse,
   'pl-fuel-register': PAGE_PATHS.plFuelRegister,
   'pl-transport-plan': PAGE_PATHS.plTransportPlan,
-  'pl-driver-plan': PAGE_PATHS.plDriverPlan
+  'pl-driver-plan': PAGE_PATHS.plDriverPlan,
+  'pl-plan-webview': PAGE_PATHS.mpWebview + '?path=' + encodeURIComponent('/m/pl/plan')
 }
 
 export const TOKEN_KEY = 'sx_token'

+ 8 - 1
miniprogram/config/workbench-menus.js

@@ -56,7 +56,7 @@ export const WORKBENCH_MODULES = [
   {
     key: 'pl',
     title: '运输管理',
-    desc: '加油登记 · 运输计划单 · 司机运输计划单',
+    desc: '加油登记 · 运输计划单 · 运输计划 · 司机运输计划单',
     iconText: '运输',
     visible: true,
     menus: [
@@ -74,6 +74,13 @@ export const WORKBENCH_MODULES = [
         icon: '📋',
         perms: 'mini:pl:transportPlan:list'
       },
+      {
+        name: '运输计划',
+        enabled: true,
+        code: 'pl-plan-webview',
+        icon: '📝',
+        perms: 'mini:pl:plan:manage'
+      },
       {
         name: '司机运输计划单',
         enabled: true,

+ 7 - 0
miniprogram/pages.json

@@ -51,6 +51,13 @@
       "style": {
         "navigationStyle": "custom"
       }
+    },
+    {
+      "path": "pages/common/mp-webview",
+      "style": {
+        "navigationStyle": "custom",
+        "navigationBarTitleText": "运输计划"
+      }
     }
     // #ifdef H5
     ,

+ 74 - 0
miniprogram/pages/common/mp-webview.vue

@@ -0,0 +1,74 @@
+<template>
+  <view class="mp-wv-page">
+    <view v-if="errorText" class="mp-wv-error">{{ errorText }}</view>
+    <web-view v-else-if="src" :src="src" />
+    <view v-else class="mp-wv-error">加载中…</view>
+  </view>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+import { onLoad } from '@dcloudio/uni-app'
+import { AUTH_API, PAGE_PATHS } from '@/config/api'
+import { WEB_ORIGIN } from '@/config/env'
+import { request, parseResponseJson } from '@/utils/request'
+import { useUserStore } from '@/stores/user'
+
+const src = ref('')
+const errorText = ref('')
+
+function isAllowedPath(path) {
+  return typeof path === 'string' && path.startsWith('/m/')
+}
+
+onLoad(async (query) => {
+  const path = decodeURIComponent(String(query?.path || '').trim())
+  if (!isAllowedPath(path)) {
+    errorText.value = '无效地址'
+    uni.showToast({ title: '无效地址', icon: 'none' })
+    setTimeout(() => {
+      uni.navigateBack({
+        fail: () => uni.reLaunch({ url: PAGE_PATHS.workbench })
+      })
+    }, 400)
+    return
+  }
+
+  const userStore = useUserStore()
+  userStore.checkLoginStatus()
+  if (!userStore.isLoggedIn) {
+    uni.reLaunch({ url: PAGE_PATHS.login })
+    return
+  }
+
+  try {
+    const res = await request({
+      url: AUTH_API.MP_WEBVIEW_TICKET,
+      method: 'POST'
+    })
+    const result = parseResponseJson(res)
+    const ticket = result && result.code === 200 ? result.data?.ticket : ''
+    if (!ticket) {
+      throw new Error((result && result.message) || '无法打开内嵌页')
+    }
+    const origin = String(WEB_ORIGIN || '').replace(/\/$/, '')
+    src.value = `${origin}/#${path}?mpTicket=${encodeURIComponent(ticket)}`
+  } catch (error) {
+    errorText.value = (error && error.message) || '无法打开内嵌页'
+    uni.showToast({ title: errorText.value, icon: 'none' })
+  }
+})
+</script>
+
+<style scoped>
+.mp-wv-page {
+  min-height: 100vh;
+  background: #f5f8f7;
+}
+.mp-wv-error {
+  padding: 48px 16px;
+  color: #6b7b74;
+  font-size: 14px;
+  text-align: center;
+}
+</style>