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' {
export interface GlobalComponents {
AppTabbar: typeof import('./src/components/AppTabbar.vue')['default']
IndexNav: typeof import('./src/components/indexNav.vue')['default']
NutCell: typeof import('@nutui/nutui-taro')['Cell']
NutCellGroup: typeof import('@nutui/nutui-taro')['CellGroup']
NutIcon: typeof import('@nutui/nutui-taro')['Icon']
NutTabbar: typeof import('@nutui/nutui-taro')['Tabbar']
NutTabbarItem: typeof import('@nutui/nutui-taro')['TabbarItem']
Picker: typeof import('./src/components/time-picker-data/picker.vue')['default']
......
......@@ -42,10 +42,18 @@
<button class="primary-btn" @tap="goToMapGuide">打开地图导览</button>
</view>
<view class="webview-entry-card">
<text class="section-label">模拟 WebView</text>
<text class="webview-entry-desc">
这里提供一个首页直达的测试 WebView 入口,用于验证通用 WebView 承载能力。
</text>
<button class="outline-btn" @tap="goToMockWebview">打开模拟 WebView</button>
</view>
<view class="test-entry-card">
<text class="section-label">测试入口</text>
<text class="test-entry-desc">
支付测试与 WebView 预览已移入测试中心,首页只保留统一入口
支付测试等调试能力仍统一收口到测试中心,方便集中联调
</text>
<button class="outline-btn" @tap="goToTestCenter">进入测试中心</button>
</view>
......@@ -60,6 +68,10 @@ import { ref } from 'vue'
import Taro, { useDidShow } from '@tarojs/taro'
import AppTabbar from '@/components/AppTabbar.vue'
import { hasAuth } from '@/utils/authRedirect'
import { buildWebviewPreviewUrl } from '@/utils/webview'
const mock_webview_url = 'https://oa-dev.onwall.cn/f/futian_home/?f=f&p=futian_list'
const mock_webview_title = '福田首页'
const isAuthed = ref(false)
......@@ -73,6 +85,12 @@ const goToMapGuide = () => {
})
}
const goToMockWebview = () => {
Taro.navigateTo({
url: buildWebviewPreviewUrl(mock_webview_url, mock_webview_title),
})
}
const goToTestCenter = () => {
Taro.navigateTo({
url: '/pages/pay-test/index',
......@@ -100,6 +118,7 @@ useDidShow(() => {
.status-card,
.overview-card,
.map-entry-card,
.webview-entry-card,
.test-entry-card {
background: rgba(255, 255, 255, 0.94);
border: 2rpx solid rgba(166, 121, 57, 0.08);
......@@ -154,6 +173,7 @@ useDidShow(() => {
.status-text,
.card-desc,
.map-entry-desc,
.webview-entry-desc,
.test-entry-desc {
display: block;
margin-top: 12rpx;
......@@ -200,6 +220,7 @@ useDidShow(() => {
}
.map-entry-card,
.webview-entry-card,
.test-entry-card {
margin-top: 24rpx;
padding: 32rpx;
......
......@@ -67,6 +67,10 @@
import { ref, watch } from 'vue'
import Taro, { useDidShow, useLoad } from '@tarojs/taro'
import { useWechatMiniPay } from '@/composables/useWechatMiniPay'
import { buildWebviewPreviewUrl } from '@/utils/webview'
const pay_bridge_preview_url = 'https://oa-dev.onwall.cn/f/map/#/weapp-pay-bridge'
const pay_bridge_preview_title = '支付桥预览'
const order_id = ref('')
const should_auto_pay = ref(false)
......@@ -105,7 +109,7 @@ const handleRefreshAuth = async () => {
const goToWebviewPreview = () => {
Taro.navigateTo({
url: '/pages/webview-preview/index',
url: buildWebviewPreviewUrl(pay_bridge_preview_url, pay_bridge_preview_title),
})
}
......
<template>
<web-view :src="preview_url" />
<web-view v-if="preview_url" :src="preview_url" />
<view v-else class="webview-preview-page">
<view class="empty-card">
<text class="empty-title">缺少预览地址</text>
<text class="empty-desc">
当前页面没有收到可用的 URL,请从业务入口重新进入。
</text>
</view>
</view>
</template>
<script setup>
const preview_url = 'https://oa-dev.onwall.cn/f/map/#/weapp-pay-bridge'
import { ref } from 'vue'
import Taro, { useLoad } from '@tarojs/taro'
import { parseWebviewRouteParam, parseWebviewRouteUrl } from '@/utils/webview'
const preview_url = ref('')
const default_page_title = 'WebView 预览'
useLoad((options) => {
preview_url.value = parseWebviewRouteUrl(options?.url)
const page_title = parseWebviewRouteParam(options?.title) || default_page_title
Taro.setNavigationBarTitle({
title: page_title,
})
if (!preview_url.value) {
Taro.showToast({
title: '缺少预览地址',
icon: 'none',
})
}
})
</script>
<style lang="less">
.webview-preview-page {
min-height: 100vh;
padding: 32rpx 24rpx;
box-sizing: border-box;
background:
radial-gradient(circle at top right, rgba(166, 121, 57, 0.16), transparent 30%),
linear-gradient(180deg, #fffaf3 0%, #f6f7fb 100%);
}
.empty-card {
background: rgba(255, 255, 255, 0.94);
border: 2rpx solid rgba(166, 121, 57, 0.08);
border-radius: 28rpx;
padding: 32rpx;
box-sizing: border-box;
box-shadow: 0 20rpx 60rpx rgba(15, 23, 42, 0.06);
}
.empty-title {
display: block;
font-size: 36rpx;
font-weight: 700;
color: #111827;
}
.empty-desc {
display: block;
margin-top: 16rpx;
font-size: 26rpx;
line-height: 1.7;
color: #6b7280;
}
</style>
......
export const buildWebviewPreviewUrl = (target_url = '', page_title = '') => {
const normalized_url = String(target_url || '').trim()
const normalized_title = String(page_title || '').trim()
if (!normalized_url) {
return '/pages/webview-preview/index'
}
const query_list = [`url=${encodeURIComponent(normalized_url)}`]
if (normalized_title) {
query_list.push(`title=${encodeURIComponent(normalized_title)}`)
}
return `/pages/webview-preview/index?${query_list.join('&')}`
}
export const parseWebviewRouteParam = (route_value = '') => {
const normalized_route_value = String(route_value || '').trim()
if (!normalized_route_value) {
return ''
}
try {
return decodeURIComponent(normalized_route_value)
} catch (error) {
return normalized_route_value
}
}
export const parseWebviewRouteUrl = (route_url = '') => parseWebviewRouteParam(route_url)