|
@@ -1,7 +1,6 @@
|
|
|
import { useEffect, useMemo, useState } from "react"
|
|
|
-import { Button, Form, Input, Modal, Select } from 'antd'
|
|
|
+import { Button, Form, Modal, Input } from 'antd'
|
|
|
import { CloseOutlined, PlusOutlined } from '@ant-design/icons'
|
|
|
-import InputColor from 'react-input-color';
|
|
|
import style from './style.module.scss'
|
|
|
import ReactEditeTable, { InputEditor } from 'react-edit-table'
|
|
|
|
|
@@ -9,27 +8,29 @@ import type { Board, BoardShape, ShapeType, ExtractShape } from "./board"
|
|
|
import type { RefObject, ComponentType } from 'react'
|
|
|
|
|
|
|
|
|
-const ColorInput = ({ shape }: { shape: BoardShape }) => (
|
|
|
- <Form.Item label="颜色" className={style['def-color-item']}>
|
|
|
- <InputColor
|
|
|
- initialValue={shape.data.color || '#000'}
|
|
|
- onChange={(color) => shape.setColor(color.rgba)}
|
|
|
- />
|
|
|
- </Form.Item>
|
|
|
-)
|
|
|
+// import { Select } from 'antd'
|
|
|
+// import InputColor from 'react-input-color';
|
|
|
+// const ColorInput = ({ shape }: { shape: BoardShape }) => (
|
|
|
+// <Form.Item label="颜色" className={style['def-color-item']}>
|
|
|
+// <InputColor
|
|
|
+// initialValue={shape.data.color || '#000'}
|
|
|
+// onChange={(color) => shape.setColor(color.rgba)}
|
|
|
+// />
|
|
|
+// </Form.Item>
|
|
|
+// )
|
|
|
|
|
|
-const sizeOptions = [6,7,8,9,10,11,12,13,14,16,18,20,28,36,48,72]
|
|
|
- .map(size => ({ label: `${size}px`, value: size }))
|
|
|
-const FontSizeInput = ({ shape }: { shape: ExtractShape<'fontSize'> }) => (
|
|
|
- <Form.Item label="字号">
|
|
|
- <Select
|
|
|
- defaultValue={shape.data.fontSize}
|
|
|
- style={{ width: 80 }}
|
|
|
- onChange={(size) => shape.setFontSize(size)}
|
|
|
- options={sizeOptions}
|
|
|
- />
|
|
|
- </Form.Item>
|
|
|
-)
|
|
|
+// const sizeOptions = [6,7,8,9,10,11,12,13,14,16,18,20,28,36,48,72]
|
|
|
+// .map(size => ({ label: `${size}px`, value: size }))
|
|
|
+// const FontSizeInput = ({ shape }: { shape: ExtractShape<'fontSize'> }) => (
|
|
|
+// <Form.Item label="字号">
|
|
|
+// <Select
|
|
|
+// defaultValue={shape.data.fontSize}
|
|
|
+// style={{ width: 80 }}
|
|
|
+// onChange={(size) => shape.setFontSize(size)}
|
|
|
+// options={sizeOptions}
|
|
|
+// />
|
|
|
+// </Form.Item>
|
|
|
+// )
|
|
|
|
|
|
|
|
|
const TextInput = ({ shape }: { shape: ExtractShape<'text'> }) => (
|
|
@@ -44,54 +45,79 @@ const TextInput = ({ shape }: { shape: ExtractShape<'text'> }) => (
|
|
|
|
|
|
const ContentInput = ({ shape }: { shape: ExtractShape<'content'> }) => {
|
|
|
const [edit, setEdit] = useState(false)
|
|
|
- const [content, setContent] = useState(shape.data.content || [['', '']])
|
|
|
- // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
- const refer = content[0] || ['', '']
|
|
|
- const transformRow = (columns: any[], row?: string[]) => {
|
|
|
- const source: { [key in number]: string } = {}
|
|
|
- for (let i = 0; i < columns.length; i++) {
|
|
|
- source[i] = (row && row[i]) || ''
|
|
|
+ const [content, setContent] = useState(shape.data.content)
|
|
|
+ const refer = content.filter(item => item.rowIndex === 0)
|
|
|
+ const tableAttrs = useMemo(() => {
|
|
|
+ const dataSource: string[][] = []
|
|
|
+ content.forEach(item => {
|
|
|
+ let columns = dataSource[item.rowIndex]
|
|
|
+ if (!columns) {
|
|
|
+ columns = dataSource[item.rowIndex] = []
|
|
|
}
|
|
|
- return source
|
|
|
- }
|
|
|
- const tableAttrs = useMemo(() => ({
|
|
|
- columns: refer.map((item, i) => ({
|
|
|
- title: `列${i + 1}`,
|
|
|
- dataIndex: i,
|
|
|
- key: i,
|
|
|
- editor: {
|
|
|
- type: 'input',
|
|
|
- component: InputEditor
|
|
|
+ columns[item.colIndex] = item.value
|
|
|
+ })
|
|
|
+
|
|
|
+ return {
|
|
|
+ columns: refer.map((item, i) => ({
|
|
|
+ title: `列${i + 1}`,
|
|
|
+ dataIndex: i,
|
|
|
+ key: i,
|
|
|
+ editor: {
|
|
|
+ type: 'input',
|
|
|
+ component: InputEditor
|
|
|
+ }
|
|
|
+ })),
|
|
|
+ dataSource
|
|
|
+ }
|
|
|
+ }, [content, refer])
|
|
|
+ const sortContent = () =>
|
|
|
+ content.sort((a, b) => {
|
|
|
+ const rowDiff = a.rowIndex - b.rowIndex
|
|
|
+ if (rowDiff) {
|
|
|
+ return rowDiff
|
|
|
+ } else {
|
|
|
+ return a.colIndex - b.colIndex
|
|
|
}
|
|
|
- })),
|
|
|
- dataSource: content.map(item => transformRow(refer, item))
|
|
|
- }), [content, refer])
|
|
|
-
|
|
|
+ })
|
|
|
+
|
|
|
const onChange = (data: any) => {
|
|
|
const newContent = [...content]
|
|
|
- newContent[data.rowIndex] = [...newContent[data.rowIndex]]
|
|
|
- newContent[data.rowIndex][data.key] = data.newValue
|
|
|
+ const item = newContent.find(item => item.rowIndex === data.rowIndex && item.colIndex === data.key)
|
|
|
+ item!.value = data.newValue
|
|
|
setContent(newContent)
|
|
|
}
|
|
|
const onDelete = (data: any) => {
|
|
|
- const newContent = [...content]
|
|
|
- newContent.splice(data.rowIndex, 1)
|
|
|
- setContent(newContent)
|
|
|
+ const newContent = sortContent()
|
|
|
+ const startIndex = newContent.findIndex(item => item.rowIndex === data.rowIndex)
|
|
|
+ const endIndex = startIndex + refer.length
|
|
|
+ setContent([
|
|
|
+ ...newContent.slice(0, startIndex),
|
|
|
+ ...newContent.slice(endIndex).map(item => ({...item, rowIndex: --item.rowIndex}))
|
|
|
+ ])
|
|
|
}
|
|
|
const onInsert = () => {
|
|
|
- setContent([...content, refer.map(() => '')])
|
|
|
+ const maxRow = Math.max(...content.map(item => item.rowIndex))
|
|
|
+ setContent([
|
|
|
+ ...content,
|
|
|
+ ...refer.map(item => ({ ...item, value: '', rowIndex: maxRow + 1 }))
|
|
|
+ ])
|
|
|
}
|
|
|
+
|
|
|
const onSubmit = () => {
|
|
|
const rowEls = Array.from(document.querySelectorAll('#edit-table .body-container .row-container')) as HTMLDivElement[]
|
|
|
- const bound = rowEls.map(row => {
|
|
|
+ const bound = rowEls.map((row, rowIndex) => {
|
|
|
const cells = Array.from(row.querySelectorAll('.cell')) as HTMLDivElement[]
|
|
|
- return {
|
|
|
+ return cells.slice(0, -1).map((cell, colIndex) => ({
|
|
|
+ width: cell.offsetWidth,
|
|
|
height: row.offsetHeight - 1,
|
|
|
- cellWidths: cells.slice(0, -1).map(cell => cell.offsetWidth)
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- console.log(bound, content)
|
|
|
+ value: content.find(item => item.rowIndex === rowIndex && item.colIndex === colIndex)!.value,
|
|
|
+ colIndex,
|
|
|
+ rowIndex
|
|
|
+ }))
|
|
|
+ }).flat()
|
|
|
+ setContent(bound)
|
|
|
+ shape.setContent(bound)
|
|
|
+ setEdit(false)
|
|
|
}
|
|
|
|
|
|
useEffect(() => {
|
|
@@ -121,23 +147,9 @@ const ContentInput = ({ shape }: { shape: ExtractShape<'content'> }) => {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
-const shapeCompontes: { [key in ShapeType]: ComponentType<{ shape: any }> } = {
|
|
|
- Wall: ColorInput,
|
|
|
- Tag: (props) => <><ColorInput {...props} /><FontSizeInput {...props} /><TextInput {...props} /> </>,
|
|
|
- Table: (props) => <><ColorInput {...props} /><FontSizeInput {...props} /><ContentInput {...props} /> </>,
|
|
|
- Rectangle: ColorInput,
|
|
|
- Circle: ColorInput,
|
|
|
- Arrow: ColorInput,
|
|
|
- Icon: ColorInput,
|
|
|
- Cigaret: ColorInput,
|
|
|
- FirePoint: ColorInput,
|
|
|
- LeftFootPrint: ColorInput,
|
|
|
- RightFootPrint: ColorInput,
|
|
|
- LeftShoePrint: ColorInput,
|
|
|
- RightShoePrint: ColorInput,
|
|
|
- FingerPrint: ColorInput,
|
|
|
- DeadBody: ColorInput,
|
|
|
- BloodStain: ColorInput
|
|
|
+const shapeCompontes: { [key in ShapeType]?: ComponentType<{ shape: any }> } = {
|
|
|
+ Tag: (props) => <><TextInput {...props} /> </>,
|
|
|
+ Table: (props) => <><ContentInput {...props} /> </>,
|
|
|
}
|
|
|
|
|
|
export type EShapeProps = {
|
|
@@ -145,6 +157,7 @@ export type EShapeProps = {
|
|
|
}
|
|
|
export const EShape = ({ board }: EShapeProps) => {
|
|
|
const [shape, setShape] = useState<BoardShape | null>(null)
|
|
|
+ const Edit = shape && shapeCompontes[shape.data.type]
|
|
|
|
|
|
useEffect(() => {
|
|
|
if (board.current) {
|
|
@@ -154,15 +167,17 @@ export const EShape = ({ board }: EShapeProps) => {
|
|
|
}
|
|
|
}, [board])
|
|
|
|
|
|
- const Edit = shape && shapeCompontes[shape.data.type]
|
|
|
- return Edit && (
|
|
|
+ return shape ? (
|
|
|
<div className={style['def-shape-edit']}>
|
|
|
- <Edit shape={shape} />
|
|
|
+ { Edit && <Edit shape={shape} /> }
|
|
|
+ <Form.Item label="形状">
|
|
|
+ <Button type="primary" onClick={() => shape.delete()}>删除</Button>
|
|
|
+ </Form.Item>
|
|
|
<div className={`ant-form-item ${style['def-close-shape-edit']}`} onClick={() => setShape(null)}>
|
|
|
- <CloseOutlined className={`${style['icon']}`} />
|
|
|
+ <CloseOutlined className={`${style['icon']}`} onClick={() => board.current?.unSelectShape()} />
|
|
|
</div>
|
|
|
</div>
|
|
|
- )
|
|
|
+ ) : <></>
|
|
|
}
|
|
|
|
|
|
export default EShape
|