chore: initialize qiming workspace repository
This commit is contained in:
@@ -0,0 +1,319 @@
|
||||
<template>
|
||||
<view class="container page-container">
|
||||
<!-- 导航栏 -->
|
||||
<custom-nav-bar :title="fileName" show-back>
|
||||
<template v-slot:right>
|
||||
<!-- #ifdef H5 || WEB -->
|
||||
<text
|
||||
class="iconfont icon-ShareAltOutlined font-48"
|
||||
@click="handleShare"
|
||||
></text>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
</custom-nav-bar>
|
||||
|
||||
<view class="file-preview-content">
|
||||
<!-- 加载中 -->
|
||||
<!-- <template v-if="isLoading">
|
||||
<view class="loading-box">
|
||||
<image
|
||||
class="icon-loading-image"
|
||||
src="@/static/assets/icon_loading.svg"
|
||||
mode="widthFix"
|
||||
/>
|
||||
</view>
|
||||
</template> -->
|
||||
|
||||
<!-- Web-View 预览 -->
|
||||
<template v-if="previewUrl">
|
||||
<!-- #ifdef H5 || WEB -->
|
||||
<iframe
|
||||
class="w-full h-full"
|
||||
frameborder="0"
|
||||
:src="previewUrl"
|
||||
></iframe>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<web-view
|
||||
class="w-full h-full"
|
||||
:src="previewUrl"
|
||||
id="webview"
|
||||
></web-view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { onAddToFavorites } from "@dcloudio/uni-app";
|
||||
import {
|
||||
parseUrlInfo,
|
||||
getFileName,
|
||||
} from "@/subpackages/utils/parseUrlInfo.uts";
|
||||
import { useI18n } from "@/utils/i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
// 请求工具
|
||||
import {
|
||||
apiUserTicketCreate,
|
||||
apiAgentConversationShare,
|
||||
} from "@/servers/agentDev.uts";
|
||||
import { SUCCESS_CODE } from "@/constants/codes.constants";
|
||||
|
||||
// 环境配置
|
||||
import { API_BASE_URL } from "@/constants/config";
|
||||
|
||||
const previewUrl = ref<string>(""); // 预览地址
|
||||
const fileName = ref<string>(""); // 文件名
|
||||
const pageTitle = ref<string>(""); // 页面标题
|
||||
const fileType = ref<string>(""); // 文件类型
|
||||
|
||||
const isLoading = ref<boolean>(true); // 是否加载中
|
||||
const conversationId = ref<string>(null); // 会话ID
|
||||
const fileProxyUrl = ref<string>(""); // 文件路径
|
||||
const sk = ref<string>(""); // sk 微信小程序中需要 sk 查询参数
|
||||
const isDev = process.env.NODE_ENV === "development";
|
||||
|
||||
let baseUrl = "";
|
||||
// #ifdef H5 || WEB
|
||||
baseUrl = isDev ? API_BASE_URL : window?.location?.origin;
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
baseUrl = API_BASE_URL;
|
||||
// #endif
|
||||
|
||||
/**
|
||||
* 获取 shareKey
|
||||
*/
|
||||
const getConversationShareKey = async (
|
||||
conversationId: string,
|
||||
content: string = "",
|
||||
): Promise<string> => {
|
||||
const params = {
|
||||
conversationId,
|
||||
type: "CONVERSATION",
|
||||
content,
|
||||
};
|
||||
|
||||
const { data, code } = await apiAgentConversationShare(params);
|
||||
|
||||
if (code !== SUCCESS_CODE || !data?.shareKey) {
|
||||
throw new Error(t("Mobile.FilePreview.getShareKeyFailed"));
|
||||
}
|
||||
|
||||
return data.shareKey;
|
||||
};
|
||||
|
||||
// 分享文件
|
||||
const handleShare = async () => {
|
||||
if (!baseUrl) {
|
||||
uni.showToast({
|
||||
title: t("Mobile.FilePreview.shareDomainMissing"),
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const shareKey = await getConversationShareKey(
|
||||
conversationId.value,
|
||||
fileProxyUrl.value || "",
|
||||
);
|
||||
|
||||
const previewUrlValue = `${baseUrl}/static/file-preview.html?sk=${shareKey}`;
|
||||
|
||||
// 复制到剪切板
|
||||
uni.setClipboardData({
|
||||
data: previewUrlValue,
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: t("Mobile.FilePreview.shareSuccess"),
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
},
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: t("Mobile.FilePreview.shareFailed"),
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("分享失败:", error);
|
||||
uni.showToast({
|
||||
title: t("Mobile.FilePreview.shareFailed"),
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 获取 ticket
|
||||
const getTicket = async () => {
|
||||
try {
|
||||
const { code, data } = await apiUserTicketCreate();
|
||||
|
||||
return code === SUCCESS_CODE && data ? data : "";
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
// 设置 html 文件标题
|
||||
const setHtmlTitle = (url: string) => {
|
||||
uni.request({
|
||||
url,
|
||||
method: "GET",
|
||||
success: (res) => {
|
||||
const data = res.data;
|
||||
// 使用正则表达式提取 <title>...</title> 中的内容
|
||||
const match = data.match(/<title[^>]*>([^<]+)<\/title>/i);
|
||||
if (match && match[1]) {
|
||||
const title = match[1].trim();
|
||||
// 赋值给 pageTitle
|
||||
pageTitle.value = title;
|
||||
// 更新导航栏标题
|
||||
uni.setNavigationBarTitle({
|
||||
title: title,
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error("获取 html 失败", err);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onLoad(async (options: { cId: number; fileProxyUrl: string }) => {
|
||||
let { cId, fileProxyUrl: fileProxyUrlValue } = options;
|
||||
if (!cId || !fileProxyUrlValue) {
|
||||
uni.showToast({
|
||||
title: t("Mobile.FilePreview.invalidParams"),
|
||||
icon: "none",
|
||||
});
|
||||
isLoading.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const { path, query } = parseUrlInfo(decodeURIComponent(fileProxyUrlValue));
|
||||
|
||||
fileProxyUrl.value = path;
|
||||
|
||||
// 得到文件名
|
||||
const fileNameValue = getFileName(path);
|
||||
conversationId.value = cId;
|
||||
fileName.value = fileNameValue;
|
||||
|
||||
uni.setNavigationBarTitle({ title: fileNameValue });
|
||||
|
||||
// 得到文件类型
|
||||
const fileTypeValue = fileNameValue.split(".").pop();
|
||||
fileType.value = fileTypeValue;
|
||||
|
||||
try {
|
||||
if (query?.sk) {
|
||||
// 有 sk 参数,直接使用
|
||||
sk.value = query.sk;
|
||||
previewUrl.value = `${baseUrl}/static/file-preview.html?sk=${query.sk}`;
|
||||
// 设置 html 文件标题
|
||||
setHtmlTitle(baseUrl + fileProxyUrl.value + "?sk=" + query.sk);
|
||||
} else {
|
||||
// 没有 sk 参数,需要获取 shareKey 和 _ticket
|
||||
// 1. 获取 shareKey 用于后续分享功能
|
||||
let shareKey = await getConversationShareKey(cId, path);
|
||||
sk.value = shareKey;
|
||||
const fileUrl = encodeURIComponent(`${fileProxyUrl.value}`);
|
||||
|
||||
// #ifdef H5 || WEB
|
||||
if (isDev) {
|
||||
// _sk 用于下载功能,_ticket 用于当前页面访问(_ticket 只能消费一次,适合当前用户自己访问)
|
||||
const _ticket = await getTicket();
|
||||
previewUrl.value = `${baseUrl}/static/file-preview.html?fileUrl=${baseUrl + fileUrl}&_ticket=${_ticket}&_sk=${shareKey}`;
|
||||
} else {
|
||||
previewUrl.value = `${baseUrl}/static/file-preview.html?fileUrl=${baseUrl + fileUrl}&sk=${shareKey}`;
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// _sk 用于下载功能,_ticket 用于当前页面访问(_ticket 只能消费一次,适合当前用户自己访问)
|
||||
const _ticket = await getTicket();
|
||||
previewUrl.value = `${baseUrl}/static/file-preview.html?fileUrl=${baseUrl + fileUrl}&_ticket=${_ticket}&_sk=${shareKey}`;
|
||||
// 设置 html 文件标题
|
||||
setHtmlTitle(baseUrl + fileProxyUrl.value + "?sk=" + shareKey);
|
||||
// #endif
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("构建预览URL失败:", error);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// 转发给朋友
|
||||
// 分享到首页,由首页自动跳转到文件预览页面,解决分享后无返回按钮问题
|
||||
onShareAppMessage(() => {
|
||||
return {
|
||||
title: pageTitle.value || fileName.value || "",
|
||||
path:
|
||||
"/pages/index/index?cId=" +
|
||||
conversationId.value +
|
||||
"&fileProxyUrl=" +
|
||||
encodeURIComponent(`${fileProxyUrl.value}?sk=${sk.value}`),
|
||||
};
|
||||
});
|
||||
|
||||
// 收藏
|
||||
onAddToFavorites(() => {
|
||||
return {
|
||||
title: pageTitle.value || fileName.value || "",
|
||||
path:
|
||||
"/pages/index/index?cId=" +
|
||||
conversationId.value +
|
||||
"&fileProxyUrl=" +
|
||||
encodeURIComponent(`${fileProxyUrl.value}?sk=${sk.value}`),
|
||||
};
|
||||
});
|
||||
// #endif
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.file-preview-content {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.loading-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
|
||||
.icon-loading-image {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
margin-right: 10rpx;
|
||||
-webkit-touch-callout: none !important;
|
||||
-webkit-user-select: none !important;
|
||||
user-select: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.text-gray-500 {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user