| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626 |
- <template>
- <view class="controller-page">
- <!-- 简单的loading,用户几乎看不到 -->
- <view class="loading-container">
- <view class="loading-spinner"></view>
- <text class="loading-text">{{ loadingText }}</text>
- </view>
- </view>
- </template>
- <script setup>
- import { ref } from "vue";
- import { onLoad } from "@dcloudio/uni-app";
- import { goToMainTab } from "@/utils/navigation";
- // 响应式数据
- const loadingText = ref("正在处理...");
- // 页面参数
- let pageParams = {};
- /**
- * 页面加载
- */
- onLoad((options) => {
- console.log("🎛️ H5控制器页面加载:", options);
- pageParams = options || {};
- // 打印详细的参数信息
- console.log("📋 接收到的参数:");
- Object.keys(pageParams).forEach((key) => {
- console.log(` ${key}:`, pageParams[key]);
- });
- // 立即执行,减少延迟
- setTimeout(() => {
- executeCommand();
- }, 100);
- });
- /**
- * 执行H5指令
- */
- const executeCommand = async () => {
- try {
- const { action, message, data, source } = pageParams;
- if (!action) {
- showError("缺少action参数");
- return;
- }
- console.log("🎯 执行H5指令:", { action, message, data, source });
- switch (action) {
- case "goBack":
- await handleGoBack();
- break;
- case "scanCode":
- await handleScanCode();
- break;
- case "chooseImage":
- await handleChooseImage();
- break;
- case "chooseFile":
- await handleChooseFile();
- break;
- case "makePhoneCall":
- await handleMakePhoneCall(data);
- break;
- case "getStorage":
- await handleGetStorage(data);
- break;
- case "setStorage":
- await handleSetStorage(data);
- break;
- case "loginSuccess":
- await handleLoginSuccess(data);
- break;
- case "noServiceAuth":
- await handleNoServiceAuth(data);
- break;
- default:
- showError(`未知指令: ${action}`);
- }
- } catch (error) {
- console.error("❌ 执行指令失败:", error);
- showError(`执行失败: ${error.message || "未知错误"}`);
- }
- };
- /**
- * 智能返回(根据来源决定返回位置)
- */
- const handleGoBack = async () => {
- loadingText.value = "正在返回...";
- // 获取当前页面栈
- const pages = getCurrentPages();
- console.log(
- "📚 当前页面栈:",
- pages.map((p) => p.route)
- );
- // 查找webview页面的前一个页面
- let targetTab = "my"; // 默认返回我的
- if (pages.length >= 2) {
- const prevPage = pages[pages.length - 2]; // webview的前一个页面
- if (prevPage && prevPage.route) {
- // 简单映射:根据来源路由推断tab
- if (prevPage.route.includes("todo")) targetTab = "todo";
- else if (prevPage.route.includes("my")) targetTab = "my";
- else if (prevPage.route.includes("statistics")) targetTab = "statistics";
- console.log("🎯 返回到来源tab:", targetTab);
- }
- }
- // 统一回主容器指定tab
- goToMainTab(targetTab);
- };
- /**
- * 扫码
- */
- const handleScanCode = async () => {
- loadingText.value = "打开扫码...";
- uni.scanCode({
- success: (res) => {
- console.log("✅ 扫码成功:", res);
- // 扫码成功,带结果回到H5页面
- const resultData = {
- action: "scanCode",
- success: true,
- result: res.result,
- scanType: res.scanType,
- timestamp: Date.now(),
- };
- returnToH5WithData(resultData);
- },
- fail: (err) => {
- console.error("❌ 扫码失败:", err);
- // 扫码失败,也要回到H5页面
- const resultData = {
- action: "scanCode",
- success: false,
- error: "扫码失败",
- timestamp: Date.now(),
- };
- returnToH5WithData(resultData);
- },
- });
- };
- /**
- * 选择图片
- */
- const handleChooseImage = async () => {
- loadingText.value = "选择图片...";
- uni.chooseImage({
- count: 1,
- success: (res) => {
- console.log("✅ 选择图片成功:", res);
- // 选择图片成功,带结果回到H5页面
- const resultData = {
- action: "chooseImage",
- success: true,
- count: res.tempFilePaths.length,
- paths: res.tempFilePaths,
- timestamp: Date.now(),
- };
- returnToH5WithData(resultData);
- },
- fail: (err) => {
- console.error("❌ 选择图片失败:", err);
- // 选择图片失败,也要回到H5页面
- const resultData = {
- action: "chooseImage",
- success: false,
- error: "选择图片失败",
- timestamp: Date.now(),
- };
- returnToH5WithData(resultData);
- },
- });
- };
- /**
- * 选择文件
- */
- const handleChooseFile = async () => {
- loadingText.value = "选择文件...";
- // 使用微信小程序的chooseMessageFile API
- uni.chooseMessageFile({
- count: 5, // 最多选择5个文件
- type: "all", // 所有文件类型:image、video、file
- success: (res) => {
- console.log("✅ 选择文件成功:", res);
- // 选择文件成功,带结果回到H5页面
- const resultData = {
- action: "chooseFile",
- success: true,
- count: res.tempFiles.length,
- paths: res.tempFiles.map((file) => file.path),
- files: res.tempFiles.map((file) => ({
- name: file.name,
- size: file.size,
- type: file.type,
- path: file.path,
- })),
- timestamp: Date.now(),
- };
- returnToH5WithData(resultData);
- },
- fail: (err) => {
- console.error("❌ 选择文件失败:", err);
- // 选择文件失败,也要回到H5页面
- const resultData = {
- action: "chooseFile",
- success: false,
- error: "选择文件失败",
- timestamp: Date.now(),
- };
- returnToH5WithData(resultData);
- },
- });
- };
- /**
- * 拨打电话
- */
- const handleMakePhoneCall = async (data) => {
- loadingText.value = "拨打电话...";
- try {
- const phoneData = data ? JSON.parse(decodeURIComponent(data)) : {};
- if (phoneData.phoneNumber) {
- uni.makePhoneCall({
- phoneNumber: phoneData.phoneNumber,
- success: () => {
- const resultData = {
- action: "makePhoneCall",
- success: true,
- phoneNumber: phoneData.phoneNumber,
- timestamp: Date.now(),
- };
- returnToH5WithData(resultData);
- },
- fail: (err) => {
- const resultData = {
- action: "makePhoneCall",
- success: false,
- error: "拨打电话失败",
- timestamp: Date.now(),
- };
- returnToH5WithData(resultData);
- },
- });
- } else {
- showError("电话号码参数错误");
- }
- } catch (error) {
- console.error("解析电话数据失败:", error);
- showError("电话参数解析失败");
- }
- };
- /**
- * 获取存储
- */
- const handleGetStorage = async (data) => {
- loadingText.value = "获取数据...";
- try {
- const storageData = data ? JSON.parse(decodeURIComponent(data)) : {};
- if (storageData.key) {
- const value = uni.getStorageSync(storageData.key);
- const resultData = {
- action: "getStorage",
- success: true,
- key: storageData.key,
- value: value,
- found: !!value,
- timestamp: Date.now(),
- };
- returnToH5WithData(resultData);
- } else {
- showError("获取参数错误");
- }
- } catch (error) {
- console.error("解析存储数据失败:", error);
- showError("存储参数解析失败");
- }
- };
- /**
- * 存储数据
- */
- const handleSetStorage = async (data) => {
- loadingText.value = "存储数据...";
- try {
- const storageData = data ? JSON.parse(decodeURIComponent(data)) : {};
- if (storageData.key && storageData.value !== undefined) {
- uni.setStorageSync(storageData.key, storageData.value);
- const resultData = {
- action: "setStorage",
- success: true,
- key: storageData.key,
- value: storageData.value,
- timestamp: Date.now(),
- };
- returnToH5WithData(resultData);
- } else {
- showError("存储参数错误");
- }
- } catch (error) {
- console.error("解析存储数据失败:", error);
- showError("存储参数解析失败");
- }
- };
- /**
- * 处理登录成功
- */
- const handleLoginSuccess = async (data) => {
- loadingText.value = "处理登录结果...";
- try {
- const loginData = data ? JSON.parse(decodeURIComponent(data)) : {};
- if (loginData.success && loginData.userInfo) {
- // 保存用户信息到小程序存储
- if (loginData.userInfo) {
- uni.setStorageSync("userInfo", loginData.userInfo);
- }
- // 保存JSESSIONID
- if (loginData.userInfo.sessId) {
- uni.setStorageSync("JSESSIONID", loginData.userInfo.sessId);
- }
- // 触发登录事件,通知其他页面
- uni.$emit("login", loginData.userInfo);
- console.log("📢 已触发登录事件");
- // 根据登录类型显示不同提示
- const isAutoLogin = loginData.isAutoLogin;
- const toastTitle = isAutoLogin ? "自动登录成功" : "登录成功";
- const delay = isAutoLogin ? 1000 : 2000; // 自动登录延迟更短
- console.log(
- "🔐 处理登录成功数据:",
- loginData,
- "是自动登录吗",
- isAutoLogin
- );
- uni.showToast({
- title: toastTitle,
- icon: "success",
- duration: delay,
- });
- // 延迟返回
- setTimeout(() => {
- if (isAutoLogin) {
- // 自动登录成功,直接返回到原页面(跳过webview和h5-controller)
- console.log("🎯 自动登录成功,返回原页面");
- uni.navigateBack({
- delta: 2, // 返回2层:h5-controller -> webview -> 原页面
- success: () => {
- console.log("✅ 已返回原页面");
- },
- fail: (err) => {
- console.log("⚠️ 返回原页面失败:", err);
- // 返回失败,重启到主容器首页(默认第一个页签)
- uni.reLaunch({
- url: "/pages/main/index",
- });
- },
- });
- } else {
- // 普通登录成功,重启到主容器首页(默认第一个页签)
- console.log("🎯 登录成功,返回主容器首页");
- uni.reLaunch({
- url: "/pages/main/index",
- });
- }
- }, delay);
- } else {
- console.error("❌ 登录数据无效:", loginData);
- showError("登录数据无效");
- }
- } catch (error) {
- console.error("❌ 处理登录数据失败:", error);
- showError("登录数据处理失败: " + error.message);
- }
- };
- /**
- * 处理没有服务授权
- */
- const handleNoServiceAuth = async (data) => {
- loadingText.value = "处理授权错误...";
- try {
- const authData = data ? JSON.parse(decodeURIComponent(data)) : {};
- console.log("🚫 处理没有服务授权:", authData);
- // 显示错误提示
- uni.showToast({
- title: "没有服务授权",
- icon: "error",
- duration: 2000,
- });
- // 延迟一下让用户看到提示,然后返回
- setTimeout(() => {
- handleGoBack();
- }, 2000);
- } catch (error) {
- console.error("❌ 处理授权错误失败:", error);
- // 出错也要返回
- handleGoBack();
- }
- };
- /**
- * 显示错误并返回
- */
- const showError = (message) => {
- console.error("❌ 控制器错误:", message);
- // 错误也要返回H5页面
- const resultData = {
- success: false,
- error: message,
- timestamp: Date.now(),
- };
- returnToH5WithData(resultData);
- };
- /**
- * 带数据返回H5页面
- */
- const returnToH5WithData = (data) => {
- try {
- // 构建带数据的H5页面URL
- const { source } = pageParams;
- console.log("🔄 带数据返回H5:", data);
- // 手动构建URL参数,避免URLSearchParams
- const encodedData = encodeURIComponent(JSON.stringify(data));
- const webviewUrl = `/pages/common/webview?dest=${
- source || "home"
- }&result=${encodedData}`;
- console.log("🔗 跳转URL:", webviewUrl);
- // 重新加载webview页面,传递新的URL
- uni.redirectTo({
- url: webviewUrl,
- success: () => {
- console.log("✅ 返回H5成功");
- },
- fail: (err) => {
- console.error("❌ 返回H5失败:", err);
- // 如果失败,直接返回
- uni.navigateBack();
- },
- });
- } catch (error) {
- console.error("❌ 返回H5数据处理失败:", error);
- // 任何错误都要回到H5页面
- uni.navigateBack();
- }
- };
- </script>
- <style scoped lang="scss">
- .controller-page {
- min-height: 100vh;
- background: #f5f5f5;
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 40rpx;
- }
- .loading-container {
- text-align: center;
- color: white;
- }
- .loading-spinner {
- width: 80rpx;
- height: 80rpx;
- border: 6rpx solid rgba(255, 255, 255, 0.3);
- border-top: 6rpx solid white;
- border-radius: 50%;
- animation: spin 1s linear infinite;
- margin: 0 auto 32rpx;
- }
- @keyframes spin {
- 0% {
- transform: rotate(0deg);
- }
- 100% {
- transform: rotate(360deg);
- }
- }
- .loading-text {
- font-size: 32rpx;
- color: white;
- }
- .result-container {
- background: white;
- border-radius: 24rpx;
- padding: 48rpx;
- max-width: 600rpx;
- width: 100%;
- box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.1);
- }
- .result-header {
- text-align: center;
- margin-bottom: 32rpx;
- }
- .result-title {
- display: block;
- font-size: 36rpx;
- font-weight: bold;
- color: #333;
- margin-bottom: 16rpx;
- }
- .result-subtitle {
- display: block;
- font-size: 28rpx;
- color: #666;
- }
- .result-data {
- background: #f8f9fa;
- border-radius: 12rpx;
- padding: 24rpx;
- margin-bottom: 32rpx;
- }
- .data-title {
- display: block;
- font-size: 28rpx;
- font-weight: 500;
- color: #333;
- margin-bottom: 16rpx;
- }
- .data-content {
- display: block;
- font-size: 24rpx;
- color: #666;
- white-space: pre-wrap;
- font-family: monospace;
- }
- .action-buttons {
- display: flex;
- gap: 24rpx;
- }
- .btn {
- flex: 1;
- height: 88rpx;
- border-radius: 12rpx;
- font-size: 28rpx;
- border: none;
- color: white;
- }
- .btn.primary {
- background: #007aff;
- }
- .btn.secondary {
- background: #6c757d;
- }
- </style>
|