|
@@ -1,20 +1,21 @@
|
|
-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 {Empty, Input, Modal} from 'antd'
|
|
|
|
+import {Button, Upload, message} from 'antd'
|
|
|
|
+import ImgCropRaw from './crop'
|
|
|
|
+import {useEffect, useMemo, useRef, useState} from 'react'
|
|
import AMapLoader from '@amap/amap-jsapi-loader';
|
|
import AMapLoader from '@amap/amap-jsapi-loader';
|
|
import style from './style.module.scss'
|
|
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'
|
|
|
|
-
|
|
|
|
|
|
+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 ImgCrop = ImgCropRaw as any
|
|
const width = 500
|
|
const width = 500
|
|
|
|
|
|
const domScreenshot = async (dom: HTMLElement) => {
|
|
const domScreenshot = async (dom: HTMLElement) => {
|
|
@@ -34,9 +35,9 @@ type SelectImageProps = {
|
|
|
|
|
|
|
|
|
|
let AMap: any
|
|
let AMap: any
|
|
-AMapLoader.load({
|
|
|
|
|
|
+AMapLoader.load({
|
|
plugins: ['AMap.PlaceSearch'],
|
|
plugins: ['AMap.PlaceSearch'],
|
|
- key: 'e661b00bdf2c44cccf71ef6070ef41b8',
|
|
|
|
|
|
+ key: 'e661b00bdf2c44cccf71ef6070ef41b8',
|
|
version: '2.0',
|
|
version: '2.0',
|
|
}).then(result => AMap = result)
|
|
}).then(result => AMap = result)
|
|
|
|
|
|
@@ -58,9 +59,9 @@ export const SelectMap = (props: SelectImageProps) => {
|
|
}
|
|
}
|
|
|
|
|
|
const renderInfo = info && <div className={style['def-map-info']}>
|
|
const renderInfo = info && <div className={style['def-map-info']}>
|
|
- <p><span>经度</span>{ info.lat }</p>
|
|
|
|
- <p><span>维度</span>{ info.lng }</p>
|
|
|
|
- <p><span>缩放级别</span>{ info.zoom }</p>
|
|
|
|
|
|
+ <p><span>经度</span>{info.lat}</p>
|
|
|
|
+ <p><span>维度</span>{info.lng}</p>
|
|
|
|
+ <p><span>缩放级别</span>{info.zoom}</p>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
@@ -74,11 +75,11 @@ export const SelectMap = (props: SelectImageProps) => {
|
|
resizeEnable: true
|
|
resizeEnable: true
|
|
})
|
|
})
|
|
const placeSearch = new AMap.PlaceSearch({
|
|
const placeSearch = new AMap.PlaceSearch({
|
|
- pageSize: 5,
|
|
|
|
- pageIndex: 1,
|
|
|
|
- map: map,
|
|
|
|
- panel: searchResultEle.current,
|
|
|
|
- autoFitView: true
|
|
|
|
|
|
+ pageSize: 5,
|
|
|
|
+ pageIndex: 1,
|
|
|
|
+ map: map,
|
|
|
|
+ panel: searchResultEle.current,
|
|
|
|
+ autoFitView: true
|
|
});
|
|
});
|
|
const getMapInfo = (): MapInfo => {
|
|
const getMapInfo = (): MapInfo => {
|
|
var zoom = map.getZoom(); //获取当前地图级别
|
|
var zoom = map.getZoom(); //获取当前地图级别
|
|
@@ -105,12 +106,12 @@ export const SelectMap = (props: SelectImageProps) => {
|
|
}, [keyword, searchAMap])
|
|
}, [keyword, searchAMap])
|
|
|
|
|
|
return (
|
|
return (
|
|
- <Modal
|
|
|
|
|
|
+ <Modal
|
|
width="588px"
|
|
width="588px"
|
|
- title="选择地址"
|
|
|
|
- open={open}
|
|
|
|
|
|
+ title="选择地址"
|
|
|
|
+ open={open}
|
|
onCancel={() => setOpen(false)}
|
|
onCancel={() => setOpen(false)}
|
|
- onOk={() => asyncLoading(onSubmit())}
|
|
|
|
|
|
+ onOk={() => asyncLoading(onSubmit())}
|
|
afterClose={props.onClose}
|
|
afterClose={props.onClose}
|
|
okText="确定"
|
|
okText="确定"
|
|
cancelText="取消"
|
|
cancelText="取消"
|
|
@@ -118,23 +119,23 @@ export const SelectMap = (props: SelectImageProps) => {
|
|
<div className={style['search-layout']}>
|
|
<div className={style['search-layout']}>
|
|
<Input.Search
|
|
<Input.Search
|
|
allowClear
|
|
allowClear
|
|
- placeholder="输入名称搜索"
|
|
|
|
|
|
+ placeholder="输入名称搜索"
|
|
onSearch={setKeyword}
|
|
onSearch={setKeyword}
|
|
- style={{ width: 350 }}
|
|
|
|
|
|
+ style={{width: 350}}
|
|
/>
|
|
/>
|
|
- <div
|
|
|
|
- className={`${style['search-result']} ${keyword ? style['show']: ''}`}
|
|
|
|
- ref={searchResultEle}
|
|
|
|
|
|
+ <div
|
|
|
|
+ className={`${style['search-result']} ${keyword ? style['show'] : ''}`}
|
|
|
|
+ ref={searchResultEle}
|
|
/>
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div ref={mapEle} className={style['def-select-map']}></div>
|
|
<div ref={mapEle} className={style['def-select-map']}></div>
|
|
- { renderInfo }
|
|
|
|
|
|
+ {renderInfo}
|
|
</Modal>
|
|
</Modal>
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
|
|
const getFuseUrl = (caseId: number) =>
|
|
const getFuseUrl = (caseId: number) =>
|
|
- `${getHref(SceneTypeDomain[SceneType.SWMX]!, SceneTypePaths[SceneType.SWMX][0], { caseId: caseId.toString() })}&share=1#show/summary`
|
|
|
|
|
|
+ `${getHref(SceneTypeDomain[SceneType.SWMX]!, SceneTypePaths[SceneType.SWMX][0], {caseId: caseId.toString()})}&share=1#show/summary`
|
|
|
|
|
|
|
|
|
|
enum ImageType {
|
|
enum ImageType {
|
|
@@ -142,10 +143,11 @@ enum ImageType {
|
|
KANKAN,
|
|
KANKAN,
|
|
LASER
|
|
LASER
|
|
}
|
|
}
|
|
|
|
+
|
|
type FuseImageRet = { type: ImageType, blob: Blob | null }
|
|
type FuseImageRet = { type: ImageType, blob: Blob | null }
|
|
const getFuseImage = async (iframe: HTMLIFrameElement) => {
|
|
const getFuseImage = async (iframe: HTMLIFrameElement) => {
|
|
const iframeElement = iframe.contentWindow?.document.documentElement
|
|
const iframeElement = iframe.contentWindow?.document.documentElement
|
|
-
|
|
|
|
|
|
+
|
|
if (!iframeElement) {
|
|
if (!iframeElement) {
|
|
return null
|
|
return null
|
|
}
|
|
}
|
|
@@ -153,12 +155,12 @@ const getFuseImage = async (iframe: HTMLIFrameElement) => {
|
|
const targetIframe = extIframe || iframe
|
|
const targetIframe = extIframe || iframe
|
|
const targetWindow: any = targetIframe.contentWindow
|
|
const targetWindow: any = targetIframe.contentWindow
|
|
const fuseCnavas = targetWindow.document.querySelector('.scene-canvas > canvas') as HTMLElement
|
|
const fuseCnavas = targetWindow.document.querySelector('.scene-canvas > canvas') as HTMLElement
|
|
-
|
|
|
|
|
|
+
|
|
if (fuseCnavas) {
|
|
if (fuseCnavas) {
|
|
const dataURL = await targetWindow.sdk.screenshot(targetIframe.offsetWidth, targetIframe.offsetHeight)
|
|
const dataURL = await targetWindow.sdk.screenshot(targetIframe.offsetWidth, targetIframe.offsetHeight)
|
|
const res = await fetch(dataURL)
|
|
const res = await fetch(dataURL)
|
|
const blob = await res.blob()
|
|
const blob = await res.blob()
|
|
- return { type: ImageType.FUSE, blob }
|
|
|
|
|
|
+ return {type: ImageType.FUSE, blob}
|
|
// return domScreenshot(fuseCnavas).then(blob => ({ type: ImageType.FUSE, blob }))
|
|
// return domScreenshot(fuseCnavas).then(blob => ({ type: ImageType.FUSE, blob }))
|
|
}
|
|
}
|
|
const isLaser = targetWindow.document.querySelector('.laser-layer')
|
|
const isLaser = targetWindow.document.querySelector('.laser-layer')
|
|
@@ -167,14 +169,14 @@ const getFuseImage = async (iframe: HTMLIFrameElement) => {
|
|
const sdk = await targetWindow.__sdk
|
|
const sdk = await targetWindow.__sdk
|
|
return new Promise<FuseImageRet>(resolve => {
|
|
return new Promise<FuseImageRet>(resolve => {
|
|
sdk.scene.screenshot(width, width).done((data: string) => {
|
|
sdk.scene.screenshot(width, width).done((data: string) => {
|
|
- resolve({ type: ImageType.FUSE, blob: base64ToBlob(data) })
|
|
|
|
|
|
+ resolve({type: ImageType.FUSE, blob: base64ToBlob(data)})
|
|
})
|
|
})
|
|
})
|
|
})
|
|
} else {
|
|
} else {
|
|
const sdk = targetWindow.__sdk
|
|
const sdk = targetWindow.__sdk
|
|
return new Promise<FuseImageRet>(resolve => {
|
|
return new Promise<FuseImageRet>(resolve => {
|
|
- sdk.Camera.screenshot([ {width: width, height: width, name: '2k' }],false).then((result: any)=>{
|
|
|
|
- resolve({ type: ImageType.KANKAN, blob: base64ToBlob(result[0].data) })
|
|
|
|
|
|
+ sdk.Camera.screenshot([{width: width, height: width, name: '2k'}], false).then((result: any) => {
|
|
|
|
+ resolve({type: ImageType.KANKAN, blob: base64ToBlob(result[0].data)})
|
|
})
|
|
})
|
|
})
|
|
})
|
|
}
|
|
}
|
|
@@ -190,8 +192,8 @@ export const SelectFuse = (props: SelectImageProps & { caseId: number }) => {
|
|
const coverUrl = useMemo(() => blob && URL.createObjectURL(blob), [blob])
|
|
const coverUrl = useMemo(() => blob && URL.createObjectURL(blob), [blob])
|
|
const url = useMemo(() => getFuseUrl(props.caseId), [props.caseId])
|
|
const url = useMemo(() => getFuseUrl(props.caseId), [props.caseId])
|
|
const addTags = useMemo(() => addTagIds.map(id => tags.find(tag => tag.tagId.toString() === id)!), [addTagIds, tags])
|
|
const addTags = useMemo(() => addTagIds.map(id => tags.find(tag => tag.tagId.toString() === id)!), [addTagIds, tags])
|
|
- const mockData = useMemo(() => tags.map(tag => ({
|
|
|
|
- data: tag,
|
|
|
|
|
|
+ const mockData = useMemo(() => tags.map(tag => ({
|
|
|
|
+ data: tag,
|
|
key: tag.tagId.toString()
|
|
key: tag.tagId.toString()
|
|
})), [tags])
|
|
})), [tags])
|
|
|
|
|
|
@@ -254,13 +256,13 @@ export const SelectFuse = (props: SelectImageProps & { caseId: number }) => {
|
|
ctx.restore()
|
|
ctx.restore()
|
|
}
|
|
}
|
|
})
|
|
})
|
|
-
|
|
|
|
|
|
+
|
|
const $ccanvas = document.createElement('canvas')
|
|
const $ccanvas = document.createElement('canvas')
|
|
$ccanvas.width = width
|
|
$ccanvas.width = width
|
|
$ccanvas.height = width
|
|
$ccanvas.height = width
|
|
const cctx = $ccanvas.getContext('2d')!
|
|
const cctx = $ccanvas.getContext('2d')!
|
|
drawImage(
|
|
drawImage(
|
|
- cctx,
|
|
|
|
|
|
+ cctx,
|
|
$ccanvas.width,
|
|
$ccanvas.width,
|
|
$ccanvas.height,
|
|
$ccanvas.height,
|
|
$canvas,
|
|
$canvas,
|
|
@@ -268,7 +270,7 @@ export const SelectFuse = (props: SelectImageProps & { caseId: number }) => {
|
|
img.height,
|
|
img.height,
|
|
0, 0
|
|
0, 0
|
|
)
|
|
)
|
|
-
|
|
|
|
|
|
+
|
|
console.error('???')
|
|
console.error('???')
|
|
const blob = await new Promise<Blob | null>(resolve => $ccanvas.toBlob(resolve, 'png'))
|
|
const blob = await new Promise<Blob | null>(resolve => $ccanvas.toBlob(resolve, 'png'))
|
|
setBlob(blob)
|
|
setBlob(blob)
|
|
@@ -277,23 +279,23 @@ export const SelectFuse = (props: SelectImageProps & { caseId: number }) => {
|
|
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
- <Modal
|
|
|
|
|
|
+ <Modal
|
|
width="1500px"
|
|
width="1500px"
|
|
- title="选择户型图"
|
|
|
|
- open={open}
|
|
|
|
|
|
+ title="选择户型图"
|
|
|
|
+ open={open}
|
|
onCancel={() => setOpen(false)}
|
|
onCancel={() => setOpen(false)}
|
|
- onOk={() => asyncLoading(onSubmit())}
|
|
|
|
|
|
+ onOk={() => asyncLoading(onSubmit())}
|
|
afterClose={props.onClose}
|
|
afterClose={props.onClose}
|
|
okText="确定"
|
|
okText="确定"
|
|
cancelText="取消"
|
|
cancelText="取消"
|
|
>
|
|
>
|
|
<div className={style['house-layout']}>
|
|
<div className={style['house-layout']}>
|
|
<div className={style['iframe-layout']}>
|
|
<div className={style['iframe-layout']}>
|
|
- <iframe src={url} ref={iframeRef} title="fuce-code" />
|
|
|
|
|
|
+ <iframe src={url} ref={iframeRef} title="fuce-code"/>
|
|
</div>
|
|
</div>
|
|
<div className={style['content-layout']}>
|
|
<div className={style['content-layout']}>
|
|
<div className={style['house-tags']}>
|
|
<div className={style['house-tags']}>
|
|
- <h4>请选择要同步到现场图的标注:</h4>
|
|
|
|
|
|
+ <h4>请选择要同步到现场图的标注:</h4>
|
|
<div className={style['tagging-transfer']}>
|
|
<div className={style['tagging-transfer']}>
|
|
<SortTransfer
|
|
<SortTransfer
|
|
dataSource={mockData}
|
|
dataSource={mockData}
|
|
@@ -305,15 +307,15 @@ export const SelectFuse = (props: SelectImageProps & { caseId: number }) => {
|
|
onChangeSort={tags => setAddTagIds(tags.map(tag => tag.data.tagId.toString()))}
|
|
onChangeSort={tags => setAddTagIds(tags.map(tag => tag.data.tagId.toString()))}
|
|
/>
|
|
/>
|
|
</div>
|
|
</div>
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
<div className={style['house-image-layout']}>
|
|
<div className={style['house-image-layout']}>
|
|
- <h4>户型图:<RedoOutlined className='icon' onClick={getCover} /></h4>
|
|
|
|
|
|
+ <h4>户型图:<RedoOutlined className='icon' onClick={getCover}/></h4>
|
|
<div className={style['house-image']}>
|
|
<div className={style['house-image']}>
|
|
<div>
|
|
<div>
|
|
- { coverUrl ? <img src={coverUrl} alt="预览图" /> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /> }
|
|
|
|
|
|
+ {coverUrl ? <img src={coverUrl} alt="预览图"/> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}/>}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Modal>
|
|
</Modal>
|
|
@@ -321,12 +323,12 @@ export const SelectFuse = (props: SelectImageProps & { caseId: number }) => {
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-
|
|
|
|
type DfUploadCropProp = Partial<SelectImageProps> & {
|
|
type DfUploadCropProp = Partial<SelectImageProps> & {
|
|
type: BoardType
|
|
type: BoardType
|
|
caseId: number
|
|
caseId: number
|
|
}
|
|
}
|
|
-export const DfUploadCrop = ({ type, caseId, onClose, onSave }: DfUploadCropProp) => {
|
|
|
|
|
|
+export const DfUploadCrop = ({type, caseId, onClose, onSave}: DfUploadCropProp) => {
|
|
|
|
+ const [minZoom, setMinZoom] = useState(1)
|
|
const onUpload: UploadProps['beforeUpload'] = async file => {
|
|
const onUpload: UploadProps['beforeUpload'] = async file => {
|
|
|
|
|
|
const img = new Image();
|
|
const img = new Image();
|
|
@@ -349,7 +351,6 @@ export const DfUploadCrop = ({ type, caseId, onClose, onSave }: DfUploadCropProp
|
|
|
|
|
|
const ext = filename.substring(filename.lastIndexOf('.'))
|
|
const ext = filename.substring(filename.lastIndexOf('.'))
|
|
const isImg = ['.png', '.jpg'].includes(ext.toLocaleLowerCase())
|
|
const isImg = ['.png', '.jpg'].includes(ext.toLocaleLowerCase())
|
|
- console.log(filename)
|
|
|
|
if (!isImg) {
|
|
if (!isImg) {
|
|
message.error('只能上传png或jpg文件')
|
|
message.error('只能上传png或jpg文件')
|
|
return Upload.LIST_IGNORE
|
|
return Upload.LIST_IGNORE
|
|
@@ -357,14 +358,44 @@ export const DfUploadCrop = ({ type, caseId, onClose, onSave }: DfUploadCropProp
|
|
message.error('大小在100MB以内')
|
|
message.error('大小在100MB以内')
|
|
return Upload.LIST_IGNORE
|
|
return Upload.LIST_IGNORE
|
|
} else {
|
|
} else {
|
|
- return true
|
|
|
|
|
|
+ return new Promise(async (resolve) => {
|
|
|
|
+ const img = new Image()
|
|
|
|
+ img.src = URL.createObjectURL(file)
|
|
|
|
+ await new Promise(resolve => img.onload = resolve)
|
|
|
|
+ const size = img.width > img.height ? img.width : img.height
|
|
|
|
+ const $canvas = document.createElement('canvas')
|
|
|
|
+ $canvas.width = size
|
|
|
|
+ $canvas.height = size
|
|
|
|
+ const ctx = $canvas.getContext('2d')!
|
|
|
|
+ ctx.drawImage(
|
|
|
|
+ img,
|
|
|
|
+ (size - img.width) / 2,
|
|
|
|
+ (size - img.height) / 2,
|
|
|
|
+ img.width,
|
|
|
|
+ img.height
|
|
|
|
+ )
|
|
|
|
+ const blob = await new Promise<Blob | null>(resolve => $canvas.toBlob(resolve, 'png'))
|
|
|
|
+ if (blob) {
|
|
|
|
+ resolve(new File([blob], "test.png"))
|
|
|
|
+ } else {
|
|
|
|
+ resolve(blob)
|
|
|
|
+ }
|
|
|
|
+ })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ console.log(minZoom)
|
|
|
|
+
|
|
return (
|
|
return (
|
|
- <ImgCrop beforeCrop={beforeCrop} rotationSlider modalTitle={"裁剪" + BoardTypeDesc[type]} aspect={width / width} minZoom={1} maxZoom={5}>
|
|
|
|
- <Upload beforeUpload={onUpload} multiple={false} accept="png">
|
|
|
|
- <Button type="primary" ghost block>上传{ BoardTypeDesc[type] }</Button>
|
|
|
|
|
|
+ <ImgCrop
|
|
|
|
+ beforeCrop={beforeCrop}
|
|
|
|
+ modalTitle={"裁剪" + BoardTypeDesc[type]}
|
|
|
|
+ aspect={width / width}
|
|
|
|
+ aspectSlider
|
|
|
|
+ maxZoom={5}
|
|
|
|
+ minZoom={minZoom}>
|
|
|
|
+ <Upload beforeUpload={onUpload} multiple={false} accept="png">
|
|
|
|
+ <Button type="primary" ghost block>上传{BoardTypeDesc[type]}</Button>
|
|
</Upload>
|
|
</Upload>
|
|
</ImgCrop>
|
|
</ImgCrop>
|
|
)
|
|
)
|