import React
, { useState
, useRef
} from "react";
import { Button
, Transfer
, Row
, Col
, Label
, Radio
, Select
, Checkbox
} from "tinper-bee";
import PopDialog
from "components/Pop";
import FormItemPro
from 'components/FormItemPro';
import { Info
} from "utils";
import moment
from "moment";
const Option
= Select
.Option
;
import "./index.less";
const FileExport
= ({
grid
,
onBeforeExportFile
,
fileName
= `fileName(${moment().format("YYYY-MM-DD HH:mm:ss")}).xlsx`
}) => {
const [isShowDialog
, setIsShowDialog
] = useState(false);
const [transferData
, setTransferData
] = useState([]);
const [selectedKeys
, setSelectedKeys
] = useState([]);
const [targetKeys
, setTargetKeys
] = useState([]);
const handleChange = (nextTargetKeys
, direction
, moveKeys
) => {
setTargetKeys(nextTargetKeys
);
};
const handleSelectedKeyChange = (sourceSelectedKeys
, targetSelectedKeys
) => {
setSelectedKeys([...sourceSelectedKeys
, ...targetSelectedKeys
]);
};
const handleScroll = (direction
, e
) => {
console
.log("direction:", direction
);
console
.log("target:", e
.target
);
};
const handleReadyExportFile = () => {
if (!grid
|| !(grid
instanceof React.Component || grid
.current
instanceof React.Component)) {
Info("未检测到传入Grid组件实例,请检查!");
return;
}
const { columns
, data
} = grid
.props
|| grid
.current
.props
;
if (!columns
|| !(columns
instanceof Array) || !columns
.filter(item
=>
Boolean(item
.title
) && (Boolean(item
.key
) || item
.children
.length
)).length
) {
Info("未检测到 [列] 相关数据,请检查!");
return;
}
if (!data
|| !Array
.isArray(data
) || !data
.length
) {
Info("未检测到 [表体] 相关数据,请检查!");
return;
}
onBeforeExportFile
&& onBeforeExportFile();
const [operationCol
] = columns
.filter(item
=> item
.title
=== "操作");
operationCol
&& Object
.assign(operationCol
, { disabled
: true });
const level
= +function func(data
) {
let level
= 0;
data
.forEach(item
=> {
if (item
.children
) {
level
++;
func(item
.children
)
}
})
return level
;
}(columns
)
if (level
> 2) {
Info('暂不支持3级及以上表头的自定义列导出!');
return;
}
const arrTransfer
= [];
+function func(data
) {
data
.forEach(item
=> {
if (item
.children
&& item
.children
.length
) {
arrTransfer
.push(...item
.children
);
} else {
arrTransfer
.push(item
);
}
})
}(columns
);
if (arrTransfer
.length
) {
setTransferData(arrTransfer
);
setIsShowDialog(true);
}
};
const handleExportFIle = () => {
if (!targetKeys
.length
) {
Info("请选择至少导出1列数据!");
return;
}
const arrTable
= [];
const { data
, columns
} = grid
.props
|| grid
.current
.props
;
const arrHeaderOne
= [];
columns
.forEach(item
=> {
if (!item
.children
) {
targetKeys
.includes(item
.key
) && arrHeaderOne
.push(item
.title
);
} else {
item
.children
.forEach(el
=> {
targetKeys
.includes(el
.key
) && arrHeaderOne
.push(item
.title
);
})
}
})
arrTable
.push(arrHeaderOne
);
let keyMapTitle
= transferData
.map(item
=> ({ [item
.key
]: item
.title
}));
keyMapTitle
= Object
.assign({}, ...keyMapTitle
);
data
.forEach(item
=> {
const arr
= [];
targetKeys
.forEach(key
=> {
const [column
] = transferData
.filter(item
=> item
.key
=== key
);
const { exportKey
} = column
;
if (exportKey
) arr
.push(item
[exportKey
]);
else arr
.push(item
[key
]);
});
arr
.filter(item
=> Boolean(item
)).length
&& arrTable
.push(arr
);
});
const ws
= XLSX.utils
.aoa_to_sheet(arrTable
);
if (!ws
["!cols"]) ws
["!cols"] = [];
targetKeys
.forEach(key
=> {
const [column
] = transferData
.filter(item
=> item
.key
=== key
);
if (column
) {
ws
["!cols"].push({
wpx
: column
.width
|| 50
});
}
});
if (!ws
["!merges"]) ws
["!merges"] = [];
transferData
.filter(item
=> Boolean(item
.render
))
.filter(item
=> item
.render
.toString().includes("rowSpan"))
.forEach(item
=> {
const sc
= targetKeys
.findIndex(el
=> el
=== item
.key
);
data
.forEach((record
, index
) => {
let sr
= 2;
let er
= sr
;
if (!!item
.render(record
[item
.key
], record
)) {
if (item
.render(record
[item
.key
], record
).props
.rowSpan
> 0) {
sr
+= index
;
er
= item
.render(record
[item
.key
], record
).props
.rowSpan
- 1;
var merge
= {
s
: {
r
: sr
,
c
: sc
},
e
: {
r
: er
+ sr
,
c
: sc
}
};
ws
["!merges"].push(merge
);
}
}
});
});
columns
.forEach(item
=> {
if (item
.children
&& item
.children
.length
) {
const arrSame
= [];
item
.children
.forEach(el
=> {
targetKeys
.includes(el
.key
) && arrSame
.push(el
.key
);
})
const [key
] = arrSame
;
const sc
= targetKeys
.findIndex(item
=> item
=== key
);
const ec
= sc
+ arrSame
.length
- 1;
var merge
= {
s
: {
r
: 0,
c
: sc
},
e
: {
r
: 0,
c
: ec
}
};
ws
["!merges"].push(merge
);
}
})
transferData
.filter(item
=> Boolean(item
.render
))
.filter(item
=> item
.render
.toString().includes("colSpan"))
.forEach(item
=> {
const sc
= targetKeys
.findIndex(el
=> el
=== item
.key
);
data
.forEach((record
, index
) => {
let sr
= 2;
let er
= 0;
if (!!item
.render(record
[item
.key
], record
)) {
if (item
.render(record
[item
.key
], record
).props
.colSpan
> 0) {
sr
+= index
;
er
= item
.render(record
[item
.key
], record
).props
.colSpan
- 1;
var merge
= {
s
: {
r
: sr
,
c
: sc
},
e
: {
r
: sr
,
c
: er
+ sc
}
};
ws
["!merges"].push(merge
);
}
}
});
});
const wb
= XLSX.utils
.book_new();
XLSX.utils
.book_append_sheet(wb
, ws
, "SheetJS");
XLSX.writeFile(wb
, fileName
);
setIsShowDialog(false);
};
return (
<span classNames
="file-export">
<Button colors
="primary" onClick
={handleReadyExportFile
}>
导出
</Button
>
{isShowDialog
&& (
<PopDialog
show
={true}
title
="列导出配置"
width
="500"
className
="export-file-dialog"
autoFocus
={false}
enforceFocus
={false}
close
={() => setIsShowDialog(false)}
btns
={[
{
label
: "导出",
fun
: handleExportFIle
,
icon
: "uf-correct"
},
{
label
: "取消",
fun
: () => setIsShowDialog(false),
icon
: "uf-back"
}
]}
>
<Transfer
dataSource
={transferData
}
titles
={["待配置列", "已配置列"]}
targetKeys
={targetKeys
}
selectedKeys
={selectedKeys
}
onChange
={handleChange
}
onSelectChange
={handleSelectedKeyChange
}
onScroll
={handleScroll
}
render
={item
=> item
.title
}
lazy
={{
container
: "modal"
}}
/>
</PopDialog
>
)}
</span
>
);
};
const FileImport = ({ grid
, onAfterImportFile
}) => {
const inputRef
= useRef(null);
const [isShowDialog
, setIsShowDialog
] = useState(false);
const [importMode
, setImportMode
] = useState('edit');
const [arrKeyMapTitle
, setArrKeyMapTitle
] = useState([{ key
: 'rowNo', title
: '序号', isPrimaryKey
: true, isSelected
: false }])
const handleFileChange = e
=> {
e
.persist()
const { files
} = e
.target
;
const fileReader
= new FileReader();
const rABS
= !!fileReader
.readAsBinaryString
;
fileReader
.onload = event
=> {
const { result
} = event
.target
;
const workbook
= XLSX.read(result
, { type
: rABS
? 'binary' : 'array' });
let dataImport
= [];
for (const sheet
in workbook
.Sheets
) {
if (workbook
.Sheets
.hasOwnProperty(sheet
)) {
dataImport
= dataImport
.concat(XLSX.utils
.sheet_to_json(workbook
.Sheets
[sheet
]));
break;
}
}
inputRef
.current
.setAttribute('type', 'text');
inputRef
.current
.setAttribute('type', 'file');
const { columns
, data
} = grid
.props
|| grid
.current
.props
;
const arrFlatColumns
= [];
+function func(data
, level
) {
data
.forEach(item
=> {
item
.level
= level
;
arrFlatColumns
.push(item
)
if (item
.children
) {
func(item
.children
, level
+ 1)
}
})
}(columns
, 0)
const titleMapKey
= {};
const keyMapTitle
= {};
const arrKeyMapTitle
= [];
+function func(data
) {
data
.forEach(item
=> {
if (item
.children
&& item
.children
.length
) {
func(item
.children
)
} else {
arrKeyMapTitle
.push({ key
: item
.key
, title
: item
.title
})
titleMapKey
[item
.title
] = item
.key
;
keyMapTitle
[item
.key
] = item
.title
;
}
})
}(columns
)
const [row
] = arrKeyMapTitle
.filter(item
=> item
.key
=== 'rowNo');
if( row
) Object
.assign(row
, { isPrimaryKey
: true });
else
Object
.assign(arrKeyMapTitle
[0], { isPrimaryKey
: true });
}
setArrKeyMapTitle(arrKeyMapTitle
)
const dataFromExcel
= [];
if (dataImport
.length
- 2 > data
.length
) {
setImportMode('add')
} else setImportMode('edit');
if (Math
.max(...arrFlatColumns
.map(item
=> item
.level
)) > 1) {
Info('暂不支持3层及以上表头的导入');
return;
}
if (Math
.max(...arrFlatColumns
.map(item
=> item
.level
)) === 0) {
dataImport
.forEach(item
=> dataFromExcel
.push(item
))
}
if (Math
.max(...arrFlatColumns
.map(item
=> item
.level
)) === 1) {
const [objHeaderOne
] = dataImport
.slice(0, 1);
dataImport
.slice(1).forEach(item
=> {
const obj
= {};
Object
.entries(item
).forEach(el
=> {
const [key
, value
] = el
;
obj
[objHeaderOne
[key
]] = value
;
})
dataFromExcel
.push(obj
);
})
}
dataFromExcel
.forEach(item
=> Object
.entries(item
).forEach(el
=> {
const [key
, value
] = el
;
Object
.assign(item
, { [titleMapKey
[key
]]: value
})
delete item
[key
];
}))
FileExport
.dataFromExcel
= dataFromExcel
;
setIsShowDialog(true)
};
if (rABS
) fileReader
.readAsBinaryString(files
[0]); else fileReader
.readAsArrayBuffer(files
[0]);
}
const handleFileImport = () => {
const { data
} = grid
.props
|| grid
.current
.props
;
switch (importMode
) {
case 'add':
data
.length
= 0;
FileExport
.dataFromExcel
.forEach(item
=>data
.push(item
))
break;
case 'edit':
const primaryKey
= arrKeyMapTitle
.filter(item
=> item
.isPrimaryKey
=== true)?.[0]?.key
;
data
.length
&& data
.filter(item
=> !!item
[primaryKey
]).forEach(item
=>{
const { rowNo
} = item
;
const [ dataRow
] = FileExport
.dataFromExcel
.filter(i
=> i
.rowNo
=== rowNo
);
const arrEditableColumns
= arrKeyMapTitle
.filter(i
=> i
.isSelected
=== true);
arrEditableColumns
.length
&& arrEditableColumns
.forEach(i
=>{
const { key
} = i
;
Object
.assign(item
, { [key
] : dataRow
[key
] });
})
})
break;
default:
break;
}
onAfterImportFile
&& onAfterImportFile();
setIsShowDialog(false);
}
const handlePrimaryKeyChange = value
=> {
const newArrKeyMapTitle
= JSON.parse(JSON.stringify(arrKeyMapTitle
))
const [row
] = newArrKeyMapTitle
.filter(item
=> item
.isPrimaryKey
=== true);
Object
.assign(row
, { isPrimaryKey
: false });
const [newRow
] = newArrKeyMapTitle
.filter(item
=> item
.key
=== value
);
Object
.assign(newRow
, { isPrimaryKey
: true, isSelected
: false });
setArrKeyMapTitle(newArrKeyMapTitle
)
}
const handleEditableColumnsChange = (key
, checked
) => {
const newArrKeyMapTitle
= JSON.parse(JSON.stringify(arrKeyMapTitle
))
const [row
] = newArrKeyMapTitle
.filter(item
=> item
.key
=== key
);
Object
.assign(row
, { isSelected
: checked
});
setArrKeyMapTitle(newArrKeyMapTitle
)
}
return (
<span
class="file-import">
<label
class='file-import-btn'><input ref
={inputRef
} type
='file' accept
='.xlsx, .xls'
onChange
={handleFileChange
} style
={{ display
: 'none' }} />导入
</label
>
{isShowDialog
&& (
<PopDialog
show
={true}
title
="导入配置"
width
='500'
className
="file-import-dialog"
autoFocus
={false}
enforceFocus
={false}
close
={() => setIsShowDialog(false)}
btns
={[
{
label
: "导入",
fun
: handleFileImport
,
icon
: "uf-correct"
},
{
label
: "取消",
fun
: () => setIsShowDialog(false),
icon
: "uf-back"
}
]}
>
<Row className
="form-panel">
<Col lg
={12} md
={12} xs
={12} sm
={12}>
<FormItemPro
>
<Label
>导入模式
</Label
>
<Radio
.RadioGroup
name
="import-mode"
selectedValue
={importMode
}
onChange
={value
=> setImportMode(value
)}
>
<Radio colors
="primary" value
="add" >新增
</Radio
>
<Radio colors
="success" value
="edit" >编辑
</Radio
>
</Radio
.RadioGroup
>
</FormItemPro
>
</Col
>
{importMode
=== 'edit' && <>
<Col lg
={12} md
={12} xs
={12} sm
={12}>
<FormItemPro
>
<Label
>主键列
</Label
>
<Select
placeholder
='请选择主键列'
onChange
={value
=> handlePrimaryKeyChange(value
)}
optionFilterProp
="children"
value
={arrKeyMapTitle
.filter(item
=> item
.isPrimaryKey
=== true)[0] ? arrKeyMapTitle
.filter(item
=> item
.isPrimaryKey
=== true)[0].title
: '序号'}
>
{!!arrKeyMapTitle
.length
&&
arrKeyMapTitle
.map(item
=> {
const { key
, title
} = item
;
return <Option key
={key
} value
={key
} >
{title
}
</Option
>
})
}
</Select
>
</FormItemPro
>
</Col
>
<Col lg
={12} md
={12} xs
={12} sm
={12}>
<FormItemPro
>
<Label
>可编辑列
</Label
>
<div
class='editable-columns' >
{!!arrKeyMapTitle
.length
&& arrKeyMapTitle
.map(item
=> {
const { key
, title
, isPrimaryKey
, isSelected
} = item
;
return <Checkbox
key
={key
}
disabled
={isPrimaryKey
}
checked
={isSelected
}
onChange
={checked
=> handleEditableColumnsChange(key
, checked
)}>
{title
}
</Checkbox
>
})}
</div
>
</FormItemPro
>
</Col
>
</>
}
</Row
>
</PopDialog
>
)}
</span
>
);
}
export { FileExport
, FileImport
};
转载请注明原文地址: https://mac.8miu.com/read-504968.html