642 lines
19 KiB
JavaScript
642 lines
19 KiB
JavaScript
import React,{useEffect,useState,useMemo,useRef} from 'react';
|
||
import { Form, Button, Input, Row,Upload, Col, Table, DatePicker, InputNumber,message,Image,Modal,Typography ,Popconfirm } from 'antd';
|
||
import { DeleteOutlined,FileWordOutlined,FilePdfOutlined,FileZipOutlined,FileExcelOutlined } from '@ant-design/icons';
|
||
import { formItemLayout, btnItemLayout } from '../../../../components/crud/FormLayoutProps';
|
||
import { getDictService } from '../../../../service/SelectValue'
|
||
import { validlgtd , validlttd } from '../../../../utils/validators';
|
||
import apiurl from '../../../../service/apiurl';
|
||
import {mobile} from '../../../../utils/validators'
|
||
import AdcdTreeSelect from '../../../../components/Form/AdcdTreeSelect'
|
||
import NormalSelect from '../../../../components/Form/NormalSelect';
|
||
import { config } from '../../../../config';
|
||
import "./index.less"
|
||
import moment from 'moment';
|
||
import { createCrudService } from '../../../../components/crud/_';
|
||
const { RangePicker } = DatePicker
|
||
const { Dragger } = Upload;
|
||
const url = "http://223.75.53.141:9100/gs-tsg"
|
||
const EditableCell = ({
|
||
editing,
|
||
dataIndex,
|
||
title,
|
||
inputType,
|
||
record,
|
||
index,
|
||
children,
|
||
...restProps
|
||
}) => {
|
||
const inputNode = inputType === 'number' ?
|
||
<InputNumber style={{ textAlign: "center", flex: 1 }} /> :
|
||
inputType === 'select' ? <NormalSelect style={{ textAlign: "center", flex: 1 }} options={[{label:"男",value:"男"},{label:"女",value:"女"}]} />:
|
||
<Input style={{ textAlign: "center" }} />;
|
||
return (
|
||
<td {...restProps}>
|
||
{editing ? (
|
||
<Form.Item
|
||
name={dataIndex}
|
||
wrapperCol={[24]}
|
||
style={{
|
||
margin: 0,
|
||
}}
|
||
// rules={[
|
||
// {
|
||
// required: true,
|
||
// message: `Please Input ${title}!`,
|
||
// },
|
||
// ]}
|
||
>
|
||
{inputNode}
|
||
</Form.Item>
|
||
) : (
|
||
children
|
||
)}
|
||
</td>
|
||
);
|
||
};
|
||
|
||
const ModalForm = ({ mode, record, onEdit, onSave, onSimilarSave }) => {
|
||
const [editingKey, setEditingKey] = useState('');
|
||
const [disabled, setDisabled] = useState(false)
|
||
const [details, setDetails] = useState([])
|
||
const detailsRef = useRef(null)
|
||
detailsRef.current = details
|
||
const isEditing = (record) => {
|
||
return record.key === editingKey;
|
||
}
|
||
|
||
const columns = [
|
||
{
|
||
title: "序号",
|
||
dataIndex: "index",
|
||
width: 60,
|
||
render: (text, record, index) => <span>{ index + 1}</span>,
|
||
align: "center"
|
||
},
|
||
{
|
||
title: '姓名',
|
||
key: 'name',
|
||
dataIndex: 'name',
|
||
width: 150
|
||
, align: "center",
|
||
editable: true,
|
||
},
|
||
{
|
||
title: '性别',
|
||
key: 'sex',
|
||
dataIndex: 'sex',
|
||
width: 100,
|
||
align: "center",
|
||
render: (rec, record) => <span>{rec == "F" ? "女" : rec == "M" ? "男" : ''}</span>,
|
||
editable: true,
|
||
},
|
||
{
|
||
title: '年龄',
|
||
key: 'age',
|
||
dataIndex: 'age',
|
||
width: 100,
|
||
align: "center",
|
||
editable: true,
|
||
},
|
||
{
|
||
title: '工作单位',
|
||
key: 'workUnit',
|
||
dataIndex: 'workUnit',
|
||
width: 150,
|
||
align: "center",
|
||
editable: true,
|
||
},
|
||
{
|
||
title: '职务',
|
||
key: 'duty',
|
||
dataIndex: 'duty',
|
||
width: 150,
|
||
align: "center",
|
||
editable: true,
|
||
},
|
||
{
|
||
title: '联系方式',
|
||
key: 'phone',
|
||
dataIndex: 'phone',
|
||
width: 150,
|
||
align: "center",
|
||
editable: true,
|
||
},
|
||
{
|
||
title: '操作', key: 'operation', width: 240, fixed: 'right',align: 'center',
|
||
render: (_, record) => {
|
||
const editable = isEditing(record);
|
||
return editable ? (
|
||
<span>
|
||
<Typography.Link
|
||
onClick={() => save(record.key)}
|
||
style={{
|
||
marginRight: 8,
|
||
}}
|
||
>
|
||
完成
|
||
</Typography.Link>
|
||
|
||
</span>
|
||
) : (
|
||
<div style={{display:"flex",justifyContent:"center",columnGap:10}}>
|
||
<Typography.Link disabled={editingKey !== ''} onClick={() => edit1(record)}>
|
||
编辑
|
||
</Typography.Link>
|
||
<Popconfirm title="确定要删除?" onConfirm={()=>handleDelete(record.key)}>
|
||
<a>删除</a>
|
||
</Popconfirm>
|
||
</div>
|
||
|
||
|
||
);
|
||
},
|
||
},
|
||
]
|
||
|
||
|
||
|
||
const newColumns = useMemo(() => {
|
||
let data = columns;
|
||
if (mode == "view") {
|
||
data.pop();
|
||
return data
|
||
} else {
|
||
return data;
|
||
}
|
||
}, [mode,editingKey])
|
||
const [form1] = Form.useForm()
|
||
|
||
const edit1 = (record) => {
|
||
setDisabled(true)
|
||
form1.setFieldsValue({
|
||
name: '',
|
||
sex:"",
|
||
age: '',
|
||
workUnit:'',
|
||
duty: '',
|
||
phone:'',
|
||
...record,
|
||
sex:record.sex == "F" ? "女" : record.sex == "M" ? "男" : ''
|
||
});
|
||
setEditingKey(record.key);
|
||
};
|
||
|
||
const save = async (key) => {
|
||
setDisabled(false)
|
||
try {
|
||
const row = await form1.validateFields();
|
||
if (row.sex) {
|
||
row.sex = row.sex == "男" ? "M" : row.sex == "女" ? "F" :''
|
||
}
|
||
const newData = [...details];
|
||
const index = newData.findIndex((item) => key === item.key);
|
||
if (index > -1) {
|
||
const item = newData[index];
|
||
newData.splice(index, 1, {
|
||
...item,
|
||
...row,
|
||
});
|
||
setDetails(newData);
|
||
setEditingKey('');
|
||
} else {
|
||
newData.push(row);
|
||
setDetails(newData);
|
||
setEditingKey('');
|
||
}
|
||
} catch (errInfo) {
|
||
console.log('Validate Failed:', errInfo);
|
||
}
|
||
};
|
||
const mergedColumns = newColumns.map((col) => {
|
||
if (!col.editable) {
|
||
return col;
|
||
}
|
||
return {
|
||
...col,
|
||
onCell: (record) => ({
|
||
record,
|
||
inputType: col.dataIndex === 'age' ? 'number' :
|
||
col.dataIndex === 'sex' ? 'select' : "text",
|
||
dataIndex: col.dataIndex,
|
||
title: col.title,
|
||
editing: isEditing(record),
|
||
}),
|
||
};
|
||
});
|
||
|
||
const handleAddRow = () => {
|
||
setDisabled(true)
|
||
const newData = {
|
||
key: (details.length + 1).toString(),
|
||
name: '',
|
||
sex: '',
|
||
age: '',
|
||
workUnit: '',
|
||
duty: '',
|
||
phone:""
|
||
};
|
||
form1.setFieldsValue(newData)
|
||
setDetails([...details, newData]);
|
||
setEditingKey(newData.key);
|
||
};
|
||
const [form] = Form.useForm();
|
||
const [fileList, setFileList] = useState([]) //上传文件列表
|
||
const [fileIds, setFileIds] = useState([])
|
||
const [iframeSrc, setIframeSrc] = useState('')
|
||
const [pdfViewOPen, setPdfViewOPen] = useState(false)
|
||
|
||
const [loading, setLoading] = useState(false)
|
||
|
||
const width = useMemo(() => columns.reduce((total, cur) => total + (cur.width), 0), [columns]);
|
||
/**
|
||
* @description 获取查看时文件
|
||
* @param {*} type
|
||
* @returns
|
||
*/
|
||
const getFileInfo = (params) => {
|
||
createCrudService(apiurl.fxzb.qsdw.zq.getFile).delGet({ teamId: params.teamId }).then(res => {
|
||
if (res.code === 200) {
|
||
let fileArr = res.data?.files.map(item => {
|
||
return {
|
||
name: item.fileName,
|
||
response: {
|
||
data: {
|
||
filePath: item.filePath,
|
||
fileId:item.fileId
|
||
}
|
||
},
|
||
}
|
||
})
|
||
setFileList(fileArr)
|
||
const result = res.data?.details.map(item => ({ ...item, key: item.detailId }))
|
||
console.log("resss",result);
|
||
|
||
setDetails(result)
|
||
}
|
||
})
|
||
}
|
||
/**
|
||
* @description 文件下载
|
||
* @param {String} params 文件fileId
|
||
*/
|
||
const download = (params) => {
|
||
let downloadLink = document.createElement("a");
|
||
downloadLink.href = `${process.env.REACT_APP_API_URL}/gunshiApp/tsg/rescue/team/file/download/${params}`;
|
||
downloadLink.download = `${params.fileName}`;
|
||
downloadLink.style.display = "none";
|
||
// 将链接添加到页面中
|
||
document.body.appendChild(downloadLink);
|
||
|
||
// 模拟点击事件,开始下载
|
||
downloadLink.click();
|
||
}
|
||
/**
|
||
* @description 上传图片
|
||
* @param {string} file 上传的文件
|
||
*/
|
||
const fileChange = (info) => {
|
||
if (info.file.status === "done") {
|
||
setLoading(false);
|
||
}
|
||
if (info.file.status === "uploading") {
|
||
setLoading(true);
|
||
}
|
||
if (info.file.status === "error") {
|
||
message.error("文件上传失败")
|
||
setLoading(false);
|
||
}
|
||
let fileIds = info.fileList.map(file => {
|
||
return file.response?.data?.fileId
|
||
})
|
||
setFileIds(fileIds)
|
||
setFileList(info.fileList)
|
||
}
|
||
/**
|
||
* @description pdf文件预览
|
||
* @param {String} params 文件预览url
|
||
*/
|
||
const viewPdf = (params) => {
|
||
setIframeSrc(params)
|
||
setPdfViewOPen(true)
|
||
}
|
||
|
||
|
||
const handleDelete = (key) => {
|
||
const newData = detailsRef.current.filter((item) => item.key !== key);
|
||
setDetails(newData);
|
||
};
|
||
|
||
|
||
const onfinish = () => {
|
||
let values = form.getFieldsValue();
|
||
values.details = details;
|
||
values.validStartDate = values.dateRangeSo&&moment(values.dateRangeSo[0]).format("YYYY-MM-DD")
|
||
values.validEndDate = values.dateRangeSo&&moment(values.dateRangeSo[1]).format("YYYY-MM-DD")
|
||
if (mode === 'edit') {
|
||
let oldFiles = fileList.map(item => item.response?.data?.fileId )
|
||
values.fileIds = oldFiles;
|
||
values.teamId = record.teamId;
|
||
onEdit(apiurl.fxzb.qsdw.zq.edit,values)
|
||
}
|
||
if (mode === 'save') {
|
||
values.fileIds = fileIds
|
||
onSave(apiurl.fxzb.qsdw.zq.save,values)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description 删除上传的图片
|
||
* @param {string} id 删除的id
|
||
*/
|
||
const deleteFile = (fileId) => {
|
||
console.log(fileId);
|
||
let filterFile = fileList.filter(item => item.response?.data?.fileId !== fileId);
|
||
setFileList(filterFile)
|
||
}
|
||
useEffect(()=>{
|
||
if (record.teamId ) {
|
||
getFileInfo(record)
|
||
}
|
||
}, [record])
|
||
|
||
useEffect(() => {
|
||
if (mode !== "save") {
|
||
let dateSo = [
|
||
record.validStartDate? moment(record.validStartDate):'',
|
||
record.validEndDate? moment(record.validEndDate): ''
|
||
]
|
||
|
||
form.setFieldsValue({...record,dateRangeSo:dateSo})
|
||
|
||
}
|
||
|
||
}, [record,mode])
|
||
|
||
return (
|
||
<>
|
||
<div className='basic-info'>基本信息</div>
|
||
{/* <Divider /> */}
|
||
<Form
|
||
form={form}
|
||
{...formItemLayout}
|
||
// initialValues={record}
|
||
>
|
||
<Row>
|
||
<Col span={12}>
|
||
<Form.Item
|
||
label="队伍名称"
|
||
name="teamName"
|
||
rules={[{ required: true }]}
|
||
>
|
||
<Input disabled={mode==='view'} style={{width:'100%'}} allowClear />
|
||
</Form.Item>
|
||
</Col>
|
||
<Col span={12}>
|
||
<Form.Item
|
||
label="登记日期"
|
||
name="registerDate"
|
||
getValueFromEvent={(e,dateString) => dateString}
|
||
getValueProps={(value) => ({ value: value ? moment(value) : undefined })}
|
||
rules={[
|
||
{
|
||
required: true,
|
||
message: `登记日期不能为空`,
|
||
},
|
||
]}
|
||
>
|
||
<DatePicker disabled={mode==='view'} format={'YYYY-MM-DD'} style={{width:'100%'}} allowClear />
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
|
||
<Row>
|
||
<Col span={12}>
|
||
<Form.Item
|
||
label="有效期限"
|
||
name="dateRangeSo"
|
||
rules={[
|
||
{
|
||
required: true,
|
||
message: `有效期限不能为空`,
|
||
},
|
||
]}
|
||
getValueFromEvent={(e,dateString) => dateString}
|
||
getValueProps={(value) => {
|
||
return {
|
||
value: value ? [value[0]&&moment(value[0]),value[1]&&moment(value[1])] : undefined
|
||
};
|
||
}}
|
||
>
|
||
<RangePicker
|
||
allowClear
|
||
showTime
|
||
disabled={mode==='view'}
|
||
// style={{ width: "300px" }}
|
||
format="YYYY-MM-DD"
|
||
/>
|
||
</Form.Item>
|
||
</Col>
|
||
<Col span={12}>
|
||
<Form.Item
|
||
label="管理单位"
|
||
name="managementUnit"
|
||
>
|
||
<Input disabled={mode==='view'} style={{width:'100%'}} allowClear />
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
|
||
<Row>
|
||
<Col span={12}>
|
||
<Form.Item
|
||
label="地址"
|
||
name="address"
|
||
rules={[{ required: true }]}
|
||
>
|
||
<Input type='text' disabled={mode==='view'} style={{width:'100%'}} allowClear />
|
||
</Form.Item>
|
||
</Col>
|
||
<Col span={6}>
|
||
<Form.Item
|
||
label="经度"
|
||
name="lgtd"
|
||
labelCol={{ span: 12 }}
|
||
wrapperCol={{ span: 10 }}
|
||
>
|
||
<Input type='text' disabled={mode==='view'} style={{width:'100%'}} allowClear />
|
||
</Form.Item>
|
||
</Col>
|
||
<Col span={6}>
|
||
<Form.Item
|
||
label="纬度"
|
||
name="lttd"
|
||
labelCol={{ span: 6 }}
|
||
wrapperCol={{ span: 10 }}
|
||
>
|
||
<Input type='text' disabled={mode==='view'} style={{width:'100%'}} allowClear />
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
|
||
<Row>
|
||
<Col span={12}>
|
||
<Form.Item
|
||
label="队伍负责人"
|
||
name="teamLeader"
|
||
>
|
||
<Input type='num' disabled={mode==='view'} style={{width:'100%'}} allowClear />
|
||
</Form.Item>
|
||
</Col>
|
||
<Col span={12}>
|
||
<Form.Item
|
||
label="联系电话"
|
||
name="phone"
|
||
>
|
||
<Input type='num' disabled={mode==='view'} style={{width:'100%'}} allowClear />
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
<Row>
|
||
<Col span={24}>
|
||
<Form.Item
|
||
label="附件"
|
||
name="fieldId"
|
||
labelCol={{ span: 3 }}
|
||
wrapperCol={{ span: 19 }}
|
||
>
|
||
{mode !== "view" &&
|
||
<Dragger
|
||
name='file'
|
||
// multiple
|
||
action="/gunshiApp/tsg/rescue/team/file/upload/singleSimple"
|
||
onChange={fileChange}
|
||
onDrop={(info) => { console.log(info.dataTransfer.files); }}
|
||
fileList={fileList}
|
||
disabled={loading}
|
||
// onSuccess={handleSuccess}
|
||
>
|
||
<p className="ant-upload-text">点击或拖拽文件到此区域上传</p>
|
||
<p className="ant-upload-hint">
|
||
支持扩展名:.rar .zip .doc .docx .pdf .jpg .png .ppt
|
||
</p>
|
||
</Dragger>
|
||
}
|
||
<Row gutter={[16]}>
|
||
{
|
||
fileList.length > 0 && fileList.map(file => {
|
||
return (
|
||
<Col span={12}>
|
||
<div className="file-item" style={{width:"75%"}}>
|
||
<div className='file-description'>
|
||
{file.name.indexOf('.docx') > -1 ?
|
||
<div
|
||
onClick={() => { download(file.response?.data?.fileId) }}
|
||
style={{ cursor: 'pointer' }}
|
||
>
|
||
<FileWordOutlined
|
||
style={{ fontSize: 40 }}
|
||
/>
|
||
</div>
|
||
:
|
||
file.name.indexOf('.pdf') > -1 ?
|
||
<div
|
||
onClick={() => { viewPdf(file.response?.data?.fileId) }}
|
||
style={{ cursor: 'pointer' }}
|
||
>
|
||
<FilePdfOutlined style={{ fontSize: 40 }} />
|
||
</div>
|
||
:
|
||
file.name.indexOf('.zip') > -1 ?
|
||
<div
|
||
onClick={() => { download(file.response?.data?.fileId) }}
|
||
style={{ cursor: 'pointer' }}
|
||
>
|
||
<FileZipOutlined style={{ fontSize: 40 }} />
|
||
</div>
|
||
:
|
||
file.name.indexOf('.xlsx') > -1 ?
|
||
<div
|
||
onClick={() => { download(file.response?.data?.fileId) }}
|
||
style={{ cursor: 'pointer' }}
|
||
>
|
||
<FileExcelOutlined style={{ fontSize: 40 }} />
|
||
</div>
|
||
:
|
||
<Image width={60} src={url +file.response?.data?.filePath} alt='' />
|
||
}
|
||
<span>{file.name}</span>
|
||
</div>
|
||
<div className={mode == "view" ? 'delete-icon disable-icon' : 'delete-icon'} onClick={() => deleteFile(file.response?.data?.fileId)}>
|
||
<DeleteOutlined />
|
||
</div>
|
||
</div>
|
||
</Col>
|
||
)
|
||
})
|
||
}
|
||
</Row>
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
</Form>
|
||
<div className='basic-info' style={{display:"flex",justifyContent:"space-between"}}>
|
||
<span>队伍明细:(共计{details?.length}人)</span>
|
||
{mode != "view" ?<div style={{display:"flex",columnGap:10,marginBottom:10}}>
|
||
<Button onClick={handleAddRow} type='primary' disabled={disabled}>添加</Button>
|
||
{/* <Button onClick={() => {}} >导入</Button> */}
|
||
</div>:null}
|
||
</div>
|
||
<Form form={form1} component={false}>
|
||
<Table
|
||
rowKey="index"
|
||
components={{
|
||
body: {
|
||
// row: EditableRow,
|
||
cell: EditableCell,
|
||
},
|
||
}}
|
||
columns={mergedColumns}
|
||
dataSource={details}
|
||
scroll={{ x: width}}
|
||
pagination={false}
|
||
/>
|
||
|
||
{
|
||
mode==='view'?null:(
|
||
<div style={{marginTop:20}}>
|
||
<Form.Item wrapperCol={{span:2,offset:22}}>
|
||
<Button type="primary" onClick={onfinish} disabled={disabled}>
|
||
{mode === 'save' ? '保存' :
|
||
'修改'}
|
||
</Button>
|
||
</Form.Item>
|
||
</div>
|
||
)
|
||
}
|
||
</Form>
|
||
<Modal
|
||
open={pdfViewOPen}
|
||
width={1000}
|
||
title=""
|
||
footer={null}
|
||
style={{marginTop:"-5%"}}
|
||
onCancel={() => {
|
||
setPdfViewOPen(false)
|
||
}}
|
||
>
|
||
<iframe
|
||
style={{
|
||
height: '80vh',
|
||
width: '100%',
|
||
border: 0,
|
||
marginTop: 20,
|
||
}}
|
||
src={`${process.env.PUBLIC_URL}/static/pdf/web/viewer.html?file=${encodeURIComponent(`/gunshiApp/tsg/rescue/goods/file/download/${iframeSrc}`)}`}
|
||
/>
|
||
</Modal>
|
||
</>
|
||
);
|
||
}
|
||
|
||
export default ModalForm;
|