Commit 6eeb558c authored by 田翔's avatar 田翔

fix: 更换拖拽组件

parent 192384e4
{
"name": "panda-xform",
"version": "3.10.5",
"description": "3.10.5: 版本升级",
"version": "3.10.6",
"description": "3.10.6: 更换拖拽组件",
"keywords": [
"panda-xform"
],
......@@ -30,19 +30,17 @@
"@wisdom-components/empty": "^1.4.7",
"antd": "4.20.7",
"antd-img-crop": "^3.14.1",
"array-move": "^4.0.0",
"form-render": "1.14.7",
"fr-generator": "2.8.3",
"http-proxy-middleware": "^1.0.6",
"moment": "^2.29.1",
"qrcode.react": "^3.1.0",
"react": "17.0.2",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-file-viewer": "^1.2.1",
"react-sign2": "^0.0.3",
"react-sortable-hoc": "^2.0.0",
"react-sortablejs": "^6.1.4",
"react-svg": "15.1.9",
"sortablejs": "^1.15.0",
"yarn": "^1.22.17"
},
"devDependencies": {
......@@ -50,7 +48,6 @@
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-syntax-jsx": "^7.12.13",
"@babel/plugin-transform-modules-amd": "^7.14.5",
"@types/sortablejs": "^1.15.1",
"@umijs/fabric": "^2.0.7",
"@wisdom-map/amap": "1.1.0-beta.45",
"@wisdom-map/arcgismap": "1.4.0-124",
......
import React, { useState, useRef, useEffect, useContext, useMemo, useLayoutEffect } from 'react'
import { MenuOutlined } from '@ant-design/icons'
import { Table, Input, Form, Popover, Popconfirm } from 'antd'
import { arrayMoveImmutable } from 'array-move'
import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc'
import { CheckOutlined, DeleteOutlined } from '@ant-design/icons'
import styles from './index.less'
const colors = [
// '#ffccc7', '#ffe7ba', '#fffb8f', '#d9f7be', '#b5f5ec',
// '#bae7ff', '#d6e4ff', '#efdbff', '#ffd6e7', '#e8e8e8',
// '#ff4d4f', '#ffa940', '#fbce00', '#73d13d', '#36cfc9',
// '#40a9ff', '#597ef7', '#9254de', '#f759ab', '#8c8c8c',
'rgb(255, 77, 79)',
'rgb(255, 169, 64)',
'rgb(251, 206, 0)',
'rgba(115, 209, 61)',
'rgba(54, 207, 201)',
'rgba(64, 169, 255)',
'rgba(89, 126, 247)',
'rgba(146, 84, 222)',
'rgba(247, 89, 171)',
'rgba(140, 140, 140)',
// 'rgba(255, 204, 199)',
// 'rgba(255, 231, 186)',
// 'rgba(255, 251, 143)',
// 'rgba(217, 247, 190)',
// 'rgba(181, 245, 236)',
// 'rgba(186, 231, 255)',
// 'rgba(214, 228, 255)',
// 'rgba(239, 219, 255)',
// 'rgba(255, 214, 231)',
// 'rgba(232, 232, 232)',
]
let newData = []
const EditableContext = React.createContext(null)
const DragHandle = SortableHandle(() => (
<MenuOutlined
style={{
cursor: 'grab',
color: '#999',
}}
/>
))
const SortableItem = SortableElement((props) => {
const [form] = Form.useForm()
return (
<Form form={form} component={false}>
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
</Form>
)
})
const SortableBody = SortableContainer((props) => <tbody {...props} />)
// const InputItem = (props) => {
// const inputRef = useRef(null)
// useLayoutEffect(() => {
// inputRef.current.focus()
// }, [])
// return (
// <Input ref={inputRef} {...props} />
// )
// }
const DragTable = (props) => {
const { dataSource, setDataSource, color } = props
const onSortEnd = ({ oldIndex, newIndex }) => {
if (oldIndex !== newIndex) {
const data = arrayMoveImmutable(dataSource.slice(), oldIndex, newIndex).filter(
(el) => !!el,
)
setDataSource(data)
import React, { useState, useEffect, useRef } from 'react';
import { Table } from 'antd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { DndProvider, useDrag, useDrop } from 'react-dnd';
import classnames from 'classnames';
import styles from './index.less';
const DraggableBodyRow = ({
name,
index,
moveRow,
className,
style,
tableType,
ItemTypes,
...restProps
}) => {
const [type, setType] = useState('');
const ref = useRef();
useEffect(() => {
if (ItemTypes) {
setType(ItemTypes);
}
}
const DraggableContainer = (props) => (
<SortableBody
useDragHandle
disableAutoscroll
helperClass="row-dragging"
onSortEnd={onSortEnd}
{...props}
/>
)
const DraggableBodyRow = ({ className, style, ...restProps }) => {
// const index = dataSource.findIndex((x) => x.index === restProps['data-row-key'])
// return <SortableItem key={index} index={index} {...restProps} />
let key = Number(restProps['data-row-key'])
return <SortableItem key={key} index={key} {...restProps} />
}
const onPressEnter = (i) => {
let length = [...dataSource].length
let array = [...dataSource]
array.splice(i + 1, 0, { key: `${length + 1}`, index: length + 1, value: '' })
setDataSource(array)
}
const inputChange = (value, i) => {
let array = []
dataSource.forEach((v, index) => {
if (index === i) {
v.value = value
}
array.push({ ...v })
})
newData = array
}
const colorClick = (value, i) => {
let array = []
dataSource.forEach((v, index) => {
if (index === i) {
v.color = value
}, [ItemTypes]);
const [{ isOver, dropClassName }, drop] = useDrop({
accept: type,
collect: monitor => {
const { index: dragIndex } = monitor.getItem() || {};
if (dragIndex === index) {
return {};
}
array.push({ ...v })
})
setDataSource(array)
}
const onBlur = () => {
if (Array.isArray(newData) && newData.length) {
setDataSource(newData)
return {
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
dropClassName: dragIndex < index ? 'drop-over-downward' : 'drop-over-upward',
};
},
drop: item => {
moveRow(item.index, index, tableType);
},
});
const [, drag] = useDrag({
type,
item: { index },
collect: monitor => ({
isDragging: monitor.isDragging(),
}),
});
drop(drag(ref));
return (
<tr
ref={ref}
className={classnames({
[className]: true,
[styles[dropClassName]]: isOver,
})}
style={{ cursor: 'move', ...style }}
{...restProps}
/>
);
};
const DragTable = props => {
const { columns, dataSource, dragCallBack, ItemTypes } = props;
// const [data, setData] = useState(null); // 分组后的数组
const components = {
body: {
row: DraggableBodyRow,
},
};
// useEffect(() => {
// if (dataSource.length > 0) {
// setData(dataSource);
// }
// }, [dataSource]);
// 每次拖拽后返回
// useEffect(() => {
// dragCallBack(data);
// }, [data]);
// 移动数组元素到指定位置
const moveInArray = (arr, from, to) => {
// 确保是有效数组
if (Object.prototype.toString.call(arr) !== '[object Array]') {
throw new Error('Please provide a valid array');
}
}
const confirm = (index) => {
let array = []
dataSource.forEach((v, i) => {
if (i !== index) {
array.push({ ...v })
}
})
newData = array
setDataSource(array)
}
const rest = (index) => {
let array = []
dataSource.forEach((v, i) => {
if (index === i) {
v.color = ''
}
array.push({ ...v })
})
setDataSource(array)
}
const columns = useMemo(() => {
let columns = [
{
title: 'value',
dataIndex: 'value',
render: (r, _, i) => {
return (
<Input
onPressEnter={() => onPressEnter(i)}
onChange={(e) => inputChange(e.target.value, i)}
defaultValue={r}
onBlur={() => onBlur()}
/>
)
}
},
{
title: 'color',
dataIndex: 'color',
width: 30,
render: (r, _, index) => {
const content = (
<div>
<div className={styles.colorTop}>
<div className={styles.topLeft}>请选择颜色</div>
<div className={styles.topRight} onClick={() => rest(index)}>重置</div>
</div>
<div className={styles.colorBox}>
{
colors.map((v, i) => {
return (
<div className={styles.colors} style={{ background: v }} onClick={() => colorClick(v, index)}>
<CheckOutlined style={{ fontSize: '11px', marginLeft: '5px', display: r === v ? 'inline-block' : 'none' }} />
</div>
)
})
}
</div>
</div>
)
return (
<Popover
content={content}
trigger='click'
>
<div className={styles.colors} style={{ background: r || '#f2f4f5' }}></div>
</Popover>
)
}
},
{
width: 30,
render: (r, _, i) => {
return (
<Popconfirm
title='确定删除?'
onConfirm={() => confirm(i)}
onCancel={() => { }}
>
<DeleteOutlined style={{ color: 'rgb(153, 153, 153)' }} />
</Popconfirm>
)
},
},
{
title: 'Sort',
dataIndex: 'sort',
width: 30,
className: 'drag-visible',
render: () => <DragHandle />,
},
]
if (!color) {
return columns.filter(v => v.dataIndex !== 'color')
// 删除当前的位置
let item = arr.splice(from, 1);
// 确保还剩有元素移动
if (!item.length) {
throw new Error(`There is no item in the array at index ${from}`);
}
return columns
}, [dataSource, color])
// 移动元素到指定位置
arr.splice(to, 0, item[0]);
return arr;
};
// 拖拽表格
const moveRow = (dragIndex, hoverIndex) => {
// setData(val => {
// let newData = JSON.parse(JSON.stringify(val));
// newData = moveInArray(newData, dragIndex, hoverIndex);
// return newData;
// });
let newData = JSON.parse(JSON.stringify(dataSource))
newData = moveInArray(newData, dragIndex, hoverIndex)
dragCallBack(newData)
}
return (
<Table
showHeader={false}
pagination={false}
dataSource={dataSource}
columns={columns}
rowKey="key"
size='small'
components={{
body: {
wrapper: DraggableContainer,
row: DraggableBodyRow,
},
}}
/>
<DndProvider backend={HTML5Backend}>
<Table
size='small'
columns={columns}
dataSource={dataSource}
components={components}
onRow={(record, index) => ({
index,
ItemTypes,
moveRow,
onClick: () => props.onClick && props.onClick(record),
})}
{...props}
/>
</DndProvider>
)
}
export default DragTable
\ No newline at end of file
export default DragTable;
.colorTop {
display: flex;
justify-content: space-between;
.topLeft {
font-size: 15px;
font-weight: 700;
color: #707070;
}
.topRight {
font-size: 12px;
color: #41b3ec;
&:hover {
cursor: pointer;
}
}
tr.drop-over-downward td {
border-bottom: 2px dashed #1890ff;
}
.colorBox {
width: 130px;
display: flex;
flex-wrap: wrap;
}
.colors {
width: 20px;
height: 20px;
border-radius: 50%;
margin-top: 6px;
margin-left: 6px;
&:hover {
cursor: pointer;
}
tr.drop-over-upward td {
border-top: 2px dashed #1890ff;
}
\ No newline at end of file
......@@ -263,6 +263,7 @@ const RelationForm = (props) => {
}
const getTableData = async (addFieldGroup) => {
console.log('addFieldGroup', addFieldGroup)
if (!addons) return
let queryWheres = getQueryWheres(addFieldGroup)
if (!queryWheres.length) {
......
import React, { useState, useRef, useContext, useEffect } from 'react'
import React, { useState, useRef, useContext, useEffect, useMemo } from 'react'
import styles from './index.less'
import { Switch, Input, Table, Form } from 'antd'
import { Switch, Input, Table, Form, Popconfirm, Popover } from 'antd'
import Drag from './../../../../components/Drag'
import DragTable from '../../../../components/DragTable'
import { CheckOutlined, DeleteOutlined, MenuOutlined } from '@ant-design/icons'
const colors = [
// '#ffccc7', '#ffe7ba', '#fffb8f', '#d9f7be', '#b5f5ec',
// '#bae7ff', '#d6e4ff', '#efdbff', '#ffd6e7', '#e8e8e8',
// '#ff4d4f', '#ffa940', '#fbce00', '#73d13d', '#36cfc9',
// '#40a9ff', '#597ef7', '#9254de', '#f759ab', '#8c8c8c',
'rgb(255, 77, 79)',
'rgb(255, 169, 64)',
'rgb(251, 206, 0)',
'rgba(115, 209, 61)',
'rgba(54, 207, 201)',
'rgba(64, 169, 255)',
'rgba(89, 126, 247)',
'rgba(146, 84, 222)',
'rgba(247, 89, 171)',
'rgba(140, 140, 140)',
// 'rgba(255, 204, 199)',
// 'rgba(255, 231, 186)',
// 'rgba(255, 251, 143)',
// 'rgba(217, 247, 190)',
// 'rgba(181, 245, 236)',
// 'rgba(186, 231, 255)',
// 'rgba(214, 228, 255)',
// 'rgba(239, 219, 255)',
// 'rgba(255, 214, 231)',
// 'rgba(232, 232, 232)',
]
const SimpleList = (props) => {
......@@ -10,15 +38,158 @@ const SimpleList = (props) => {
const { color } = addons.formData
const [visible, setVisible] = useState(false)
const [text, setText] = useState('')
const [loading, setLoading] = useState(true)
useEffect(() => {
setTimeout(() => {
setLoading(false)
}, 0)
}, [])
const onPressEnter = (i) => {
let length = [...value].length
let array = [...value]
array.splice(i + 1, 0, { key: `${length + 1}`, index: length + 1, color: colors[length % 10], value: '' })
onChange(array)
}
const inputChange = (item, i) => {
let array = []
value.forEach((v, index) => {
if (index === i) {
v.value = item
}
array.push({ ...v })
})
onChange(array)
}
const confirm = (index) => {
let array = []
value.forEach((v, i) => {
if (i !== index) {
array.push({ ...v })
}
})
onChange(array)
}
const colorClick = (item, i) => {
let array = []
value.forEach((v, index) => {
if (index === i) {
v.color = item
}
array.push({ ...v })
})
onChange(array)
}
const rest = (index) => {
let array = []
value.forEach((v, i) => {
if (index === i) {
v.color = colors[index % 10]
}
array.push({ ...v })
})
onChange(array)
}
const columns = useMemo(() => {
let columns = [
{
title: 'value',
dataIndex: 'value',
render: (r, _, i) => {
return (
<Input
onPressEnter={() => onPressEnter(i)}
onChange={(e) => inputChange(e.target.value, i)}
defaultValue={r}
/>
)
}
},
{
title: 'color',
dataIndex: 'color',
width: 30,
render: (r, _, index) => {
const content = (
<div>
<div className={styles.colorTop}>
<div className={styles.topLeft}>请选择颜色</div>
<div className={styles.topRight} onClick={() => rest(index)}>重置</div>
</div>
<div className={styles.colorBox}>
{
colors.map((v, i) => {
return (
<div className={styles.colors} style={{ background: v }} onClick={() => colorClick(v, index)}>
<CheckOutlined style={{ fontSize: '11px', marginLeft: '5px', display: r === v ? 'inline-block' : 'none' }} />
</div>
)
})
}
</div>
</div>
)
return (
<Popover
content={content}
trigger='click'
>
<div className={styles.colors} style={{ background: r || '#f2f4f5' }}></div>
</Popover>
)
}
},
{
width: 30,
render: (r, _, i) => {
return (
<Popconfirm
title='确定删除?'
onConfirm={() => confirm(i)}
onCancel={() => { }}
>
<DeleteOutlined style={{ color: 'rgb(153, 153, 153)' }} />
</Popconfirm>
)
},
},
{
title: 'Sort',
dataIndex: 'sort',
width: 30,
className: 'drag-visible',
render: () => <MenuOutlined style={{ cursor: 'grab', color: '#999', }} />,
},
]
if (!color) {
return columns.filter(v => v.dataIndex !== 'color')
}
return columns
}, [value, color])
const switchChange = (checked) => {
addons.setValue('color', checked)
if (checked) {
if (Array.isArray(value)) {
let array = []
value.forEach((v, i) => {
array.push({ ...v, color: colors[i % 10] })
})
onChange(array)
}
}
}
const add = () => {
let length = [...value].length
let array = [...value]
array.push({ key: `${length + 1}`, index: length + 1, value: '' })
array.push({ key: `${length + 1}`, index: length + 1, color: colors[length % 10], value: '' })
onChange(array)
}
......@@ -28,11 +199,17 @@ const SimpleList = (props) => {
}
const onOk = () => {
let array = text.split('\n').map((v, i) => { return { key: `${i}`, index: i, value: v } })
let array = text.split('\n').map((v, i) => { return { key: `${i}`, index: i, value: v, color: colors[i % 10] } })
onChange(array)
setVisible(false)
}
const dragCallBack = (array) => {
if (array) {
onChange(array)
}
}
return (
<div className={styles.simpleList}>
<div className={styles.title}>
......@@ -43,11 +220,19 @@ const SimpleList = (props) => {
</div>
</div>
<div className={styles.box}>
<DragTable
dataSource={Array.isArray(value) ? value.map((v, i) => { return { key: `${i}`, index: i, ...v } }) : []}
setDataSource={onChange}
color={color}
/>
{
loading ? null :
<DragTable
dataSource={Array.isArray(value) ? value.map((v, i) => { return { key: `${i}`, index: i, ...v } }) : []}
showHeader={false}
rowKey='key'
ItemTypes='stadingOrder'
color={color}
columns={columns}
pagination={false}
dragCallBack={dragCallBack}
/>
}
</div>
<div className={styles.footer}>
<span onClick={add}>添加选项</span>
......
......@@ -25,4 +25,35 @@
}
}
}
}
.colorTop {
display: flex;
justify-content: space-between;
.topLeft {
font-size: 15px;
font-weight: 700;
color: #707070;
}
.topRight {
font-size: 12px;
color: #41b3ec;
&:hover {
cursor: pointer;
}
}
}
.colorBox {
width: 130px;
display: flex;
flex-wrap: wrap;
}
.colors {
width: 20px;
height: 20px;
border-radius: 50%;
margin-top: 6px;
margin-left: 6px;
&:hover {
cursor: pointer;
}
}
\ No newline at end of file
......@@ -127,13 +127,13 @@ export const debounce = (fn) => {
}
//生成随机ID
export function getNanoid(len = 6) {
export function getNanoid(len = 6, left = '分组名称_') {
var orgStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let returnStr = "";
for (var i = 0; i < len; i++) {
returnStr += orgStr.charAt(Math.floor((Math.random() * orgStr.length)));
}
return `分组名称_${returnStr}`
return `${left}${returnStr}`
}
//手动校验配置信息
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment