index.vue 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. <template>
  2. <div class="df-layout">
  3. <Header
  4. class="df-header"
  5. :type="props.type"
  6. @back-page="backPageHandler"
  7. @back="board.back()"
  8. @forward="board.forward()"
  9. @view-init="board.viewInit()"
  10. @save="saveHandler"
  11. @export="exportHandler"
  12. :back-disabled="state.backDisabled"
  13. :forward-disabled="state.forwardDisabled"
  14. v-if="props && board"
  15. />
  16. <div class="df-layout-child">
  17. <Eshape v-model:shape="state.selectShape" v-if="state.selectShape" @cropping="handleCropping" />
  18. <div class="df-sider">
  19. <Slider
  20. :type="props.type"
  21. :add-shape="state.addShape"
  22. :exists-bg-image="state.exixtsBgImage"
  23. @update:add-shape="updateAddShape"
  24. @track-image="trackImage"
  25. @selectImage="setBackImage"
  26. v-if="props"
  27. />
  28. </div>
  29. <div class="df-content">
  30. <div class="df-content-layout">
  31. <div class="df-board">
  32. <canvas ref="dom" />
  33. </div>
  34. </div>
  35. </div>
  36. </div>
  37. </div>
  38. </template>
  39. <script setup lang="ts">
  40. import Header from "./header.vue";
  41. import Slider from "./slider.vue";
  42. import Eshape from "./eshape.vue";
  43. import login from "./loginDialog.vue";
  44. import { computed, nextTick, ref, watch, onMounted } from "vue";
  45. import { RouteName, router } from "@/router";
  46. import { useBoard, title } from "./board/useBoard";
  47. import { selectFuseImage, selectMapImage } from "@/view/case/quisk";
  48. import { CaseTagging } from "@/store/caseTagging";
  49. import saveAs from "@/util/file-serve";
  50. import { BoardTypeDesc } from "@/constant/caseFile";
  51. import { addByMediaLiBrary, updateByTreeFileLists, uploadNewFile, getUrlSrc } from "@/store/case";
  52. import { imageCropper } from "@/view/system/quisk";
  53. import {
  54. BoardType,
  55. SaveCaseFileImageInfo,
  56. TitleShapeData,
  57. saveCaseFileImageInfo,
  58. } from "@/store/caseFile";
  59. import { uploadFile } from "@/store/system";
  60. const list = ref({
  61. xct:[],
  62. xczp:[],
  63. klbj:[],
  64. });
  65. const fmtId = ref(0);
  66. const pmtId = ref(0);
  67. // const board = ref(null);
  68. // const state = ref({});
  69. const ognFilesUrl = ref('')
  70. const dom = ref<HTMLCanvasElement>();
  71. const props = computed(() => {
  72. const route = router.currentRoute.value;
  73. if (route.name !== RouteName.drawCaseFile || !dom.value) {
  74. return null;
  75. } else {
  76. const params = route.params;
  77. const fileId = Number(params.id);
  78. return {
  79. caseId: Number(params.caseId),
  80. inAdd: fileId === -1,
  81. fileId,
  82. type: params.type.toString() as BoardType,
  83. dom: dom.value!,
  84. };
  85. }
  86. });
  87. const {board, state} = useBoard(props);
  88. async function getList() {
  89. updateByTreeFileLists(props.caseId).then(res => {
  90. let newlist = res.find(ele => ele.filesTypeName == '三录材料')?.childrenList || [];
  91. list.value.xct = newlist.find(ele => ele.filesTypeName == '现场图')?.childrenList || [];
  92. pmtId.value = list.value.xct.find(ele => ele.filesTypeName == '平面图').filesTypeId
  93. fmtId.value = list.value.xct.find(ele => ele.filesTypeName == '方位图').filesTypeId
  94. console.log('list.value', list.value)
  95. // if(pmtId.value || fmtId.value) {
  96. // }
  97. })
  98. }
  99. const backPageHandler = () => {
  100. board.value && board.value.clear();
  101. router.replace({ name: RouteName.material, params: { caseId: props.caseId } });
  102. // router.back();
  103. };
  104. const setBackImage = (blob: Blob) => {
  105. console.log('setBackImage', blob, board.value);
  106. board.value!.setImage(URL.createObjectURL(blob));
  107. };
  108. const updateAddShape = async (s, d) => {
  109. if (d) {
  110. state.value.addData = await uploadFile(d);
  111. console.log('state.value', state.value.addData);
  112. }
  113. state.value.addShape = s;
  114. };
  115. const trackImage = async () => {
  116. const data =
  117. props.value!.type === BoardType.scene
  118. ? await selectFuseImage(props.value!)
  119. : await selectMapImage({});
  120. console.log('户型图', data);
  121. if (data?.ognFilesUrl) {
  122. ognFilesUrl.value = data.ognFilesUrl;
  123. }
  124. if (data?.blob) {
  125. setBackImage(data.blob);
  126. if ("taggings" in data) {
  127. const tags = data.taggings as CaseTagging[];
  128. const table = await board.value!.calcTableShape([
  129. ["序号", "标注"],
  130. ...tags.map((tag, index) => [`序号${index + 1}`, tag.tagTitle]),
  131. ]);
  132. board.value!.setDefaultTable(null, table.content);
  133. }
  134. }
  135. };
  136. // watch(props, (newValue) => {
  137. // if(!newValue) return;
  138. // const BoardData = useBoard(props)
  139. // board.value = BoardData.board;
  140. // state.value = BoardData.state;
  141. // console.log('watchEffect111', newValue, props, board.value)
  142. // // const board = ref(null);
  143. // // const state = ref(null);
  144. // })
  145. console.log('useBoard', board, state)
  146. // 获取通用数据
  147. const getStore = async () => {
  148. const store = await board.value!.getStore();
  149. console.log('getStore', store, board.value, state.value);
  150. const titleShape = store.shapes.find(
  151. (shape: any) => shape.type === title
  152. ) as TitleShapeData;
  153. return { store, titleShape, ognFilesUrl: store.ognFilesUrl };
  154. };
  155. const isUrl = (string) => {
  156. try {
  157. new URL(string);
  158. return true;
  159. } catch (err) {
  160. return false;
  161. }
  162. }
  163. //裁剪
  164. const handleCropping = async (data) => {
  165. const appStore = await getStore();
  166. const args = props.value!;
  167. let imgUrl = args.inAdd ? ognFilesUrl.value : appStore.store.ognFilesUrl;
  168. const {width, height } = appStore.store.floors?.[0].bgImage;
  169. const blob = await fetch(imgUrl || state.value.selectShape.data.url).then(res => res.blob());
  170. const cropBlob = await imageCropper({
  171. img: blob,
  172. fixed: [width, height]
  173. })
  174. console.log(cropBlob)
  175. setBackImage(cropBlob)
  176. // if (data) {
  177. // state.value.croppingData = data;
  178. // board.value!.setCropping(data);
  179. // }
  180. };
  181. // 保存数据
  182. const saveHandler = async () => {
  183. const { store, titleShape } = await getStore();
  184. const args = props.value!;
  185. console.log('titleShape', store, titleShape);
  186. const blob = await board.value!.export();
  187. let filesTitle = titleShape?.text || `${args.caseId}_${BoardTypeDesc[args.type]}`
  188. const body: SaveCaseFileImageInfo = {
  189. caseId: args.caseId,
  190. imgType: args.type,
  191. file: new File([blob], `${filesTitle}.jpg`),
  192. filesTitle: filesTitle,
  193. content: store && JSON.stringify(store),
  194. ognFileUrl: ognFilesUrl.value || store.ognFilesUrl,
  195. };
  196. args.inAdd || (body.filesId = props.value!.fileId);
  197. const { data } = await uploadNewFile(body);
  198. const rse = await addByMediaLiBrary({ ...body, caseId: args.caseId,filesTypeId: args.type != BoardType.scene ? fmtId.value : pmtId.value, uploadId: data.id });
  199. if (args.inAdd) {
  200. router.replace({
  201. name: RouteName.drawCaseFile,
  202. params: { caseId: args.caseId, type: args.type, id: rse.filesId },
  203. });
  204. }
  205. await nextTick();
  206. setTimeout(() => {
  207. // location.reload();
  208. }, 100);
  209. };
  210. // 导出图片
  211. const exportHandler = async () => {
  212. const { titleShape } = await getStore();
  213. const blob = await board.value!.export();
  214. saveAs(blob, `${titleShape.text}.jpg`);
  215. };
  216. onMounted(() => {
  217. getList()
  218. })
  219. </script>
  220. <style lang="scss" scoped>
  221. .df-layout {
  222. display: flex;
  223. flex-direction: column;
  224. height: 100vh;
  225. background: #f0f2f5;
  226. }
  227. .df-header {
  228. flex: none;
  229. }
  230. .df-layout-child {
  231. width: 100%;
  232. height: calc(100% - 5.4rem);
  233. display: flex;
  234. position: relative;
  235. }
  236. .df-sider {
  237. flex: 0 0 340px;
  238. overflow-y: auto;
  239. box-sizing: border-box;
  240. background: #fff;
  241. }
  242. .df-content {
  243. flex: 1;
  244. display: grid;
  245. align-items: center;
  246. justify-content: center;
  247. height: 100%;
  248. overflow: auto;
  249. }
  250. .df-content-layout {
  251. --w: 297px;
  252. --h: 210px;
  253. --padding: 0;
  254. --calc: 3.5;
  255. border: calc(var(--padding) * var(--calc)) solid #fff;
  256. }
  257. .df-board {
  258. // border: 1px solid #000;
  259. width: calc(var(--w) * var(--calc));
  260. height: calc(var(--h) * var(--calc));
  261. box-sizing: border-box;
  262. canvas {
  263. background: #fff;
  264. width: 100%;
  265. height: 100%;
  266. }
  267. }
  268. </style>