Files
qiming/qiming-mobile/subpackages/pages/webview/webview.uvue

233 lines
6.3 KiB
Plaintext

<template>
<!-- #ifdef H5 || WEB -->
<!-- 自定义导航栏 -->
<custom-nav-bar :title="displayPageTitle">
<template v-slot:left>
<text class="iconfont icon-a-Chevronleft" @tap="onBackClick"></text>
</template>
</custom-nav-bar>
<!-- #endif -->
<web-view
class="web-view page-container"
v-if="url.length != 0"
:src="url"
id="webview"
@error="handleWebviewError"
@load="handleWebviewLoad"
@message="handleWebviewMessage"
></web-view>
</template>
<script lang="uts" setup>
import { computed, ref } from "vue";
import { removeQueryCompat } from "@/utils/common.uts";
import { NO_LOGIN_CHECK_URL } from "@/constants/config";
import { apiUserTicketCreate } from "@/servers/agentDev";
import { SUCCESS_CODE } from "@/constants/codes.constants";
import { onAddToFavorites } from "@dcloudio/uni-app";
import { isHttpUrl } from "@/utils/common.uts";
import { isTabPage } from "@/utils/commonBusiness.uts";
import { useI18n } from "@/utils/i18n";
const { t } = useI18n();
const url = ref("");
const method = ref("");
const data_type = ref("");
const request_id = ref("");
const pageTitle = ref("");
const displayPageTitle = computed(
() => pageTitle.value || t("Mobile.Webview.defaultTitle"),
);
const getQueryParams = (url) => {
const queryString = url.split("?")[1] || "";
const pairs = queryString.split("&");
const params = {};
for (let pair of pairs) {
if (!pair) continue;
const [k, v] = pair.split("=");
params[decodeURIComponent(k)] = decodeURIComponent(v || "");
}
return params;
};
// 判断是否需要调用接口
const isNeedCallApi = computed(() => {
return !!(
method.value === "browser_navigate_page" &&
data_type.value &&
request_id.value
);
});
// WebView 加载错误处理
const handleWebviewError = (e: any) => {
console.error("WebView 加载错误:", e);
uni.showToast({
title: t("Mobile.Webview.loadFailed"),
icon: "none",
duration: 2000,
});
};
// WebView 加载完成
const handleWebviewLoad = (e: any) => {
// #ifdef MP-WEIXIN
if (isNeedCallApi.value) {
uni.showLoading({
title: t("Mobile.Webview.aiReading"),
mask: true,
});
setTimeout(() => {
uni.navigateBack({ delta: 1 });
uni.hideLoading();
}, 4000);
}
// #endif
};
/**
* WebView 消息处理
*
* ⚠️ 重要:微信小程序的 @message 不会实时触发!
* 触发时机:
* 1. 用户点击返回按钮(最常用)
* 2. 组件销毁时
* 3. 分享时
*
* 调试方法:
* 1. 网页发送消息后,点击小程序的返回按钮
* 2. 查看控制台是否有 "收到消息" 日志
* 3. 如果没有,检查网页端代码是否正确调用 wx.miniProgram.postMessage
*/
const handleWebviewMessage = (e: any) => {
// #ifdef MP-WEIXIN
// e.detail.data 是一个数组,包含所有 postMessage 发送的消息
const messages = e.detail.data;
if (isNeedCallApi.value && messages && messages.length > 0) {
// 处理最后一条消息 - 读取首页内容
uni.$emit("browser_navigate_page", {
method: method.value,
data_type: data_type.value,
html: messages[messages.length - 1].html,
request_id: request_id.value,
});
} else {
console.warn("消息数组为空");
}
// #endif
};
/**
* 获取分享链接
*/
const getSharingLink = () => {
const newUrl = removeQueryCompat(url.value, ["_ticket", "jump_type"]);
const andStr = newUrl.includes("?") ? "&" : "?";
const currentUrl = newUrl + andStr + "jump_type=outer";
return encodeURIComponent(currentUrl);
};
const onBackClick = () => {
const backUrl = uni.getStorageSync("backUrl");
// 首页是 tabbar 页面,必须使用 switchTab 跳转
const toUrl = backUrl && backUrl !== "/" ? backUrl : "/pages/index/index";
if (isTabPage(toUrl)) {
uni.switchTab({ url: toUrl });
} else {
uni.redirectTo({ url: toUrl });
}
uni.removeStorageSync("backUrl");
};
// 初始化加载
const onLoadInit = async (params: UTSJSONObject) => {
if (params.url) {
let currentUrl = decodeURIComponent(params.url);
const queryParams = getQueryParams(currentUrl);
// 设置页面标题
const title = queryParams.title || t("Mobile.Webview.defaultTitle");
pageTitle.value = title;
uni.setNavigationBarTitle({
title: title,
});
// #ifdef H5 || WEB
if (isHttpUrl(currentUrl)) {
url.value = currentUrl;
} else {
url.value = window.location.origin + currentUrl;
}
// #endif
// #ifdef MP-WEIXIN
// 判断当前url是否不需要登录检查
if (NO_LOGIN_CHECK_URL.includes(currentUrl)) {
url.value = currentUrl;
return;
}
if (queryParams.method) {
method.value = queryParams.method;
}
if (queryParams.data_type) {
data_type.value = queryParams.data_type;
}
if (queryParams.request_id) {
request_id.value = queryParams.request_id;
}
// 判断是否存在 _ticket
if (queryParams._ticket) {
url.value = currentUrl;
} else {
// 暂存当前url
globalThis.appConfig.redirectUrl = params.url; // 未解码
const ticketResult = await apiUserTicketCreate();
if (ticketResult.code === SUCCESS_CODE && ticketResult.data) {
const andStr = currentUrl.includes("?") ? "&" : "?";
url.value = currentUrl + andStr + `_ticket=${ticketResult.data}`;
}
}
// #endif
}
};
onLoad((params) => {
// 加载初始化数据
onLoadInit(params);
});
// #ifdef MP-WEIXIN
// 转发给朋友
onShareAppMessage(() => {
return {
title:
getQueryParams(url.value)?.["title"] || t("Mobile.Common.appName"),
path: "/subpackages/pages/webview/webview?url=" + getSharingLink(),
};
});
// 收藏
onAddToFavorites(() => {
return {
title:
getQueryParams(url.value)?.["title"] || t("Mobile.Common.appName"),
query: "url=" + getSharingLink(),
};
});
// #endif
</script>
<style lang="scss" scoped>
.web-view {
width: 100%;
}
</style>