hookehuyr

feat: 添加通用webview预览组件并优化入口

新增通用webview预览工具函数和组件,支持动态URL和标题参数传递。移除未使用的NutUI组件类型声明,在首页添加模拟webview测试入口,并优化测试中心描述文案。

- 新增webview.js工具模块,包含URL构建和参数解析函数
- 重构webview-preview页面,支持动态URL和错误状态处理
- 在首页添加模拟webview测试入口,便于验证承载能力
- 移除components.d.ts中未使用的NutUI组件类型声明
- 优化pay-test页面,使用工具函数构建webview预览URL
...@@ -9,9 +9,6 @@ declare module 'vue' { ...@@ -9,9 +9,6 @@ declare module 'vue' {
9 export interface GlobalComponents { 9 export interface GlobalComponents {
10 AppTabbar: typeof import('./src/components/AppTabbar.vue')['default'] 10 AppTabbar: typeof import('./src/components/AppTabbar.vue')['default']
11 IndexNav: typeof import('./src/components/indexNav.vue')['default'] 11 IndexNav: typeof import('./src/components/indexNav.vue')['default']
12 - NutCell: typeof import('@nutui/nutui-taro')['Cell']
13 - NutCellGroup: typeof import('@nutui/nutui-taro')['CellGroup']
14 - NutIcon: typeof import('@nutui/nutui-taro')['Icon']
15 NutTabbar: typeof import('@nutui/nutui-taro')['Tabbar'] 12 NutTabbar: typeof import('@nutui/nutui-taro')['Tabbar']
16 NutTabbarItem: typeof import('@nutui/nutui-taro')['TabbarItem'] 13 NutTabbarItem: typeof import('@nutui/nutui-taro')['TabbarItem']
17 Picker: typeof import('./src/components/time-picker-data/picker.vue')['default'] 14 Picker: typeof import('./src/components/time-picker-data/picker.vue')['default']
......
...@@ -42,10 +42,18 @@ ...@@ -42,10 +42,18 @@
42 <button class="primary-btn" @tap="goToMapGuide">打开地图导览</button> 42 <button class="primary-btn" @tap="goToMapGuide">打开地图导览</button>
43 </view> 43 </view>
44 44
45 + <view class="webview-entry-card">
46 + <text class="section-label">模拟 WebView</text>
47 + <text class="webview-entry-desc">
48 + 这里提供一个首页直达的测试 WebView 入口,用于验证通用 WebView 承载能力。
49 + </text>
50 + <button class="outline-btn" @tap="goToMockWebview">打开模拟 WebView</button>
51 + </view>
52 +
45 <view class="test-entry-card"> 53 <view class="test-entry-card">
46 <text class="section-label">测试入口</text> 54 <text class="section-label">测试入口</text>
47 <text class="test-entry-desc"> 55 <text class="test-entry-desc">
48 - 支付测试与 WebView 预览已移入测试中心,首页只保留统一入口 56 + 支付测试等调试能力仍统一收口到测试中心,方便集中联调
49 </text> 57 </text>
50 <button class="outline-btn" @tap="goToTestCenter">进入测试中心</button> 58 <button class="outline-btn" @tap="goToTestCenter">进入测试中心</button>
51 </view> 59 </view>
...@@ -60,6 +68,10 @@ import { ref } from 'vue' ...@@ -60,6 +68,10 @@ import { ref } from 'vue'
60 import Taro, { useDidShow } from '@tarojs/taro' 68 import Taro, { useDidShow } from '@tarojs/taro'
61 import AppTabbar from '@/components/AppTabbar.vue' 69 import AppTabbar from '@/components/AppTabbar.vue'
62 import { hasAuth } from '@/utils/authRedirect' 70 import { hasAuth } from '@/utils/authRedirect'
71 +import { buildWebviewPreviewUrl } from '@/utils/webview'
72 +
73 +const mock_webview_url = 'https://oa-dev.onwall.cn/f/futian_home/?f=f&p=futian_list'
74 +const mock_webview_title = '福田首页'
63 75
64 const isAuthed = ref(false) 76 const isAuthed = ref(false)
65 77
...@@ -73,6 +85,12 @@ const goToMapGuide = () => { ...@@ -73,6 +85,12 @@ const goToMapGuide = () => {
73 }) 85 })
74 } 86 }
75 87
88 +const goToMockWebview = () => {
89 + Taro.navigateTo({
90 + url: buildWebviewPreviewUrl(mock_webview_url, mock_webview_title),
91 + })
92 +}
93 +
76 const goToTestCenter = () => { 94 const goToTestCenter = () => {
77 Taro.navigateTo({ 95 Taro.navigateTo({
78 url: '/pages/pay-test/index', 96 url: '/pages/pay-test/index',
...@@ -100,6 +118,7 @@ useDidShow(() => { ...@@ -100,6 +118,7 @@ useDidShow(() => {
100 .status-card, 118 .status-card,
101 .overview-card, 119 .overview-card,
102 .map-entry-card, 120 .map-entry-card,
121 + .webview-entry-card,
103 .test-entry-card { 122 .test-entry-card {
104 background: rgba(255, 255, 255, 0.94); 123 background: rgba(255, 255, 255, 0.94);
105 border: 2rpx solid rgba(166, 121, 57, 0.08); 124 border: 2rpx solid rgba(166, 121, 57, 0.08);
...@@ -154,6 +173,7 @@ useDidShow(() => { ...@@ -154,6 +173,7 @@ useDidShow(() => {
154 .status-text, 173 .status-text,
155 .card-desc, 174 .card-desc,
156 .map-entry-desc, 175 .map-entry-desc,
176 + .webview-entry-desc,
157 .test-entry-desc { 177 .test-entry-desc {
158 display: block; 178 display: block;
159 margin-top: 12rpx; 179 margin-top: 12rpx;
...@@ -200,6 +220,7 @@ useDidShow(() => { ...@@ -200,6 +220,7 @@ useDidShow(() => {
200 } 220 }
201 221
202 .map-entry-card, 222 .map-entry-card,
223 + .webview-entry-card,
203 .test-entry-card { 224 .test-entry-card {
204 margin-top: 24rpx; 225 margin-top: 24rpx;
205 padding: 32rpx; 226 padding: 32rpx;
......
...@@ -67,6 +67,10 @@ ...@@ -67,6 +67,10 @@
67 import { ref, watch } from 'vue' 67 import { ref, watch } from 'vue'
68 import Taro, { useDidShow, useLoad } from '@tarojs/taro' 68 import Taro, { useDidShow, useLoad } from '@tarojs/taro'
69 import { useWechatMiniPay } from '@/composables/useWechatMiniPay' 69 import { useWechatMiniPay } from '@/composables/useWechatMiniPay'
70 +import { buildWebviewPreviewUrl } from '@/utils/webview'
71 +
72 +const pay_bridge_preview_url = 'https://oa-dev.onwall.cn/f/map/#/weapp-pay-bridge'
73 +const pay_bridge_preview_title = '支付桥预览'
70 74
71 const order_id = ref('') 75 const order_id = ref('')
72 const should_auto_pay = ref(false) 76 const should_auto_pay = ref(false)
...@@ -105,7 +109,7 @@ const handleRefreshAuth = async () => { ...@@ -105,7 +109,7 @@ const handleRefreshAuth = async () => {
105 109
106 const goToWebviewPreview = () => { 110 const goToWebviewPreview = () => {
107 Taro.navigateTo({ 111 Taro.navigateTo({
108 - url: '/pages/webview-preview/index', 112 + url: buildWebviewPreviewUrl(pay_bridge_preview_url, pay_bridge_preview_title),
109 }) 113 })
110 } 114 }
111 115
......
1 <template> 1 <template>
2 - <web-view :src="preview_url" /> 2 + <web-view v-if="preview_url" :src="preview_url" />
3 + <view v-else class="webview-preview-page">
4 + <view class="empty-card">
5 + <text class="empty-title">缺少预览地址</text>
6 + <text class="empty-desc">
7 + 当前页面没有收到可用的 URL,请从业务入口重新进入。
8 + </text>
9 + </view>
10 + </view>
3 </template> 11 </template>
4 12
5 <script setup> 13 <script setup>
6 -const preview_url = 'https://oa-dev.onwall.cn/f/map/#/weapp-pay-bridge' 14 +import { ref } from 'vue'
15 +import Taro, { useLoad } from '@tarojs/taro'
16 +import { parseWebviewRouteParam, parseWebviewRouteUrl } from '@/utils/webview'
17 +
18 +const preview_url = ref('')
19 +const default_page_title = 'WebView 预览'
20 +
21 +useLoad((options) => {
22 + preview_url.value = parseWebviewRouteUrl(options?.url)
23 + const page_title = parseWebviewRouteParam(options?.title) || default_page_title
24 +
25 + Taro.setNavigationBarTitle({
26 + title: page_title,
27 + })
28 +
29 + if (!preview_url.value) {
30 + Taro.showToast({
31 + title: '缺少预览地址',
32 + icon: 'none',
33 + })
34 + }
35 +})
7 </script> 36 </script>
37 +
38 +<style lang="less">
39 +.webview-preview-page {
40 + min-height: 100vh;
41 + padding: 32rpx 24rpx;
42 + box-sizing: border-box;
43 + background:
44 + radial-gradient(circle at top right, rgba(166, 121, 57, 0.16), transparent 30%),
45 + linear-gradient(180deg, #fffaf3 0%, #f6f7fb 100%);
46 +}
47 +
48 +.empty-card {
49 + background: rgba(255, 255, 255, 0.94);
50 + border: 2rpx solid rgba(166, 121, 57, 0.08);
51 + border-radius: 28rpx;
52 + padding: 32rpx;
53 + box-sizing: border-box;
54 + box-shadow: 0 20rpx 60rpx rgba(15, 23, 42, 0.06);
55 +}
56 +
57 +.empty-title {
58 + display: block;
59 + font-size: 36rpx;
60 + font-weight: 700;
61 + color: #111827;
62 +}
63 +
64 +.empty-desc {
65 + display: block;
66 + margin-top: 16rpx;
67 + font-size: 26rpx;
68 + line-height: 1.7;
69 + color: #6b7280;
70 +}
71 +</style>
......
1 +export const buildWebviewPreviewUrl = (target_url = '', page_title = '') => {
2 + const normalized_url = String(target_url || '').trim()
3 + const normalized_title = String(page_title || '').trim()
4 +
5 + if (!normalized_url) {
6 + return '/pages/webview-preview/index'
7 + }
8 +
9 + const query_list = [`url=${encodeURIComponent(normalized_url)}`]
10 +
11 + if (normalized_title) {
12 + query_list.push(`title=${encodeURIComponent(normalized_title)}`)
13 + }
14 +
15 + return `/pages/webview-preview/index?${query_list.join('&')}`
16 +}
17 +
18 +export const parseWebviewRouteParam = (route_value = '') => {
19 + const normalized_route_value = String(route_value || '').trim()
20 +
21 + if (!normalized_route_value) {
22 + return ''
23 + }
24 +
25 + try {
26 + return decodeURIComponent(normalized_route_value)
27 + } catch (error) {
28 + return normalized_route_value
29 + }
30 +}
31 +
32 +export const parseWebviewRouteUrl = (route_url = '') => parseWebviewRouteParam(route_url)