bill 2 年之前
父節點
當前提交
c40c9f143f

+ 0 - 1
src/api/board.ts

@@ -69,7 +69,6 @@ export interface TextShapeData extends ShapeData {
 export type TableShapeContentItem = { width: number, height: number, value: string, rowIndex: number, colIndex: number }
 export interface TableShapeData extends CurrencyShapeData {
   type: typeof table
-  fontSize: number
   content: TableShapeContentItem[]
 }
 

+ 1 - 0
src/hook/refersh.ts

@@ -4,6 +4,7 @@ export const useRefersh = () => {
   const [refershCount, setRefershCount] = useState(0)
 
   return useCallback(() => {
+    console.log(refershCount)
     setRefershCount(refershCount + 1)
   // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [])

+ 4 - 3
src/views/draw-file/board/index.d.ts

@@ -1,5 +1,5 @@
 import { metas as fMetas } from './shape'
-import type { BoardData, BoardShapeData } from 'api'
+import type { BoardData, BoardShapeData, TableShapeData } from 'api'
 import type { Emitter } from 'mitt'
 import {
   brokenLine,
@@ -38,7 +38,7 @@ export type BoardShape<T = BoardShapeData, K = keyof T> = IntersectionFromUnion<
   K extends 'type'
     ? { data: { [key in K]: T[K]} }
     : { data: { [key in K]: T[K] } } & { [key in `set${Capitalize<K>}`]: (val: T[K]) => void }
-> & { delete: () => void }
+> & { delete: () => void, autoSet?: boolean }
 
 export type ExtractShape<T extends string, D = BoardShapeData> = BoardShape<
   D extends object
@@ -60,7 +60,8 @@ export type Board = {
   forward(): void
   viewInit(): void
   setImage(url: string): void
-  getStore(): BoardData
+  getStore(): Promise<BoardData>
+  calcTableShape(data: string[][]): Promise<TableShapeData>
   export(): Promise<Blob>
   destroy(): void
 }

+ 58 - 13
src/views/draw-file/board/index.js

@@ -8,13 +8,14 @@ import {
 } from './shape'
 import Layer from './editCAD/Layer'
 import { history } from './editCAD/History/History.js'
+import { uploadFile } from 'api'
 
-const toStore = (refs) => {
-  return {
-    bgImage: refs.baseMap?.data || null,
-    shapes: refs.shapes.map(shape => shape.data)
-  }
-}
+// const toStore = (refs) => {
+//   return {
+//     bgImage: refs.baseMap?.data || null,
+//     shapes: refs.shapes.map(shape => shape.data)
+//   }
+// }
 
 export const create = (store, canvas) => {
   const refs = {
@@ -88,14 +89,26 @@ export const create = (store, canvas) => {
   const board = {
     bus: refs.bus,
     el: canvas,
-    getStore() {
+    async getStore() {
       const data = layer.uiControl.exportJSON()
-      const titleValue = data.floors[0]?.title.value
+      const floor = data.floors[0]
+      const shapes = []
+
+      if (floor) {
+        const bgImage = floor.image.src
+        if (bgImage && bgImage.includes('blob:')) {
+          const url = await fetch(bgImage)
+            .then(res => res.blob())
+            .then(blob => uploadFile(new File([blob], (store.id || 'image') + '.png')))
+
+            floor.image.src = url
+            console.log(url) 
+        }
+        shapes.push({ type: title, text: floor.title.value })
+      }
       return {
         id: store.id,
-        shapes: [
-          { type: title, text: titleValue }
-        ],
+        shapes,
         ...layer.uiControl.exportJSON()
       }
     },
@@ -105,6 +118,8 @@ export const create = (store, canvas) => {
     unSelectShape() {
       layer.uiControl.clearUI()
     },
+    setDefaultTable(rbTable, rtTable) {
+    },
     readyAddShape(shapeType, onFine) {
       layer.uiControl.selectUI = shapeType
       layer.uiControl.updateEventNameForSelectUI()
@@ -125,8 +140,38 @@ export const create = (store, canvas) => {
       layer.uiControl.setAttributes(bgImage, 'update', url)
     },
     export() {
-      console.log(layer.uiControl.menu_screenShot())
-      // return new Promise(resolve => canvas.toBlob(resolve))
+      return new Promise(resolve => resolve(layer.uiControl.menu_screenShot()))
+    },
+    calcTableShape(data) {
+      return new Promise(resolve => {
+        const tableData = {
+          data: {
+            type: table,
+            content: data.map((cols, index) => [
+              {
+                rowIndex: index,
+                colIndex: 0,
+                width: 0,
+                height: 0,
+                value: cols[0],
+              },
+              {
+                rowIndex: index,
+                colIndex: 1,
+                width: 0,
+                height: 0,
+                value: cols[1],
+              }
+            ]).flat()
+          },
+          setContent(newData) {
+            board.bus.emit('selectShape', null)
+            resolve({type: table, content: newData})
+          },
+          autoSet: true
+        }
+        board.bus.emit('selectShape', tableData)
+      })
     },
     destroy() {
     }

+ 32 - 5
src/views/draw-file/eshape.tsx

@@ -1,4 +1,4 @@
-import { useEffect, useMemo, useState } from "react"
+import { useCallback, useEffect, useMemo, useState } from "react"
 import { Button, Form, Modal, Input } from 'antd'
 import { CloseOutlined, PlusOutlined, RotateRightOutlined } from '@ant-design/icons'
 import style from './style.module.scss'
@@ -7,6 +7,8 @@ import ReactEditeTable, { InputEditor } from 'react-edit-table'
 
 import type { Board, BoardShape, ShapeType, ExtractShape } from "./board"
 import type { ComponentType } from 'react'
+import { useSelector } from "store"
+import { usePathData } from "router"
 
 
 // import { Select } from 'antd'
@@ -84,7 +86,7 @@ const ContentInput = ({ shape }: { shape: ExtractShape<'content'> }) => {
   }, [content, refer])
   const sortContent = () => 
     content.sort((a, b) => {
-      const rowDiff = a.rowIndex - b.rowIndex
+      const rowDiff: number = a.rowIndex - b.rowIndex
       if (rowDiff) {
         return rowDiff
       } else {
@@ -115,7 +117,7 @@ const ContentInput = ({ shape }: { shape: ExtractShape<'content'> }) => {
     ])
   }
 
-  const onSubmit = () => {
+  const onSubmit = useCallback(() => {
     const rowEls = Array.from(document.querySelectorAll('#edit-table .body-container .row-container')) as HTMLDivElement[]
     const bound = rowEls.map((row, rowIndex) => {
       const cells = Array.from(row.querySelectorAll('.cell')) as HTMLDivElement[]
@@ -130,7 +132,7 @@ const ContentInput = ({ shape }: { shape: ExtractShape<'content'> }) => {
     setContent(bound)
     shape.setContent(bound)
     setEdit(false)
-  }
+  }, [content, shape])
 
   useEffect(() => {
     if (!edit) {
@@ -138,6 +140,14 @@ const ContentInput = ({ shape }: { shape: ExtractShape<'content'> }) => {
     }
   }, [edit, shape.data.content])
 
+  useEffect(() => {
+    if (shape.autoSet) {
+      setEdit(true)
+      setTimeout(onSubmit, 100)
+    }
+  // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, [])
+
   return (
     <Form.Item label="内容">
       <Button type="primary" onClick={() => setEdit(true)}>编辑</Button>
@@ -208,8 +218,25 @@ export const EShape = ({ board }: EShapeProps) => {
     }
   }, [board, shape, disabledDelete])
 
+  const path = usePathData()
+  const user = useSelector(store => store.user.value)
+  useEffect(() => {
+    if (board && path?.id === '-1') {
+      board.calcTableShape([
+        ["案发时间", "2022年10月10日"],
+        ["案发地点", ""],
+        ["绘图单位", ""],
+        ["绘图人", user.nickName],
+        ["绘图时间", "2022年10月10日"]
+      ]).then(data => {
+        console.log('===>', data)
+      })
+      
+    }
+  }, [user, board, path?.id])
+
   return shape ? (
-    <div className={style['def-shape-edit']}>
+    <div className={style['def-shape-edit']} style={{ visibility: shape.autoSet ? "hidden" : 'visible' }}>
       { Edit && <Edit shape={shape} /> }
       { renderDelete }
       <div 

+ 5 - 4
src/views/draw-file/header.tsx

@@ -7,7 +7,7 @@ import {
   BoardTypeDesc, 
   BoardType,
   saveBoard,
-  TitleShapeData
+  TitleShapeData,
 } from 'api'
 
 import { useEffect, useState } from "react"
@@ -36,6 +36,7 @@ type HeaderProps = {
   type: BoardType
 }
 const Header = ({ board, type }: HeaderProps) => {
+  console.log('--->?')
   const [backDisabled, setBackDisabled] = useState(true)
   const [forwardDisabled, setForwradDisabled] = useState(true)
   const path = usePathData()
@@ -45,12 +46,12 @@ const Header = ({ board, type }: HeaderProps) => {
   const navigate = useNavigate()
   const exportPng = async () => {
     const blob = await board.export()
-    saveAs(blob, '现场图.png')
+    saveAs(blob, `${BoardTypeDesc[type]}.png`)
   }
 
   
   const save = async () => {
-    const store = board.getStore()
+    const store = await board.getStore()
     const titleShape = store.shapes.find(shape => shape.type === title) as TitleShapeData
     const blob = await board.export()
     const isNew = pathId === -1
@@ -59,7 +60,7 @@ const Header = ({ board, type }: HeaderProps) => {
       imgType: pathType,
       file: new File([blob], `${pathType}_${pathId}.png`),
       filesTitle: titleShape?.text || `${caseId}_${BoardTypeDesc[pathType]}`, 
-      content: board.getStore()
+      content: store
     }
     if (!isNew) {
       body.filesId = pathId

+ 6 - 5
src/views/draw-file/index.tsx

@@ -6,7 +6,6 @@ import boardFactory from './board'
 import DfSlider from './slider'
 import DfHeader from './header'
 import EShape from './eshape'
-import { useDispatch } from 'store'
 import { getBoardById, BoardType, BoardData } from 'api'
 import { useRefersh } from 'hook'
 
@@ -39,12 +38,12 @@ const DfBoard = memo(forwardRef(({ data: boardData }: { data: BoardData }, ref)
 export const DrawFile = () => {
   const refersh = useRefersh()
   const path = usePathData()
-  const dispatch = useDispatch()
   const pathId = Number(path!.id)
   const caseId = Number(path!.caseId)
   const pathType = path!.type as BoardType
   const [boardData, setBoardData] = useState<BoardData>()
   const board = useRef<Board>()
+  const pathRef = useRef(path)
 
   const updateBoard = useCallback((data: Board) => {
     if (data !== board.current) {
@@ -66,9 +65,11 @@ export const DrawFile = () => {
     }
   }, [pathId, boardData?.id, boardData])
 
-  useEffect(() => () => {
-    dispatch({ type: 'board/destory' })
-  }, [dispatch])
+  useEffect(() => {
+    if (JSON.stringify(path) !== JSON.stringify(pathRef.current)) {
+      location.reload()
+    }
+  }, [path])
 
   return (
     <Layout className={style['df-layout']}>

+ 66 - 10
src/views/draw-file/modal.tsx

@@ -130,6 +130,12 @@ const getFuseUrl = (caseId: number) =>
   `${getHref(SceneTypeDomain[SceneType.SWMX]!, SceneTypePaths[SceneType.SWMX][0], { caseId: caseId.toString() })}&share=1#show/summary`
 
 
+enum ImageType {
+  FUSE,
+  KANKAN,
+  LASER
+}
+type FuseImageRet = { type: ImageType, blob: Blob | null }
 const getFuseImage = async (iframe: HTMLIFrameElement) => {
   const iframeElement = iframe.contentWindow?.document.documentElement
   if (!iframeElement) {
@@ -141,22 +147,22 @@ const getFuseImage = async (iframe: HTMLIFrameElement) => {
   const fuseCnavas = targetWindow.document.querySelector('.scene-canvas > canvas') as HTMLElement
   
   if (fuseCnavas) {
-    return domScreenshot(fuseCnavas)
+    return domScreenshot(fuseCnavas).then(blob => ({ type: ImageType.FUSE, blob }))
   }
   const isLaser = targetWindow.document.querySelector('.laser-layer')
 
   if (isLaser) {
     const sdk = await targetWindow.__sdk
-    return new Promise<Blob | null>(resolve => {
+    return new Promise<FuseImageRet>(resolve => {
       sdk.scene.screenshot(900, 900).done((data: string) => {
-        resolve(base64ToBlob(data))
+        resolve({ type: ImageType.FUSE, blob: base64ToBlob(data) })
       })
     })
   } else {
     const sdk = targetWindow.__sdk
-    return new Promise<Blob | null>(resolve => {
+    return new Promise<FuseImageRet>(resolve => {
       sdk.Camera.screenshot([ {width: 2048, height: 1024, name: '2k' }],false).then((result: any)=>{
-        resolve(base64ToBlob(result[0].data))
+        resolve({ type: ImageType.KANKAN, blob: base64ToBlob(result[0].data) })
       })
     })
   }
@@ -168,10 +174,11 @@ export const SelectFuse = (props: SelectImageProps & { caseId: number }) => {
   const [blob, setBlob] = useState<Blob | null>(null)
   const [tags, setTags] = useState<Tagging[]>([])
   const [selectTags, setSelectTags] = useState<string[]>([])
-  const [addTags, setAddTags] = useState<string[]>([])
+  const [addTagIds, setAddTagIds] = useState<string[]>([])
   const iframeRef = useRef<HTMLIFrameElement>(null)
   const coverUrl = useMemo(() => blob && URL.createObjectURL(blob), [blob])
   const url = useMemo(() => getFuseUrl(props.caseId), [props.caseId])
+  const addTags = useMemo(() => addTagIds.map(id => tags.find(tag => tag.tagId.toString() === id)!), [addTagIds, tags])
   const mockData = useMemo(() => tags.map(tag => ({ 
     data: tag, 
     key: tag.tagId.toString()
@@ -183,11 +190,60 @@ export const SelectFuse = (props: SelectImageProps & { caseId: number }) => {
   }, [props.caseId])
 
   const onSubmit = async () => {
-    props.onSave(blob, tags.filter(tag => addTags.includes(tag.tagId.toString())))
+    const filterTags = tags.filter(tag => addTagIds.includes(tag.tagId.toString()))
+    props.onSave(blob, filterTags)
+    setOpen(false)
   }
   const getCover = async () => {
     if (iframeRef.current) {
-      const blob = await getFuseImage(iframeRef.current)
+      const fuseImage = await getFuseImage(iframeRef.current)
+      if (!fuseImage?.blob) {
+        return;
+      } else if (fuseImage.type !== ImageType.FUSE || !addTags.length) {
+        setBlob(fuseImage.blob)
+        return;
+      }
+
+      const img = new Image()
+      img.src = URL.createObjectURL(fuseImage.blob)
+      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 = iframeRef.current.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 = addTags.findIndex(tag => tag.tagTitle === hotTitle)
+        if (index !== -1) {
+          const bound = hot.getBoundingClientRect()
+          const size = 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 blob = await new Promise<Blob | null>(resolve => $canvas.toBlob(resolve, 'png'))
       setBlob(blob)
     }
   }
@@ -214,9 +270,9 @@ export const SelectFuse = (props: SelectImageProps & { caseId: number }) => {
               <Transfer
                 dataSource={mockData}
                 titles={['所有', '需要']}
-                targetKeys={addTags}
+                targetKeys={addTagIds}
                 selectedKeys={selectTags}
-                onChange={setAddTags}
+                onChange={setAddTagIds}
                 onSelectChange={(sKeys, tKeys) => setSelectTags([...sKeys, ...tKeys])}
                 render={(item) => item.data.tagTitle}
               />

+ 8 - 0
src/views/draw-file/slider.tsx

@@ -35,6 +35,12 @@ export const DfSlider = ({ board, type, caseId }: SliderProps) => {
       const url = URL.createObjectURL(blob)
       board.setImage(url)
     }
+    if (taggings.length) {
+      const table = await board.calcTableShape(
+        taggings.map((tag, index) => [`图例${index + 1}`, tag.tagTitle])
+      )
+      console.log(table)
+    }
   }
   const SelectImage = type  === BoardType.map ? SelectMap : SelectFuse
   const renderSelect = selectMode && <SelectImage
@@ -64,6 +70,8 @@ export const DfSlider = ({ board, type, caseId }: SliderProps) => {
     }
   }, [currentShape, board])
   
+
+
   return (
     <div className={style['df-slide-content']}>
       { renderSelect }

+ 4 - 2
src/views/draw-file/style.module.scss

@@ -238,6 +238,7 @@ body {
 
 .house-layout {
   display: flex;
+  height: 600px;
 }
 
 .iframe-layout {
@@ -259,7 +260,8 @@ body {
   margin-left: 40px;
 
   > div {
-    flex: 1 1 0;
+    flex: none;
+    height: 290px;
     display: flex;
     flex-direction: column;
 
@@ -291,7 +293,7 @@ body {
   border: 1px solid #D9D9D9;
   img {
     width: 100%;
-    height: 100%;
+    height: 253px;
     object-fit: cover;
   }
 }