709 lines
23 KiB
JavaScript
709 lines
23 KiB
JavaScript
import React,{useState,useEffect,useRef,useContext,useMemo} from 'react'
|
||
import { Table, Radio,Switch,Button,Form,message, InputNumber,DatePicker,Upload,Row,Col,Image,Modal,Input} from "antd"
|
||
import { EditOutlined,DeleteOutlined,EyeOutlined } from '@ant-design/icons';
|
||
import { httpget2, httppost2 } from '../../../../utils/request'
|
||
import { handleData } from "../../../../utils/tools"
|
||
import apiurl from '../../../../service/apiurl'
|
||
import PfViewModal from "./pfViewModal"
|
||
import { formItemLayout, btnItemLayout } from '../../../../components/crud/FormLayoutProps';
|
||
import moment from 'moment'
|
||
const { Dragger } = Upload;
|
||
|
||
export default function PfDetail({ record, Item, refresh, onCancel,tabs }) {
|
||
const url = "http://223.75.53.141:9102/test.by-lyf.tmp"
|
||
const EditableContext = React.createContext(null);
|
||
const EditableRow = ({ index, ...props }) => {
|
||
const [form] = Form.useForm();
|
||
return (
|
||
<Form form={form} component={false}>
|
||
<EditableContext.Provider value={form}>
|
||
<tr {...props} />
|
||
</EditableContext.Provider>
|
||
</Form>
|
||
);
|
||
};
|
||
const EditableCell = ({
|
||
title,
|
||
editable,
|
||
children,
|
||
dataIndex,
|
||
record,
|
||
handleSave,
|
||
...restProps
|
||
}) => {
|
||
const [editing, setEditing] = useState(false);
|
||
const inputRef = useRef(null);
|
||
const form = useContext(EditableContext);
|
||
useEffect(() => {
|
||
if (editing) {
|
||
inputRef.current.focus();
|
||
}
|
||
}, [editing]);
|
||
const toggleEdit = () => {
|
||
if(Item.view) return
|
||
setEditing(!editing);
|
||
form.setFieldsValue({
|
||
[dataIndex]: record[dataIndex],
|
||
});
|
||
};
|
||
const save = async () => {
|
||
try {
|
||
const values = await form.validateFields();
|
||
toggleEdit();
|
||
handleSave({
|
||
...record,
|
||
...values,
|
||
});
|
||
} catch (errInfo) {
|
||
console.log('Save failed:', errInfo);
|
||
}
|
||
};
|
||
let childNode = children;
|
||
if (editable) {
|
||
childNode = editing ? (
|
||
<Form form={form}>
|
||
<Form.Item
|
||
style={{
|
||
margin: 0,
|
||
}}
|
||
name={dataIndex}
|
||
>
|
||
<InputNumber min={0} max={record?.standardScore} ref={inputRef} onPressEnter={save} onBlur={save} />
|
||
</Form.Item>
|
||
|
||
</Form>
|
||
) : (
|
||
<div
|
||
className="editable-cell-value-wrap"
|
||
style={{
|
||
paddingRight: 24,
|
||
}}
|
||
onClick={toggleEdit}
|
||
>
|
||
{children}
|
||
</div>
|
||
);
|
||
}
|
||
return <td {...restProps}>{childNode}</td>;
|
||
};
|
||
|
||
// 总分
|
||
const [tableData, setTableData] = useState([])
|
||
const score = useMemo(() => tableData?.reduce((total, cur) => total + (cur?.assessScore ?? 0), 0), [tableData]);
|
||
const columns = [
|
||
{
|
||
title: "考核类目",
|
||
dataIndex: "name",
|
||
key:"name",
|
||
width: 150,
|
||
align: "center",
|
||
onCell: (row) => ({ rowSpan: row.rowSpan || 0 })
|
||
},
|
||
{
|
||
title: '指标名称',
|
||
key: 'indicatorName',
|
||
dataIndex: 'indicatorName',
|
||
width: 200,
|
||
align: "center",
|
||
},
|
||
{
|
||
title: '标准分数',
|
||
key: 'standardScore',
|
||
dataIndex: 'standardScore',
|
||
width: 70,
|
||
align: "center",
|
||
},
|
||
{
|
||
title: `考核得分(${score ?? ''})`,
|
||
key: 'assessScore',
|
||
dataIndex: 'assessScore',
|
||
width: 80,
|
||
align: "center",
|
||
editable: true,
|
||
},
|
||
{
|
||
title: '是否需要整改',
|
||
key: 'isNeedRectify1',
|
||
dataIndex: 'isNeedRectify1',
|
||
width: 150,
|
||
align: "center",
|
||
render: (text, row) => {
|
||
const checked = compareScore(row)
|
||
return (
|
||
<>
|
||
<Switch
|
||
checkedChildren="是"
|
||
unCheckedChildren="否"
|
||
checked={checked}
|
||
/>
|
||
|
||
{(checked && !Item.view) ? <EditOutlined
|
||
title='编辑'
|
||
style={{ marginLeft: 10, cursor: 'pointer' }}
|
||
onClick={() => { zgCallback(row) }}
|
||
/> : (checked && Item.view) ?
|
||
<EyeOutlined
|
||
title='查看'
|
||
style={{ marginLeft: 10, cursor: 'pointer' }}
|
||
onClick={() => { zgView(row) }}
|
||
/> : null
|
||
}
|
||
|
||
</>
|
||
)
|
||
}
|
||
},
|
||
]
|
||
const components = {
|
||
body: {
|
||
row: EditableRow,
|
||
cell: EditableCell,
|
||
},
|
||
};
|
||
const newcolumns = columns.map((col) => {
|
||
if (!col.editable) {
|
||
return col;
|
||
}
|
||
return {
|
||
...col,
|
||
onCell: (record) => ({
|
||
record,
|
||
editable: col.editable,
|
||
dataIndex: col.dataIndex,
|
||
title: col.title,
|
||
handleSave,
|
||
}),
|
||
};
|
||
});
|
||
const handleSave = (row) => {
|
||
const newData = [...tableData];
|
||
const index = newData.findIndex((item) => row.id === item.id);
|
||
const item = newData[index];
|
||
newData.splice(index, 1, {
|
||
...item,
|
||
...row,
|
||
});
|
||
setTableData(newData);
|
||
tableDataRef.current = newData
|
||
};
|
||
|
||
|
||
const tableDataRef = useRef(null)
|
||
const getZbTableData = async (id, type) => {
|
||
const url = type == 1 ? apiurl.rcgl.jdkh.khmbgl.info :
|
||
apiurl.rcgl.jdkh.khrwgl.pfDetail
|
||
try {
|
||
const res = await httpget2(url + `/${id}`)
|
||
if (res.code == 200) {
|
||
res.data.forEach(item => {
|
||
if (item.rowSpan) delete item.rowSpan;
|
||
})
|
||
const result = handleData(res.data, "name")
|
||
setTableData(result)
|
||
tableDataRef.current = result;
|
||
}
|
||
} catch (error) {
|
||
console.log(error);
|
||
}
|
||
}
|
||
|
||
// 分数进行比较
|
||
const compareScore = (row) => {
|
||
let isBelowStandard = false;
|
||
if (Item.tabs != 2) {
|
||
isBelowStandard = row.standardScore > row.assessScore ? true : false;
|
||
return isBelowStandard;
|
||
} else {
|
||
for (let i = 0; row[`assessScore${i}`] !== undefined; i++) {
|
||
if (row[`assessScore${i}`] < row.standardScore) {
|
||
isBelowStandard = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return isBelowStandard
|
||
}
|
||
// 处理清单任务查看详情
|
||
const handleTableData = (obj) => {
|
||
let rrlts = {};
|
||
const arr = Object.values(obj).map(item => {
|
||
item.map((it, index) => {
|
||
it['teamUserName' + index] = it.teamUserName;
|
||
it['assessScore' + index] = it.assessScore;
|
||
it['problemDesc' + index] = it.problemDesc;
|
||
it['rectifyRequirement' + index] = it.rectifyRequirement;
|
||
it['rectifyLastDate' + index] = it.rectifyLastDate;
|
||
it['files' + index] = it.files;
|
||
it["count"] = index +1;
|
||
rrlts = { ...rrlts, ...it }
|
||
})
|
||
return rrlts
|
||
})
|
||
return arr
|
||
}
|
||
|
||
const handleTableData2 = (obj) => {
|
||
const names = Object.values(obj)?.[0]?.map(o=>o.teamUserName)
|
||
const obj2 = {}
|
||
for(let key in obj){
|
||
const arr = []
|
||
names?.map((name)=>{
|
||
obj?.[key]?.map((item)=>{
|
||
if(name===item.teamUserName){
|
||
arr.push(item)
|
||
}
|
||
})
|
||
})
|
||
obj2[key] = arr
|
||
}
|
||
return obj2
|
||
}
|
||
// 获取清单查看数据
|
||
const [qdColumns, setQdColumns] = useState(newcolumns)
|
||
const [qdWidth, setQdWidth] = useState()
|
||
const getQdViewData = async (id) => {
|
||
try {
|
||
const res = await httpget2(apiurl.rcgl.jdkh.khrwgl.qdView + `/${id}`)
|
||
if (res.code == 200) {
|
||
const linshi = handleTableData2(res.data)//将接口里用户的顺序统一
|
||
const result = handleTableData(linshi);
|
||
const insertCols = [];
|
||
result.forEach((item, index, arr) => {
|
||
const total = arr?.reduce((total, cur) => total + (cur["assessScore" + index] || 0), 0)
|
||
if (item["teamUserName" + index]) {
|
||
insertCols.push( {
|
||
title: item['teamUserName' + index] + `(${total})`,
|
||
key: "assessScore" + index,
|
||
dataIndex: "assessScore" + index,
|
||
width: 80,
|
||
align: "center",
|
||
})
|
||
}
|
||
})
|
||
// 综合得分
|
||
const zfScore = result?.reduce((total,cur) => total + (cur?.indicatorScore || 0),0 )
|
||
insertCols.push({
|
||
title: "综合得分" + `(${zfScore})`,
|
||
key: "indicatorScore",
|
||
dataIndex: "indicatorScore",
|
||
width: 100,
|
||
align: "center",
|
||
render: (v, r) => (
|
||
<div style={{display:"flex",columnGap:10,justifyContent:"center"}}>
|
||
<span>{record?.scoreWay ==1 ? "取最低": record?.scoreWay ==2 ? "平均" : ''}</span>
|
||
<span>{v}</span>
|
||
</div>
|
||
)
|
||
})
|
||
columns.splice(3, 1, ...insertCols)
|
||
const width = columns?.reduce((total, cur) => total + (cur?.width || 0), 0);
|
||
setQdWidth(width)
|
||
setQdColumns(columns)
|
||
result.forEach(item => {
|
||
if (item.rowSpan) delete item.rowSpan;
|
||
})
|
||
const newData = handleData(result, "name")
|
||
setTableData(newData)
|
||
|
||
}
|
||
} catch (error) {
|
||
console.log(error);
|
||
|
||
}
|
||
}
|
||
|
||
// 重置评分
|
||
const resetPf = () => {
|
||
const newData = [...tableData];
|
||
newData.forEach(item => {
|
||
item.assessScore = ''
|
||
})
|
||
setTableData(newData)
|
||
tableDataRef.current = newData
|
||
}
|
||
|
||
// 保存评分
|
||
const savepf = async () => {
|
||
const params = {
|
||
taskId: record.id,
|
||
score,
|
||
ratings: tableData.map(item => ({
|
||
indicatorId: item.indicatorId,
|
||
standardScore: item.standardScore,
|
||
assessScore: item.assessScore,
|
||
teamId: Item.id,
|
||
isNeedRectify: item.isNeedRectify || 0,
|
||
problemDesc: item.problemDesc,
|
||
rectifyRequirement: item.rectifyRequirement,
|
||
rectifyLastDate: item.rectifyLastDate,
|
||
files: item.files,
|
||
fileList:undefined,
|
||
rectifyStatus:0
|
||
}))
|
||
}
|
||
try {
|
||
const res =await httppost2(apiurl.rcgl.jdkh.khrwgl.savePf, params)
|
||
if (res.code == 200) {
|
||
message.success("保存成功")
|
||
refresh()
|
||
} else {
|
||
message.error("保存失败")
|
||
}
|
||
} catch (error) {
|
||
console.log(error);
|
||
}
|
||
}
|
||
|
||
// 确认完成
|
||
const confirm = async () => {
|
||
const params = {
|
||
taskId: record.id,
|
||
score,
|
||
ratings: tableData.map(item => ({
|
||
indicatorId: item.indicatorId,
|
||
standardScore: item.standardScore,
|
||
assessScore: item.assessScore,
|
||
teamId: Item.id,
|
||
isNeedRectify: item.isNeedRectify || 0,
|
||
problemDesc: item.problemDesc,
|
||
rectifyRequirement: item.rectifyRequirement,
|
||
rectifyLastDate: item.rectifyLastDate,
|
||
files: item.files,
|
||
fileList:undefined,
|
||
rectifyStatus:0
|
||
}))
|
||
}
|
||
if(tableData.length>0){
|
||
let flag = true //fasle有位评分的
|
||
params.ratings?.map((item)=>{
|
||
if(item.assessScore==null){
|
||
flag = false
|
||
}
|
||
})
|
||
if(!flag){
|
||
message.error('请输入全部考核评分')
|
||
return
|
||
}
|
||
}
|
||
try {
|
||
const res = await httppost2(apiurl.rcgl.jdkh.khrwgl.confirmpf, params)
|
||
if (res.code == 200) {
|
||
message.success("评分完成")
|
||
refresh()
|
||
onCancel()
|
||
}
|
||
} catch (error) {
|
||
console.log(error);
|
||
|
||
}
|
||
}
|
||
|
||
// 查看评分详情
|
||
const [zgViewOpen, setzgViewOpen] = useState(false)
|
||
const zgView = (record) => {
|
||
setzgViewOpen(true)
|
||
setZgItem(record)
|
||
}
|
||
const [clickItem, setClickItem] = useState()
|
||
// 点击某一行的回调
|
||
const handleRowClick = (record) => {
|
||
setClickItem(record)
|
||
}
|
||
const handleRadioChange = (e) => {
|
||
if (e.target.value == 1) {
|
||
if (tabs == 2) {
|
||
getQdViewData(Item?.id)
|
||
} else {
|
||
getZbTableData(Item?.id,2)
|
||
}
|
||
} else {
|
||
// debugger
|
||
const newData = tabs == 2 ? tableData.filter(item => item.standardScore > item.indicatorScore) :
|
||
tableData.filter(item => item.standardScore > item.assessScore)
|
||
newData.forEach(item => {
|
||
if (item.rowSpan) delete item.rowSpan;
|
||
})
|
||
const res = handleData(newData, "name")
|
||
setTableData(res);
|
||
}
|
||
}
|
||
|
||
// 整改
|
||
const [zgOpen, setZgOpen] = useState(false)
|
||
const [form1] = Form.useForm();
|
||
const [loading, setLoading] = useState(false)
|
||
const [imgloading, setImgLoading] = useState(false)
|
||
const [imgfileList, setImgFileList] = useState([]) //上传文件列表
|
||
|
||
const [zgItem, setZgItem] = useState("")
|
||
const zgCallback = (e) => {
|
||
setZgOpen(true)
|
||
setZgItem(e)
|
||
console.log("ee",e);
|
||
|
||
}
|
||
|
||
const imgbeforeUpload = (file) => {
|
||
const isJpgOrPng =
|
||
file.type === 'image/jpeg' ||
|
||
file.type === 'image/jpg' ||
|
||
file.type === 'image/png';
|
||
|
||
if (!isJpgOrPng) {
|
||
message.error('请上传图片格式的文件!');
|
||
}
|
||
const isLt2M = file.size / 1024 / 1024 < 5;
|
||
if (!isLt2M) {
|
||
message.error('图片大小需小于5M!');
|
||
}
|
||
return isJpgOrPng && isLt2M ? true : Upload.LIST_IGNORE;
|
||
};
|
||
const imgdeleteFile = (fileId) => {
|
||
let filterFile = imgfileList.filter(item => item.response?.data?.fileId !== fileId);
|
||
setImgFileList(filterFile)
|
||
}
|
||
const imgfileChange = (info) => {
|
||
console.log("info",info);
|
||
if (info.file.status === "done") {
|
||
setImgLoading(false);
|
||
}
|
||
if (info.file.status === "uploading") {
|
||
setImgLoading(true);
|
||
}
|
||
if (info.file.status === "error") {
|
||
message.error("文件上传失败")
|
||
setImgLoading(false);
|
||
}
|
||
setImgFileList(info.fileList)
|
||
}
|
||
// 整改数据
|
||
const onfinish = (values) => {
|
||
let files = imgfileList.map(item => ({ fileId: item.response?.data?.fileId }))
|
||
values.files = files;
|
||
values.isNeedRectify = 1;
|
||
values.fileList = imgfileList.map(item => item.response.data);
|
||
const newData = tableData.map(item => {
|
||
if (item.id == zgItem.id) {
|
||
return {...item, ...values}
|
||
} else {
|
||
return item
|
||
}
|
||
})
|
||
setTableData(newData)
|
||
setZgOpen(false)
|
||
setZgItem("")
|
||
form1.resetFields();
|
||
}
|
||
|
||
// 获取指标表格数据
|
||
useEffect(() => {
|
||
// if (Item.type != "start") {
|
||
// if (tabs == 2) {
|
||
// getQdViewData(Item?.id)
|
||
// } else {
|
||
// getZbTableData(Item?.id,2)
|
||
// }
|
||
// } else {
|
||
// getZbTableData(record?.templateId,1)
|
||
|
||
// }
|
||
if (tabs == 2) {
|
||
getQdViewData(Item?.id)
|
||
} else {
|
||
getZbTableData(Item?.id,2)
|
||
}
|
||
}, [record, Item])
|
||
|
||
useEffect(() => {
|
||
const file = zgItem?.fileList ? zgItem.fileList : zgItem.files
|
||
if (file) {
|
||
const imgFile = file?.map(o => ({
|
||
name: o.fileName,
|
||
response: {
|
||
data: {
|
||
filePath: o.filePath,
|
||
fileId:o.fileId
|
||
}
|
||
},
|
||
}))
|
||
setImgFileList(imgFile)
|
||
} else {
|
||
setImgFileList([])
|
||
}
|
||
form1.setFieldsValue({...zgItem})
|
||
}, [zgItem])
|
||
|
||
return (
|
||
<div>
|
||
<Radio.Group style={{marginBottom:10}} defaultValue={1} onChange={(e) => handleRadioChange(e)}>
|
||
<Radio value={1}>显示全部</Radio>
|
||
<Radio value={2}>仅显示扣分项目</Radio>
|
||
</Radio.Group>
|
||
<Table
|
||
components={components}
|
||
rowKey="id"
|
||
columns={Item?.tabs != 2 ?newcolumns :qdColumns }
|
||
dataSource={tableData}
|
||
scroll={{x:Item?.tabs != 2 ? 500: qdWidth, y: "calc( 100vh - 400px )"}}
|
||
pagination={false}
|
||
onRow={(record, rowIndex) => {
|
||
return {
|
||
onClick: () => handleRowClick(record),
|
||
onDoubleClick:(record, rowIndex) => setClickItem()
|
||
};
|
||
}}
|
||
/>
|
||
{clickItem ? <div style={{backgroundColor:"#f2f2f2",marginTop:20,padding:10}}>
|
||
{clickItem?.indicatorRatings?.map(item => (
|
||
<div key={item.id}>
|
||
<div>{item?.ratingDesc}</div>
|
||
</div>
|
||
))}
|
||
</div> : null}
|
||
{!Item?.view ?
|
||
<div className='btns' style={{display:"flex",marginTop:40,justifyContent:"space-between"}}>
|
||
<Button type="primary" onClick={resetPf}>重置评分</Button>
|
||
<div style={{display:"flex",columnGap:10}}>
|
||
<Button type="primary" onClick={onCancel}>取消</Button>
|
||
<Button onClick={savepf}>保存</Button>
|
||
<Button type="primary" onClick={confirm}>确认完成</Button>
|
||
</div>
|
||
</div>
|
||
:
|
||
<div className='btns' style={{display:"flex",marginTop:40,justifyContent:"flex-end"}}>
|
||
<Button onClick={onCancel} type='primary'>关闭</Button>
|
||
</div>
|
||
}
|
||
|
||
{/* 整改 */}
|
||
<Modal
|
||
open={zgOpen}
|
||
width={800}
|
||
footer={null}
|
||
onCancel={() => { setZgOpen(false);form1.resetFields(); }}
|
||
title="整改详情"
|
||
destroyOnClose={true}
|
||
>
|
||
<Form
|
||
form={form1}
|
||
{...formItemLayout}
|
||
onFinish={onfinish}
|
||
// initialValues={zgItem}
|
||
>
|
||
<Row>
|
||
<Col span={24}>
|
||
<Form.Item
|
||
label="问题描述"
|
||
name="problemDesc"
|
||
labelCol={{ span: 3 }}
|
||
wrapperCol={{ span: 19 }}
|
||
rules={[
|
||
{
|
||
required: true,
|
||
},
|
||
]}
|
||
>
|
||
<Input.TextArea style={{width:'100%',minHeight:'100px'}} allowClear />
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
<Row>
|
||
<Col span={24}>
|
||
<Form.Item
|
||
label="整改要求"
|
||
name="rectifyRequirement"
|
||
labelCol={{ span: 3 }}
|
||
wrapperCol={{ span: 19 }}
|
||
>
|
||
<Input.TextArea style={{width:'100%',minHeight:'100px'}} allowClear />
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
<Row>
|
||
<Col span={12}>
|
||
<Form.Item
|
||
label="整改期限"
|
||
name="rectifyLastDate"
|
||
getValueFromEvent={(e,dateString) => dateString}
|
||
getValueProps={(value) => ({ value: value ? moment(value) : undefined })}
|
||
>
|
||
<DatePicker format={'YYYY-MM-DD'} style={{width:'100%'}} allowClear />
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
<Row>
|
||
<Col span={24}>
|
||
<Form.Item
|
||
label="现场图片"
|
||
name="fieldId"
|
||
labelCol={{ span: 3 }}
|
||
wrapperCol={{ span: 19 }}
|
||
>
|
||
|
||
<Dragger
|
||
name='file'
|
||
action="/gunshiApp/tsg/assessTeamRating/file/upload/singleSimple"
|
||
onChange={imgfileChange}
|
||
beforeUpload={imgbeforeUpload}
|
||
onDrop={(info) => { console.log(info); }}
|
||
fileList={imgfileList}
|
||
disabled={imgloading}
|
||
>
|
||
<p className="ant-upload-text">点击或拖拽文件到此区域上传</p>
|
||
<p className="ant-upload-hint">
|
||
支持扩展名:.jpg .png
|
||
</p>
|
||
</Dragger>
|
||
|
||
<Row gutter={[16]}>
|
||
{
|
||
loading ? <span>文件正在上传中,请等待</span> :
|
||
imgfileList.length > 0 && imgfileList.map(file => {
|
||
return (
|
||
<Col span={12}>
|
||
<div className={'file-item'} >
|
||
<div className='file-description'>
|
||
<Image width={60} src={url +file.response?.data?.filePath} alt='' />
|
||
<span>{file.name}</span>
|
||
</div>
|
||
<div
|
||
className={'delete-icon'}
|
||
onClick={() => imgdeleteFile(file.response?.data?.fileId)}
|
||
>
|
||
<DeleteOutlined
|
||
/>
|
||
</div>
|
||
</div>
|
||
</Col>
|
||
)
|
||
})
|
||
}
|
||
|
||
</Row>
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
<Form.Item {...btnItemLayout}>
|
||
<Button type="primary" htmlType="submit">
|
||
提交
|
||
</Button>
|
||
</Form.Item>
|
||
</Form>
|
||
</Modal>
|
||
|
||
{/* 评分详情中整改的详情查看 */}
|
||
<Modal
|
||
open={zgViewOpen}
|
||
width={800}
|
||
footer={null}
|
||
onCancel={() => { setzgViewOpen(false); ;setZgItem('');}}
|
||
title="查看"
|
||
destroyOnClose
|
||
wrapClassName='zgview-modal'
|
||
>
|
||
<PfViewModal zgItem={zgItem} record={Item} onCancel={() => {setzgViewOpen(false); ;setZgItem('');}} />
|
||
</Modal>
|
||
</div>
|
||
)
|
||
}
|