sync.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. import axios from "@/dbo/main";
  2. import { list } from "@/store/measure";
  3. import { baseLines } from "@/store/baseLine";
  4. import { basePoints } from "@/store/basePoint";
  5. import { fixPoints } from "@/store/fixPoint";
  6. import { photos } from "@/store/photos";
  7. import { accidentPhotos } from "@/store/accidentPhotos";
  8. import { roadPhotos } from "@/store/roadPhotos";
  9. import {
  10. asyncTimeout,
  11. base64ToBlob,
  12. blobToBase64,
  13. debounce,
  14. getId,
  15. } from "@/utils";
  16. import { watch } from "vue";
  17. import { genUseLoading, params } from "@/hook";
  18. import router, { writeRouteName } from "@/router";
  19. import { baseURL } from "@/dbo/main";
  20. import { defaultUses, uses } from "@/store/SVGLabel";
  21. import { imageRotate } from "@/utils/image-rotate";
  22. import { sceneSeting } from "./sceneSeting";
  23. import { tables } from "./tables";
  24. import { drawSetting } from "./drawSetting";
  25. import { Pos3D } from "@/sdk";
  26. import { reshootData } from "./reshoot";
  27. const global = window as any;
  28. const getFilesIng = [];
  29. const getFilesSuccess = [];
  30. setInterval(() => {
  31. if (getFilesSuccess.length !== getFilesIng.length) {
  32. console.log(
  33. "请求资源数:" + getFilesIng.length,
  34. "响应结果数:" + getFilesSuccess.length
  35. );
  36. console.log(
  37. "未返回资源:" +
  38. getFilesIng.filter((url) => !getFilesSuccess.includes(url))
  39. );
  40. }
  41. // console.log(getFilesSuccess, getFilesIng);
  42. }, 1000);
  43. const normalImage = async (url: string) => {
  44. const getUrl = await api.getFile(url);
  45. const blob = await imageRotate(getUrl);
  46. if (!blob) {
  47. return url;
  48. } else {
  49. return await api.uploadImage(new File([blob], getId()));
  50. }
  51. };
  52. console.log("进入初始化sync count为" + global.count);
  53. if (!global.count) {
  54. global.count = 0;
  55. }
  56. export const api = !global.android
  57. ? // true
  58. // const api = import.meta.env.DEV
  59. {
  60. async setStore(data) {
  61. console.log("setStore");
  62. return axios.post("sceneStore", data);
  63. },
  64. async getStore() {
  65. return (await axios.get("/attach/sceneStore")).data;
  66. },
  67. async uploadImage(file) {
  68. return (
  69. await axios({
  70. url: "/upload",
  71. headers: { "Content-Type": "multipart/form-data" },
  72. method: "post",
  73. data: { file },
  74. })
  75. ).data.data as string;
  76. },
  77. async downloadImage(file) {
  78. window.open(URL.createObjectURL(file));
  79. return true;
  80. },
  81. async shareImage(filename: string) {
  82. await window.open(await api.getFile(filename));
  83. },
  84. async getFile(url) {
  85. try {
  86. const urlRaw = url;
  87. getFilesIng.push(urlRaw);
  88. if (url.includes(baseURL)) {
  89. url = url.substring(baseURL.length);
  90. }
  91. url = url.trim();
  92. const paths = url.split("/");
  93. const notBase64BaseTypes = [".png", ".jpg"];
  94. const notBase64 = notBase64BaseTypes.some((type) =>
  95. paths[paths.length - 1].includes(type)
  96. );
  97. if (notBase64) {
  98. getFilesSuccess.push(urlRaw);
  99. // await new Promise((resolve) => setTimeout(resolve, 2000));
  100. console.error(baseURL + url);
  101. return baseURL + url;
  102. } else {
  103. const data = await axios.get(url, { responseType: "blob" });
  104. const base64 = await blobToBase64(data.data);
  105. getFilesSuccess.push(urlRaw);
  106. return URL.createObjectURL(base64ToBlob(base64));
  107. }
  108. } catch (e) {
  109. console.error("获取文件失败 url:", url);
  110. throw e;
  111. }
  112. },
  113. async photograph(rotate = true) {
  114. const file = await new Promise<File>((resolve) => {
  115. const input = document.createElement("input");
  116. input.type = "file";
  117. input.click();
  118. input.addEventListener("change", (ev) => {
  119. resolve(input.files[0]);
  120. });
  121. });
  122. const url = await this.uploadImage(file);
  123. return rotate ? await normalImage(url) : url;
  124. },
  125. async selectPhotoAlbum(rotate = true) {
  126. return await this.photograph(rotate);
  127. },
  128. async closePage() {
  129. return router.push({ name: writeRouteName.scene });
  130. },
  131. async reshoot(pos: Pos3D) {
  132. console.log("reshoot参数:");
  133. console.log(JSON.stringify(pos));
  134. await asyncTimeout(1000);
  135. return { position: pos, image: "/images/1761892155839_0_pano_0.jpg" };
  136. },
  137. async delPano() {},
  138. }
  139. : {
  140. delPano(data: any) {
  141. return new Promise((resolve) => {
  142. global.delPanoCallback = (data) => {
  143. delete global.delPanoCallback;
  144. resolve(data);
  145. };
  146. global.android.delPano(JSON.stringify(data), "delPanoCallback");
  147. });
  148. },
  149. reshoot(pos: Pos3D) {
  150. return new Promise((resolve) => {
  151. global.reshootCallback = (data) => {
  152. delete global.reshootCallback;
  153. resolve(data);
  154. };
  155. global.android.reshoot(JSON.stringify(pos), "reshootCallback");
  156. });
  157. },
  158. shareImage(filename: string) {
  159. return new Promise((resolve) => {
  160. global.shareImageCallback = (data) => {
  161. delete global.shareImageCallback;
  162. resolve(data);
  163. };
  164. global.android.shareImage(filename, "shareImageCallback");
  165. });
  166. },
  167. setStore(data) {
  168. return new Promise((resolve) => {
  169. global.setSceneStoreCallback = (data) => {
  170. resolve(data);
  171. };
  172. global.android.setSceneStore(
  173. params.m + "/store.json",
  174. JSON.stringify(data),
  175. "setSceneStoreCallback"
  176. );
  177. });
  178. },
  179. getStore() {
  180. return new Promise((resolve) => {
  181. global.getSceneStoreCallback = (data) => {
  182. resolve(data);
  183. };
  184. global.android.getSceneStore(
  185. params.m + "/store.json",
  186. "getSceneStoreCallback"
  187. );
  188. });
  189. },
  190. // genUseLoading()
  191. async getFile(fileUrl: string) {
  192. const urlRaw = fileUrl;
  193. getFilesIng.push(urlRaw);
  194. fileUrl = fileUrl.trim();
  195. if (fileUrl.includes(params.m)) {
  196. fileUrl = fileUrl.substring(
  197. fileUrl.indexOf(params.m) + params.m.length
  198. );
  199. }
  200. fileUrl = new URL(fileUrl, "http://www.a.com").pathname;
  201. fileUrl = (params.realPath || params.m) + fileUrl;
  202. const paths = fileUrl.split("/");
  203. const notBase64BaseTypes = [
  204. // ".png", ".jpg"
  205. // , ".bin"
  206. ];
  207. const notBase64 = notBase64BaseTypes.some((type) =>
  208. paths[paths.length - 1].includes(type)
  209. );
  210. if (!notBase64) {
  211. return await new Promise<string>((resolve) => {
  212. const apiName = `getImageCallback${global.count++}`;
  213. global[apiName] = (base64) => {
  214. getFilesSuccess.push(urlRaw);
  215. try {
  216. resolve(URL.createObjectURL(base64ToBlob(base64)));
  217. } catch (e) {
  218. console.error(
  219. "getFile 失败 获取url:",
  220. fileUrl,
  221. "获取结果:",
  222. base64
  223. );
  224. }
  225. delete global[apiName];
  226. };
  227. global.android.getImage(fileUrl, apiName);
  228. });
  229. } else {
  230. getFilesSuccess.push(urlRaw);
  231. return fileUrl;
  232. }
  233. },
  234. uploadImage(file: File) {
  235. return new Promise<string>(async (resolve) => {
  236. const apiName = `uploadImageCallback${global.count++}`;
  237. global[apiName] = (data) => {
  238. resolve(data);
  239. delete global[apiName];
  240. };
  241. const data = await blobToBase64(file);
  242. global.android.uploadImage(
  243. params.m + "/attach/upload/" + file.name,
  244. data,
  245. apiName
  246. );
  247. });
  248. },
  249. downloadImage(file: File) {
  250. return new Promise<boolean>(async (resolve) => {
  251. const apiName = `downloadImageCallback${global.count++}`;
  252. console.log("download ing fileName ", file.name, "apiName ", apiName);
  253. global[apiName] = () => {
  254. console.log("download success fileName", file.name);
  255. resolve(true);
  256. delete global[apiName];
  257. };
  258. const data = await blobToBase64(file);
  259. // file为base64
  260. global.android.downloadImage(file.name, data, apiName);
  261. });
  262. },
  263. photograph(rotate = true) {
  264. return new Promise<string>((resolve) => {
  265. const apiName = `photograph${global.count++}`;
  266. global[apiName] = (data) => {
  267. data
  268. ? rotate
  269. ? normalImage(data).then(resolve)
  270. : resolve(data)
  271. : resolve(null);
  272. delete global[apiName];
  273. };
  274. global.android.cameraPhotograph(params.m, apiName);
  275. });
  276. },
  277. selectPhotoAlbum(rotate = true) {
  278. return new Promise<string>((resolve) => {
  279. const apiName = `selectPhotoAlbum${global.count++}`;
  280. global[apiName] = (data) => {
  281. data
  282. ? rotate
  283. ? normalImage(data).then(resolve)
  284. : resolve(data)
  285. : resolve(null);
  286. delete global[apiName];
  287. };
  288. global.android.selectPhotoAlbum(params.m, apiName);
  289. });
  290. },
  291. closePage() {
  292. return new Promise((resolve) => {
  293. global.closeWebViewCallback = resolve;
  294. global.android.closeWebView("closeWebViewCallback");
  295. });
  296. },
  297. };
  298. export const back = () => {
  299. api.closePage();
  300. };
  301. const loadStore = async () => {
  302. const data: any = await api.getStore();
  303. if (params.temp) {
  304. try {
  305. const str = await api.getFile("panoReshot.json");
  306. const data = await (await fetch(str).then()).text();
  307. reshootData.value = JSON.parse(data).map((item) => ({
  308. ...item,
  309. position: JSON.parse(item.position),
  310. }));
  311. } catch (e) {
  312. console.error(e);
  313. reshootData.value = [];
  314. }
  315. }
  316. list.value = data?.measures || [];
  317. baseLines.value = data?.baseLines || [];
  318. basePoints.value = data?.basePoints || [];
  319. sceneSeting.value = data?.sceneSeting;
  320. fixPoints.value = data?.fixPoints || [];
  321. photos.value = data?.photos || [];
  322. accidentPhotos.value = data?.accidentPhotos || [];
  323. roadPhotos.value = data?.roadPhotos || [];
  324. uses.value = data?.uses || defaultUses;
  325. tables.value = data?.tables || {};
  326. drawSetting.value = data?.drawSetting || {};
  327. syncSceneStore();
  328. };
  329. export const updateSceneStore = debounce(api.setStore, 300);
  330. export const uploadImage = (blob: Blob, name = `${getId()}.jpg`) => {
  331. const file = new File([blob], name);
  332. return api.uploadImage(file);
  333. };
  334. export const reshoot = (pos: Pos3D) => api.reshoot(pos);
  335. export const downloadImage = async (
  336. data: Blob | string,
  337. name = `${getId()}.jpg`
  338. ) => {
  339. const blob: Blob =
  340. typeof data === "string"
  341. ? (await axios.get(data, { responseType: "blob" })).data
  342. : data;
  343. const file = new File([blob], name, { type: "image/jpeg" });
  344. return await api.downloadImage(file);
  345. };
  346. const syncSceneStore = () => {
  347. return watch(
  348. () => ({
  349. measures: list.value,
  350. baseLines: baseLines.value,
  351. sceneSeting: sceneSeting.value,
  352. basePoints: basePoints.value,
  353. fixPoints: fixPoints.value,
  354. photos: photos.value,
  355. uses: uses.value,
  356. accidentPhotos: accidentPhotos.value,
  357. roadPhotos: roadPhotos.value,
  358. tables: tables.value,
  359. drawSetting: drawSetting.value,
  360. }),
  361. (data) => {
  362. console.error("收到数据源更新");
  363. updateSceneStore(data);
  364. },
  365. { deep: true, flush: "sync" }
  366. );
  367. };
  368. loadStore().catch((e) => {
  369. console.error(e);
  370. alert("场景数据加载失败");
  371. });