header.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. <template>
  2. <Header :action-groups="actions" :title="title" no-back :draw="draw">
  3. <template #saves>
  4. <el-button type="primary" @click="saveHandler" :disabled="draw.drawing">
  5. 保存
  6. </el-button>
  7. <el-button
  8. @click="gotoTabulation"
  9. color="#E6E6E6"
  10. :disabled="draw.drawing"
  11. v-if="showTabulation"
  12. >
  13. 图纸
  14. </el-button>
  15. </template>
  16. </Header>
  17. </template>
  18. <script lang="ts" setup>
  19. import Header from "../../../components/header/index.vue";
  20. import { ElButton, ElMessage } from "element-plus";
  21. import { useDraw } from "../../../components/container/use-draw.ts";
  22. import { selectScene } from "../../../dialog/vr/index.ts";
  23. import { Scene } from "../../../platform/platform-resource.ts";
  24. import { getHeaderActions, getImage } from "../../../components/header/actions.ts";
  25. import {
  26. tabulationData,
  27. refreshTabulationData,
  28. tableCoverWidth,
  29. tableCoverHeight,
  30. overviewData,
  31. TabCover,
  32. } from "../../store.ts";
  33. import { nextTick, onUnmounted } from "vue";
  34. import { DataGroupId } from "@/constant/index.ts";
  35. import { Group } from "konva/lib/Group";
  36. import { Mode } from "@/constant/mode.ts";
  37. import { lineLen } from "@/utils/math.ts";
  38. import { repTabulationStore } from "../tabulation/gen-tab.ts";
  39. import { router } from "../../router.ts";
  40. import { overviewId, params, tabulationId } from "@/example/env.ts";
  41. import { listener } from "@/utils/event.ts";
  42. import { mergeFuns, repeatedlyOnly } from "@/utils/shared.ts";
  43. import saveAs from "@/utils/file-serve.ts";
  44. const props = defineProps<{ title: string }>();
  45. const draw = useDraw();
  46. const emit = defineEmits<{
  47. (e: "selectVR", v: Scene): void;
  48. (e: "saveAfter"): void;
  49. }>();
  50. // const showTabulation = !params.value.sceneDraw;
  51. const showTabulation = true;
  52. const baseActions = getHeaderActions(draw);
  53. const actions = [
  54. [baseActions.undo, baseActions.redo],
  55. [
  56. baseActions.clear,
  57. baseActions.rotateView,
  58. { ...baseActions.initViewport, handler: () => draw.initViewport(40) },
  59. baseActions.toggleShow,
  60. ],
  61. [
  62. {
  63. handler: async () => {
  64. const scene = await selectScene();
  65. emit("selectVR", scene);
  66. },
  67. text: "VR辅助",
  68. icon: "VR",
  69. },
  70. ],
  71. [
  72. {
  73. ...baseActions.expose,
  74. children: baseActions.expose.children.map((item) => ({
  75. ...item,
  76. async handler() {
  77. const format = item.text.toLowerCase();
  78. if (format !== "dxf") {
  79. const blob = await draw.enterTemp(async () => {
  80. const back = draw.config.back;
  81. const [_, _a, recover] = await setViewToTableCover();
  82. if (format === "jpg") draw.config.back = back;
  83. await nextTick();
  84. const blob = await getImage(draw, `image/${format}`);
  85. recover();
  86. await nextTick();
  87. return blob;
  88. });
  89. if (!blob) {
  90. ElMessage.error("导出失败");
  91. } else {
  92. await saveAs(blob, `${props.title}.${format}`);
  93. ElMessage.success("导出成功");
  94. }
  95. } else {
  96. await item.handler(props.title);
  97. }
  98. },
  99. })),
  100. },
  101. ],
  102. ];
  103. const setViewToTableCover = async () => {
  104. const oldViewMat = draw.viewer.viewMat;
  105. const oldShowGrid = draw.config.showGrid;
  106. const oldSize = draw.config.size;
  107. const oldBack = draw.config.back;
  108. const oldShowCompass = draw.config.showCompass;
  109. const oldLabelLineConfig = { ...draw.config.labelLineConfig };
  110. const oldShowOffset = draw.config.labelLineConfig.showOffset;
  111. draw.initViewport(0);
  112. await nextTick();
  113. const getRect = (id: string) => draw.stage!.findOne<Group>(`#${id}`)?.getClientRect();
  114. const pop = draw.mode.push(Mode.readonly);
  115. const rect = getRect(DataGroupId)!;
  116. let width = rect.width;
  117. let height = rect.height;
  118. const rectScale = width / height;
  119. const tableCoverScale = tableCoverWidth / tableCoverHeight;
  120. const padding = 70;
  121. if (rectScale > tableCoverScale) {
  122. height = width / tableCoverScale;
  123. } else {
  124. width = tableCoverScale * height;
  125. }
  126. if (width < padding * 2) {
  127. width += padding * 2;
  128. }
  129. if (height < padding * 2) {
  130. height += padding * 2;
  131. }
  132. draw.config.size = { width, height };
  133. draw.config.showGrid = false;
  134. draw.config.back = undefined;
  135. draw.config.showCompass = false;
  136. draw.config.labelLineConfig.type = "auto";
  137. draw.config.labelLineConfig.fontSize = width / 60;
  138. draw.config.labelLineConfig.strokeWidth = draw.config.labelLineConfig.fontSize / 10;
  139. await nextTick();
  140. draw.config.labelLineConfig.showOffset = padding - 5;
  141. draw.initViewport(padding);
  142. await nextTick();
  143. const syncItems: TabCover["syncItems"] = [];
  144. // const positionRect = getRect("formal")!;
  145. // draw.store.items.forEach((item) => {
  146. // if (item.key === "trace") {
  147. // const itemRect = getRect(item.id);
  148. // if (itemRect) {
  149. // itemRect.x = itemRect.x - positionRect.x;
  150. // itemRect.y = itemRect.y - positionRect.y;
  151. // syncItems.push({
  152. // ...item,
  153. // rect: itemRect,
  154. // desc: (item as any).name || "",
  155. // } as any);
  156. // }
  157. // }
  158. // });
  159. return [
  160. {
  161. width,
  162. height,
  163. },
  164. syncItems,
  165. () => {
  166. pop();
  167. draw.config.size = oldSize;
  168. draw.config.showGrid = oldShowGrid;
  169. draw.config.back = oldBack;
  170. draw.config.showCompass = oldShowCompass;
  171. draw.config.labelLineConfig = oldLabelLineConfig;
  172. draw.config.labelLineConfig.showOffset = oldShowOffset;
  173. draw.viewer.setViewMat(oldViewMat);
  174. },
  175. ] as const;
  176. };
  177. const setViewToKanKanCover = async () => {
  178. const oldViewMat = draw.viewer.viewMat;
  179. const oldBack = draw.config.back && { ...draw.config.back };
  180. const oldShowGrid = draw.config.showGrid;
  181. const oldLabelLineConfig = { ...draw.config.labelLineConfig };
  182. draw.config.labelLineConfig.stroke = "#FFFFFF";
  183. draw.config.labelLineConfig.shadowColor = "#000000";
  184. draw.config.labelLineConfig.fontSize = 18;
  185. const pop = draw.mode.push(Mode.readonly);
  186. draw.config.showGrid = false;
  187. draw.config.back = undefined;
  188. const set: any = {
  189. stroke: "#FFFFFF",
  190. fill: undefined,
  191. color: "#FFFFFF",
  192. fontColor: "#FFFFFF",
  193. };
  194. const cSet: any = {
  195. arrow: {
  196. fill: "#FFFFFF",
  197. },
  198. text: {
  199. fill: "#FFFFFF",
  200. },
  201. };
  202. const typeItems: any = Object.entries(draw.store.typeItems);
  203. const lineData = draw.store.getTypeItems("line")[0];
  204. if (lineData) {
  205. typeItems.push(["lines", lineData.lines]);
  206. }
  207. const clearupItems = typeItems.map(([type, items]: any) => {
  208. const cleanups: (() => void)[] = [];
  209. items.forEach((item: any) => {
  210. const itemSet = type in cSet ? cSet[type] : set;
  211. const setKeys = Object.keys(itemSet);
  212. for (const key of setKeys) {
  213. if (key in item) {
  214. const oldVal = item[key];
  215. cleanups.push(() => (item[key] = oldVal));
  216. } else {
  217. cleanups.push(() => delete item[key]);
  218. }
  219. item[key] = itemSet[key];
  220. }
  221. });
  222. return mergeFuns(cleanups);
  223. });
  224. draw.initViewport(70);
  225. await nextTick();
  226. const blob = await getImage(draw, "image/png");
  227. mergeFuns(clearupItems)();
  228. pop();
  229. draw.config.back = oldBack;
  230. draw.config.labelLineConfig = oldLabelLineConfig;
  231. draw.config.showGrid = oldShowGrid;
  232. draw.viewer.setViewMat(oldViewMat);
  233. await nextTick();
  234. return blob;
  235. };
  236. const saveHandler = repeatedlyOnly(async () => {
  237. const storeData = draw.getData();
  238. const [tabBlob, listBlob, kkBlob, scale, rect, syncItems] = await draw.enterTemp(
  239. async () => {
  240. const back = draw.config.back;
  241. const [rect, syncItems, recover] = await setViewToTableCover();
  242. await nextTick();
  243. const mat = draw.viewer.transform.invert();
  244. const scale =
  245. lineLen(mat.point({ x: 1, y: 0 }), mat.point({ x: 0, y: 0 })) *
  246. draw.store.config.proportion.scale;
  247. const tabBlob = await getImage(draw, "image/png");
  248. draw.config.back = back;
  249. await nextTick();
  250. const listBlob = await getImage(draw, "image/jpg");
  251. recover();
  252. await nextTick();
  253. const kkBlob = await setViewToKanKanCover();
  254. return [tabBlob, listBlob, kkBlob, scale, rect, syncItems] as const;
  255. }
  256. );
  257. let tabUrl = null;
  258. let listUrl = null;
  259. let kankanUrl = null;
  260. if (!tabBlob || !listBlob || !kkBlob) {
  261. ElMessage.error("截图保存失败");
  262. } else {
  263. console.error(window.platform.uploadResourse);
  264. [tabUrl, listUrl, kankanUrl] = await Promise.all([
  265. window.platform.uploadResourse(new File([tabBlob], `tabulation-cover.png`)),
  266. window.platform.uploadResourse(new File([listBlob], `list-cover.png`)),
  267. window.platform.uploadResourse(new File([kkBlob], `kankan-cover.png`)),
  268. ]);
  269. }
  270. tabulationId.value = await window.platform.getTabulationId(overviewId.value);
  271. await refreshTabulationData();
  272. const cover = {
  273. url: tabUrl,
  274. width: rect.width,
  275. height: rect.height,
  276. proportion: { ...draw.store.config.proportion, scale },
  277. syncItems,
  278. };
  279. console.log(tabulationData.value.store);
  280. const tabStore = await repTabulationStore(
  281. tabulationData.value.paperKey,
  282. storeData.config.compass.rotation,
  283. cover,
  284. tabulationData.value.isAutoGen ? undefined : tabulationData.value.store
  285. );
  286. console.log(tabStore);
  287. tabStore.config.compass = storeData.config.compass;
  288. const body: any = {
  289. ...overviewData.value,
  290. listCover: listUrl,
  291. store: storeData,
  292. viewport: draw!.viewer.transform.m,
  293. caseTabulation: {
  294. ...tabulationData.value,
  295. id: tabulationId.value,
  296. title: overviewData.value.title,
  297. cover,
  298. store: tabStore,
  299. overviewId: overviewId.value,
  300. },
  301. };
  302. if (window.platform.sceneDraw) {
  303. body.kankanCover = kankanUrl;
  304. }
  305. overviewId.value = await window.platform.saveOverviewData(overviewId.value, body);
  306. tabulationId.value = await window.platform.getTabulationId(overviewId.value);
  307. console.log("保存完毕");
  308. emit("saveAfter");
  309. });
  310. onUnmounted(
  311. listener(document.documentElement, "keydown", (ev) => {
  312. if (ev.ctrlKey && ev.key.toUpperCase() === "S") {
  313. saveHandler();
  314. }
  315. })
  316. );
  317. const gotoTabulation = repeatedlyOnly(async () => {
  318. await saveHandler();
  319. router.push({
  320. ...router.currentRoute.value,
  321. name: "tabulation",
  322. query: params.value,
  323. } as any);
  324. });
  325. defineExpose({ gotoTabulation, saveHandler });
  326. </script>