import { Empty, Input, Modal } from 'antd' import { Button, Upload, message } from 'antd' import ImgCrop from 'antd-img-crop' import { useEffect, useMemo, useRef, useState } from 'react' import AMapLoader from '@amap/amap-jsapi-loader'; import style from './style.module.scss' import { SceneType, SceneTypeDomain, SceneTypePaths } from 'constant'; import { base64ToBlob, getHref, drawImage } from 'utils'; import { asyncLoading } from 'components/loading'; import { RedoOutlined } from '@ant-design/icons'; import { fetchTaggings } from 'api' import { SortTransfer } from './sort-transfer' import { BoardType, BoardTypeDesc } from 'api' import type { Tagging } from 'api' import type { UploadProps } from 'antd' const domScreenshot = async (dom: HTMLElement) => { const canvas = (dom.tagName.toUpperCase() === 'CANVAS' ? dom : dom.querySelector('canvas')) as HTMLCanvasElement return new Promise(resolve => { if (!canvas) { return resolve(null) } canvas.toBlob(resolve) }) } type SelectImageProps = { onClose: () => void onSave: (url: Blob | null, tagging: Tagging[]) => void } let AMap: any AMapLoader.load({ plugins: ['AMap.PlaceSearch'], key: 'e661b00bdf2c44cccf71ef6070ef41b8', version: '2.0', }).then(result => AMap = result) type MapInfo = { lat: number, lng: number, zoom: number } export const SelectMap = (props: SelectImageProps) => { const [open, setOpen] = useState(true) const [info, setInfo] = useState() const [keyword, setKeyword] = useState('') const mapEle = useRef(null) const searchResultEle = useRef(null) const searchAMap = useRef() const onSubmit = async () => { if (mapEle.current) { const blob = await domScreenshot(mapEle.current) await props.onSave(blob, []) setOpen(false) } } const renderInfo = info &&

经度{ info.lat }

维度{ info.lng }

缩放级别{ info.zoom }

useEffect(() => { if (!mapEle.current) { return; } const map = new AMap.Map(mapEle.current, { WebGLParams: { preserveDrawingBuffer: true }, resizeEnable: true }) const placeSearch = new AMap.PlaceSearch({ pageSize: 5, pageIndex: 1, map: map, panel: searchResultEle.current, autoFitView: true }); const getMapInfo = (): MapInfo => { var zoom = map.getZoom(); //获取当前地图级别 var center = map.getCenter(); return { zoom, lat: center.lat, lng: center.lng } } //绑定地图移动与缩放事件 map.on('moveend', () => setInfo(getMapInfo())); map.on('zoomend', () => setInfo(getMapInfo())); searchAMap.current = placeSearch return () => { searchAMap.current = null map.destroy() } }, [mapEle]) useEffect(() => { keyword && searchAMap.current?.search(keyword) }, [keyword, searchAMap]) return ( setOpen(false)} onOk={() => asyncLoading(onSubmit())} afterClose={props.onClose} okText="确定" cancelText="取消" >
{ renderInfo } ) } 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) { return null } const extIframe = iframeElement.querySelector('.external') as HTMLIFrameElement const targetIframe = extIframe || iframe const targetWindow: any = targetIframe.contentWindow const fuseCnavas = targetWindow.document.querySelector('.scene-canvas > canvas') as HTMLElement if (fuseCnavas) { const dataURL = await targetWindow.sdk.screenshot(targetIframe.offsetWidth, targetIframe.offsetHeight) const res = await fetch(dataURL) const blob = await res.blob() return { type: ImageType.FUSE, blob } // 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(resolve => { sdk.scene.screenshot(540, 390).done((data: string) => { resolve({ type: ImageType.FUSE, blob: base64ToBlob(data) }) }) }) } else { const sdk = targetWindow.__sdk return new Promise(resolve => { sdk.Camera.screenshot([ {width: 540, height: 390, name: '2k' }],false).then((result: any)=>{ resolve({ type: ImageType.KANKAN, blob: base64ToBlob(result[0].data) }) }) }) } } export const SelectFuse = (props: SelectImageProps & { caseId: number }) => { const [open, setOpen] = useState(true) const [blob, setBlob] = useState(null) const [tags, setTags] = useState([]) const [selectTags, setSelectTags] = useState([]) const [addTagIds, setAddTagIds] = useState([]) const iframeRef = useRef(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() })), [tags]) useEffect(() => { fetchTaggings(props.caseId.toString()).then(setTags) }, [props.caseId]) const onSubmit = async () => { const filterTags = addTagIds.map(id => tags.find(tag => tag.tagId.toString() === id)!) props.onSave(blob, filterTags) setOpen(false) } const getCover = async () => { if (iframeRef.current) { const fuseImage = await getFuseImage(iframeRef.current) if (!fuseImage?.blob) { return; } else if (fuseImage.type !== ImageType.FUSE) { 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.trim() === hotTitle.trim()) if (index !== -1) { const bound = hot.getBoundingClientRect() const size = (img.width / 540) * 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 = 540 $ccanvas.height = 390 const cctx = $ccanvas.getContext('2d')! drawImage( cctx, $ccanvas.width, $ccanvas.height, $canvas, img.width, img.height, 0, 0 ) console.error('???') const blob = await new Promise(resolve => $ccanvas.toBlob(resolve, 'png')) setBlob(blob) } } return ( setOpen(false)} onOk={() => asyncLoading(onSubmit())} afterClose={props.onClose} okText="确定" cancelText="取消" >