123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- import { appConstant } from "@/app";
- import {
- SceneTypeDesc,
- SceneTypeDomain,
- SceneTypePaths,
- } from "@/constant/scene";
- import { alert } from "@/helper/message";
- import { getCaseSceneList, getSyncSceneInfo } from "@/store/case";
- import { CaseTagging } from "@/store/caseTagging";
- import { ModelScene, QuoteScene, Scene, SceneType } from "@/store/scene";
- import { transformSWToken, user } from "@/store/user";
- import { base64ToBlob, drawImage } from "@/util";
- import { ref, watchEffect } from "vue";
- export type MenuItem = {
- key: string;
- label: string;
- onClick: (caseId: number) => void;
- };
- export const getFuseCodeLink = (caseId: number, query?: boolean) => {
- const params: { token?: string; caseId: string; app: string } = {
- caseId: caseId.toString(),
- app: appConstant.deptId.toString(),
- };
- if (!query) {
- params.token = user.value.token;
- }
- const url = new URL(
- SceneTypePaths[SceneType.SWMX][0],
- SceneTypeDomain[SceneType.SWMX]
- );
- for (const [name, val] of Object.entries(params)) {
- url.searchParams.append(name, val || "");
- }
- return url.href;
- };
- export const getSWKKSyncLink = async (caseId: number) => {
- const scenes = await getCaseSceneList(caseId);
- const supportTypes = [
- SceneType.SWKK,
- SceneType.SWKJ,
- SceneType.SWSSMX,
- SceneType.SWYDMX,
- ];
- const kkScenes = scenes.filter((scene) =>
- supportTypes.includes(scene.type)
- ) as QuoteScene[];
- let msg: string | null = null;
- if (!scenes.length) {
- msg = "当前案件下无场景,请先添加场景。";
- } else if (!kkScenes.length) {
- msg = `带看仅支持${supportTypes
- .map((type) => SceneTypeDesc[type])
- .join("、")}类型场景,请添加此类型场景。`;
- }
- if (msg) {
- alert(msg);
- throw msg;
- }
- const url = new URL(
- SceneTypePaths[SceneType.SWKK][2],
- SceneTypeDomain[SceneType.SWKK]
- );
- const roomId = await getSyncSceneInfo(caseId);
- const params = {
- vruserId: user.value.info.userName,
- // platform: "fd",
- roomId,
- // domain: location.href,
- // fromMiniApp: "0",
- role: "leader",
- avatar: user.value.info.avatar,
- redirect: encodeURIComponent(location.href),
- name: user.value.info.userName,
- // isTour: "0",
- m: kkScenes[0].num,
- };
- for (const [name, val] of Object.entries(params)) {
- url.searchParams.append(name, val || "");
- }
- return url;
- };
- export const checkScenesOpen = async (caseId: number, url: URL | string) => {
- const scenes = await getCaseSceneList(caseId);
- if (!scenes.length) {
- alert("当前案件下无场景,请先添加场景。");
- } else {
- window.open(url);
- }
- };
- export const getQuery = (
- caseId: number,
- share: boolean = false,
- single: boolean = false
- ) =>
- `${getFuseCodeLink(caseId, true)}${share ? "&share=1" : ""}${
- single ? "&single=1" : ""
- }#show/summary`;
- // 查看
- export const gotoQuery = (caseId: number) => {
- checkScenesOpen(caseId, getQuery(caseId, true));
- };
- export enum FuseImageType {
- FUSE,
- KANKAN,
- LASER,
- }
- export const getSceneIframe = (iframe: HTMLIFrameElement) => {
- const iframeElement = iframe.contentWindow?.document.documentElement;
- if (!iframeElement) {
- return null;
- }
- const extIframe = iframeElement.querySelector(
- ".external"
- ) as HTMLIFrameElement;
- return extIframe || iframe;
- };
- export const getIframeSceneType = async (iframe: HTMLIFrameElement) => {
- const targetIframe = getSceneIframe(iframe);
- if (!targetIframe) {
- return null;
- }
- const targetWindow: any = targetIframe.contentWindow;
- const fuseCnavas = targetWindow.document.querySelector(
- ".scene-canvas > canvas"
- ) as HTMLElement;
- if (fuseCnavas) {
- return { type: FuseImageType.FUSE, sdk: targetWindow.sdk };
- }
- const isLaser = targetWindow.document.querySelector(".laser-layer");
- return {
- type: isLaser ? FuseImageType.LASER : FuseImageType.KANKAN,
- sdk: await targetWindow.__sdk,
- };
- };
- // 处理融合iframe页面
- export const fuseIframeHandler = (iframe: HTMLIFrameElement) => {
- const currentType = ref<FuseImageType>();
- const interval = setInterval(async () => {
- const typeMap = await getIframeSceneType(iframe);
- currentType.value = typeMap?.type;
- }, 100);
- const stopWatch = watchEffect((onCleanup) => {
- // if (currentType.value === FuseImageType.LASER) {
- // const $iframe = getSceneIframe(iframe)!;
- // const target = $iframe.contentWindow!.document.head;
- // const $style = document.createElement("style");
- // $style.type = "text/css";
- // var textNode = document.createTextNode(`
- // .mode-tab > .model-mode-tab.strengthen {
- // display: none
- // }
- // `);
- // $style.appendChild(textNode);
- // target.appendChild($style);
- // }
- });
- return () => {
- clearInterval(interval);
- stopWatch();
- };
- };
- // 获取fuse场景截图
- export type FuseImageRet = { type: FuseImageType; blob: Blob | null };
- export const getFuseImage = async (
- iframe: HTMLIFrameElement,
- width: number = 500,
- height: number = width
- ) => {
- const typeMap = await getIframeSceneType(iframe);
- let blob: Blob | null = null;
- switch (typeMap?.type) {
- case FuseImageType.FUSE:
- const dataURL = await typeMap.sdk.screenshot(width, height);
- const res = await fetch(dataURL);
- blob = await res.blob();
- break;
- case FuseImageType.KANKAN:
- const result = await typeMap.sdk.Camera.screenshot(
- [{ width: width, height: width, name: "2k" }],
- false
- );
- blob = base64ToBlob(result[0].data);
- break;
- case FuseImageType.LASER:
- blob = await new Promise<Blob | null>((resolve) => {
- typeMap.sdk.scene
- .screenshot(width, height)
- .done((data: { dataUrl: string }) =>
- resolve(base64ToBlob(data.dataUrl))
- );
- });
- break;
- }
- return { type: typeMap?.type, blob };
- };
- // 处理fuse融合一起的图,将热点加入图片内
- export const fuseImageJoinHot = async (
- iframe: HTMLIFrameElement,
- rawBlob: Blob,
- showTags: CaseTagging[],
- width = 500
- ) => {
- // fuse场景需要特别处理
- const img = new Image();
- img.src = URL.createObjectURL(rawBlob);
- await new Promise((resolve) => (img.onload = resolve));
- const $canvas = document.createElement("canvas");
- $canvas.width = img.width;
- $canvas.height = img.height;
- const ctx = $canvas.getContext("2d")!;
- ctx.drawImage(img, 0, 0, img.width, img.height);
- const contentDoc = iframe.contentWindow!.document;
- const hotItems = Array.from(
- contentDoc.querySelectorAll(".hot-item")
- ) as HTMLDivElement[];
- hotItems.forEach((hot) => {
- const hotTitle = (hot.querySelector(".tip") as HTMLDivElement).innerText;
- const index = showTags.findIndex(
- (tag) => tag.tagTitle.trim() === hotTitle.trim()
- );
- if (index !== -1) {
- const bound = hot.getBoundingClientRect();
- const size = (img.width / width) * 32;
- const left = bound.left + size / 2;
- const top = bound.top + size / 2;
- ctx.save();
- ctx.translate(left, top);
- ctx.beginPath();
- ctx.arc(0, 0, size / 2, 0, 2 * Math.PI);
- ctx.strokeStyle = "#000";
- ctx.fillStyle = "#fff";
- ctx.stroke();
- ctx.fill();
- ctx.beginPath();
- ctx.fillStyle = "#000";
- ctx.textAlign = "center";
- ctx.textBaseline = "middle";
- ctx.font = `normal ${size / 2}px serif`;
- ctx.fillText((index + 1).toString(), 0, 0);
- ctx.restore();
- }
- });
- const $ccanvas = document.createElement("canvas");
- $ccanvas.width = width;
- $ccanvas.height = width;
- const cctx = $ccanvas.getContext("2d")!;
- drawImage(
- cctx,
- $ccanvas.width,
- $ccanvas.height,
- $canvas,
- img.width,
- img.height,
- 0,
- 0
- );
- const blob = await new Promise<Blob | null>((resolve) =>
- $ccanvas.toBlob(resolve, "png")
- );
- return blob;
- };
- export enum OpenType {
- query,
- edit,
- }
- export const openSceneUrl = async (scene: Scene, type: OpenType) => {
- const pathname = SceneTypePaths[scene.type][type];
- const url = new URL(pathname || "", window.location.href);
- if (scene.type === SceneType.SWMX) {
- url.searchParams.append(
- "modelId",
- (scene as ModelScene).modelId.toString()
- );
- url.hash = "#sign-model";
- url.searchParams.append("share", "1");
- url.searchParams.append("app", appConstant.deptId.toString());
- } else {
- url.searchParams.append("m", (scene as QuoteScene).num);
- if (type === OpenType.edit) {
- url.searchParams.append(
- "token",
- await transformSWToken(scene as QuoteScene)
- );
- }
- }
- window.open(url);
- };
|