123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- import { useEffect, useMemo, useState } from "react"
- import { Button, Form, Input, Modal, Select } 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'
- 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>
- )
- 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'> }) => (
- <Form.Item label="内容">
- <Input
- style={{ width: 120 }}
- defaultValue={shape.data.text}
- onChange={(ev) => shape.setText(ev.target.value)}
- />
- </Form.Item>
- )
- 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]) || ''
- }
- return source
- }
- const tableAttrs = useMemo(() => ({
- columns: refer.map((item, i) => ({
- title: `列${i + 1}`,
- dataIndex: i,
- key: i,
- editor: {
- type: 'input',
- component: InputEditor
- }
- })),
- 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
- setContent(newContent)
- }
- const onDelete = (data: any) => {
- const newContent = [...content]
- newContent.splice(data.rowIndex, 1)
- setContent(newContent)
- }
- const onInsert = () => {
- setContent([...content, refer.map(() => '')])
- }
- const onSubmit = () => {
- const rowEls = Array.from(document.querySelectorAll('#edit-table .body-container .row-container')) as HTMLDivElement[]
- const bound = rowEls.map(row => {
- const cells = Array.from(row.querySelectorAll('.cell')) as HTMLDivElement[]
- return {
- height: row.offsetHeight - 1,
- cellWidths: cells.slice(0, -1).map(cell => cell.offsetWidth)
- }
- })
- console.log(bound, content)
- }
- useEffect(() => {
- if (!edit) {
- setContent(shape.data.content || [['', '']])
- }
- }, [edit, shape.data.content])
- return (
- <Form.Item label="内容">
- <Button type="primary" onClick={() => setEdit(true)}>编辑</Button>
- <Modal open={edit} onCancel={() => setEdit(false)} onOk={onSubmit}>
- <div id="edit-table">
- <ReactEditeTable
- {...tableAttrs}
- onDelete={onDelete}
- onChange={onChange}
- />
- <div className={style['add-table-row']}>
- <Button onClick={onInsert} type="primary">
- <PlusOutlined className="icon" /> 行
- </Button>
- </div>
- </div>
- </Modal>
- </Form.Item>
- )
- }
- 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
- }
- export type EShapeProps = {
- board: RefObject<Board>
- }
- export const EShape = ({ board }: EShapeProps) => {
- const [shape, setShape] = useState<BoardShape | null>(null)
- useEffect(() => {
- if (board.current) {
- const boardRef = board.current
- boardRef.bus.on('selectShape', setShape)
- return () => boardRef.bus.off('selectShape', setShape)
- }
- }, [board])
- const Edit = shape && shapeCompontes[shape.data.type]
- return Edit && (
- <div className={style['def-shape-edit']}>
- <Edit shape={shape} />
- <div className={`ant-form-item ${style['def-close-shape-edit']}`} onClick={() => setShape(null)}>
- <CloseOutlined className={`${style['icon']}`} />
- </div>
- </div>
- )
- }
- export default EShape
|