import PageContent from '@/components/PageContent'; import { Button, Tabs, Space, Drawer, Timeline, message } from 'antd'; import styles from './index.less'; import { useEffect, useMemo, useRef, useState } from 'react'; import axios from 'axios'; import { useLocation, useParams, useRequest, useSearchParams, useNavigate, useModel, } from '@umijs/max'; import { queryPsrExcel, queryPsrExcelList, queryPsrMonthDetail, queryPsrMonthLast, queryPsrMonthList, queryPsrWorkLoad, querySavePsrMonth, } from '../../services/psr'; import SaveModal from './components/saveOtherModal'; import CompareModal from './components/compareModal'; import CompareCom from './components/compareCom'; import dayjs from 'dayjs'; import { getToken } from '@/utils/utils'; import { exportExcel, getUUID } from '../../utils/exportExcl'; import { stringify } from 'qs'; import LuckyExcel from 'luckyexcel'; const ZeroNineType = { Equipment: '09-010', //设备费 Production: '09-020', //金科制造中心设备制造费 UF: '09-030', //金科制造中心-UF膜( AI: '09-040', //数字双胞胎 Install: '09-050', //安装分包费用(包括增值税) Construction: '09-060', //土建分包费用(包括增值税) }; const actConfig = [ //实际支出 { type: ZeroNineType.Equipment, originC: 8, originR: { begin: 6, end: 297 }, //总的减上面所有的 fill: { c: 3, r: 36 }, num: 291, }, { type: ZeroNineType.Production, originC: 8, originR: { begin: 17, end: 27 }, //填充到psr表中的位置 fill: { c: 3, r: 37 }, num: 299, }, { type: ZeroNineType.UF, originC: 8, originR: { begin: 6, end: 16 }, fill: { c: 3, r: 38 }, num: 307, }, { type: ZeroNineType.AI, originC: 8, originR: { begin: 172, end: 192 }, fill: { c: 3, r: 39 }, num: 315, }, { type: ZeroNineType.Install, originC: 8, originR: { begin: 214, end: 224 }, fill: { c: 3, r: 40 }, num: 323, }, { type: ZeroNineType.Construction, originC: 8, originR: { begin: 225, end: 235 }, fill: { c: 3, r: 41 }, num: 331, }, ]; const preCeConfig = [ //预测列 { type: ZeroNineType.Equipment, originC: 6, originR: { begin: 6, end: 297 }, //总的减上面所有的 fill: { c: 5, r: 36 }, num: 293, }, { type: ZeroNineType.Production, originC: 6, originR: { begin: 17, end: 27 }, //填充到psr表中的位置 fill: { c: 5, r: 37 }, num: 301, }, { type: ZeroNineType.UF, originC: 6, originR: { begin: 6, end: 16 }, fill: { c: 5, r: 38 }, num: 309, }, { type: ZeroNineType.AI, originC: 6, originR: { begin: 172, end: 192 }, fill: { c: 5, r: 39 }, num: 317, }, { type: ZeroNineType.Install, originC: 6, originR: { begin: 214, end: 224 }, fill: { c: 5, r: 40 }, num: 325, }, { type: ZeroNineType.Construction, originC: 6, originR: { begin: 225, end: 235 }, fill: { c: 5, r: 41 }, num: 333, }, ]; const curMonthConfig = [ //当月发生额 { type: ZeroNineType.Equipment, originC: null, originR: { begin: 6, end: 297 }, //总的减上面所有的 fill: { c: 7, r: 36 }, num: 295, }, { type: ZeroNineType.Production, originC: null, //需要计算的出,当前表单是第几月,取当月的那列 originR: { begin: 17, end: 27 }, fill: { c: 7, r: 37 }, num: 303, }, { type: ZeroNineType.UF, originC: null, originR: { begin: 6, end: 16 }, fill: { c: 7, r: 38 }, num: 311, }, { type: ZeroNineType.AI, originC: null, originR: { begin: 172, end: 192 }, fill: { c: 7, r: 39 }, num: 319, }, { type: ZeroNineType.Install, originC: null, originR: { begin: 214, end: 224 }, fill: { c: 7, r: 40 }, num: 327, }, { type: ZeroNineType.Construction, originC: null, originR: { begin: 225, end: 235 }, fill: { c: 7, r: 41 }, num: 335, }, ]; const workConfig = [ { code: '02-010', fill: { r: 7, actC: 3, curC: 7 }, // actC实际支出 curC当月发生额 }, { code: '04-010', fill: { r: 11, actC: 3, curC: 7 }, }, { code: '05-010', fill: { r: 16, actC: 3, curC: 7 }, }, { code: '05-050', fill: { r: 20, actC: 3, curC: 7 }, }, { code: '06-010', fill: { r: 24, actC: 3, curC: 7 }, }, { code: '07-010', fill: { r: 28, actC: 3, curC: 7 }, }, { code: '08-010', fill: { r: 32, actC: 3, curC: 7 }, }, { code: '10-010', fill: { r: 44, actC: 3, curC: 7 }, }, { code: '11-010', fill: { r: 59, actC: 3, curC: 7 }, }, { code: '11-030', fill: { r: 61, actC: 3, curC: 7 }, }, { code: '11-050', fill: { r: 63, actC: 3, curC: 7 }, }, ]; const PSRDetail = () => { const { initialState } = useModel('@@initialState'); const user = initialState?.user || {}; const navigate = useNavigate(); const params = useParams(); const location = useLocation(); const token = getToken(); const { id: projectId } = params; const { state: { project_name, flow_id, node_id, init_flow_id }, } = location; const [historyList, setHistoryList] = useState([]); const [excelData, setExcelData] = useState(); const [historyOpen, setHistoryOpen] = useState(); const [open, setOpen] = useState(false); const [key, setKey] = useState(); const [compareOpen, setCompareOpen] = useState(false); const [compareValues, setCompareValues] = useState([]); const [isOriginVer, setIsOriginVer] = useState(false); //是否原始版本 是的话只能另存不能编辑 const [noData, setNoData] = useState(false); //是否展示导出按钮 const titleRef = useRef(''); const luckysheetRef = useRef(); const iframeRef = useRef(); const unableEdit = (option) => { option.showtoolbar = false; option.enableAddRow = false; option.sheetFormulaBar = false; option.enableAddBackTop = false; option.showsheetbarConfig = { add: false, sheet: false, }; option.cellRightClickConfig = { copy: false, // 复制 copyAs: false, // 复制为 paste: false, // 粘贴 insertRow: false, // 插入行 insertColumn: false, // 插入列 deleteRow: false, // 删除选中行 deleteColumn: false, // 删除选中列 deleteCell: false, // 删除单元格 hideRow: false, // 隐藏选中行和显示选中行 hideColumn: false, // 隐藏选中列和显示选中列 rowHeight: false, // 行高 columnWidth: false, // 列宽 clear: false, // 清除内容 matrix: false, // 矩阵操作选区 sort: false, // 排序选区 filter: false, // 筛选选区 chart: false, // 图表生成 image: false, // 插入图片 link: false, // 插入链接 data: false, // 数据验证 cellFormat: false, // 设置单元格格式 }; }; //请求投标版、签字版psr excel // const { run: runExcel } = useRequest(queryPsrExcel, { // manual: true, // formatResult: (res) => { // if (res) { // const jsonData = JSON.parse(res); // renderSheet(jsonData); // } // }, // }); //请求月度psr和现金流列表 data_type 1 psr 2 现金流 const { // data: historyList, run: runList, loading: listLoading, } = useRequest( (data) => queryPsrMonthList({ project_id: projectId, data_type: data_type, ...data, }), { manual: true, formatResult: (res) => { if (res.code == 200) { const list = res?.data?.list?.map((item) => { let name = dayjs(item.day).format('YYYY-MM'); if (item.ver_type == 1) name = '原始版本'; if (item.ver_type == 2) name = '基础版本'; return { ...item, name: `${titleRef.current}${name}` }; }); setHistoryList(list); } }, }, ); //保存月度psr和现金流接口 const { run: runSave, loading: saveLoading } = useRequest( (data) => querySavePsrMonth(data), { manual: true, onSuccess: () => { message.success('保存成功'); }, onError: () => { message.success('添加失败'); }, }, ); //另存为月度psr和现金流接口 const { run: runSaveOther, loading: saveOtherLoading } = useRequest( (data) => querySavePsrMonth(data), { manual: true, onSuccess: (data) => { if (data) { message.error(data); return; } message.success('另存成功'); if (open) setOpen(false); //另存成功之后切换到最新的记录 initPsrActrual(key); }, onError: () => { message.success('另存失败'); }, }, ); //请求月度psr和现金流详情接口 const { run: runDetail } = useRequest((data) => queryPsrMonthDetail(data), { manual: true, formatResult: (res) => { if (res?.data) { let data = res.data; let name = `${titleRef.current}${dayjs(data.day).format('YYYY-MM')}`; if (data.ver_type == 1) name = '原始版本'; if (data.ver_type == 2) name = '基础版本'; setExcelData({ ...data, name }); setHistoryOpen(false); const jsonData = JSON.parse(data.json_data); jsonData.map((item) => { if (item.celldata && typeof item.celldata == 'string') item.celldata = JSON.parse(item.celldata); if (item.config && typeof item.config == 'string') item.config = JSON.parse(item.config); if (item?.name == 'PSR') item.hide = 0; }); renderSheet(jsonData, data.is_edit, data.day); } else { setExcelData({ name: '' }); setNoData(true); } }, }); //请求签字版PSR历史版本列表 const { run: run, loading: loading } = useRequest( (id) => queryPsrExcelList({ project_id: projectId, template_node_id: id, }), { manual: true, formatResult: (res) => { if (res.code == 200) { const list = res?.data?.list?.map((item) => { return { ...item, name: item.version_name }; }); setHistoryList(list); } }, }, ); const data_type = useMemo(() => { if (key == '3') return 1; if (key == '4') return 2; return null; }, [key]); useEffect(() => { let str = ''; switch (key) { case '2': str = '签字版PSR_'; break; case '3': str = '过程/终版PSR_'; runList({ data_type: 1 }); break; case '4': str = '现金流_'; runList({ data_type: 2 }); break; } titleRef.current = str; setCompareValues([]); onChange(key); }, [key]); const onChange = (key) => { if (!key) return; if (key == '1') { queryPsrExcel({ gridKey: node_id }); } else if (key == '2') { queryPsrExcel({ gridKey: flow_id }); } else { initPsrActrual(key); } }; //请求投标版、签字版psr excel const queryPsrExcel = (data) => { axios({ url: `/api/v1/purchase/record/sheet?${stringify(data)}`, method: 'POST', data, headers: { 'JWT-TOKEN': token, }, }).then((req) => { if (req.status == 200) { const jsonData = JSON.parse(req.data); renderSheet(jsonData); } }); }; //请求 过程/终版PSR 现金流最近一条数据 const initPsrActrual = async (key) => { const data_type = key == '3' ? 1 : 2; const res = await queryPsrMonthLast({ project_id: projectId, data_type }); if (res.data?.length > 0 && res.data[0].json_data) { let name = `${titleRef.current}${dayjs(res.data[0].day).format( 'YYYY-MM', )}`; if (res.data[0].ver_type == 1) name = '原始版本'; if (res.data[0].ver_type == 2) name = '基础版本'; console.log('------------------', res.data); const isOrigin = res.data[0].ver_type == 1 ? 1 : 0; setIsOriginVer(isOrigin); setExcelData({ ...res.data[0], name }); let data = JSON.parse(res.data[0].json_data); const canEdit = isOrigin ? 0 : res.data[0].is_edit; if (!Array.isArray(data)) { data = [data]; } data.map((item) => { if (item.name == 'PSR') item.hide = 0; if (data_type == 2) item.hide = 0; if (item.celldata && typeof item.celldata == 'string') item.celldata = JSON.parse(item.celldata); if (item.config && typeof item.config == 'string') item.config = JSON.parse(item.config); }); renderSheet(data, canEdit, res.data[0].day); } else { setIsOriginVer(false); setExcelData({ name: '' }); setNoData(true); } }; //另存为月版本 const handlerSaveOther = (data) => { const luckyData = luckysheetRef.current?.toJson(); luckyData?.data.forEach((item) => delete item.data); //设置表单日期 const date = data.ver_type == 2 //基础版本是创建当天的日期 月版本是创建月份的最后一天 ? dayjs().format('YYYY-MM-DD') : dayjs(data.day).endOf('month').format('YYYY-MM-DD'); const days = changeDate(date); const celldata = luckyData?.data[0]?.celldata; const rc = key == '3' ? { r: 1, c: 1 } : { r: 1, c: 3 }; //psr日期位置是1 1 现金流日期位置是 1 3 const dateItem = celldata?.find((item) => item.r == rc.r && item.c == rc.c); if (dateItem) { dateItem.v.v = days + ''; // dateItem.v.m = days; } if (luckyData?.data) { const params = { ...data, project_id: Number(projectId), json_data: JSON.stringify(luckyData.data), data_type: data_type, }; console.log(params); runSaveOther(params); } }; //保存 const handlerSave = () => { // 手动触发单元格的完成编辑事件 const $ = iframeRef.current.contentWindow.$; const e = $.Event('keydown'); e.keyCode = 13; $('.luckysheet-cell-input').trigger(e); const luckyData = luckysheetRef.current?.toJson(); let allData; //如果是现金流的保存。需要计算一些数值填充到psr中; if (key == '4') { //当月发生额数据 计算当月发生额的月份 originC let newMonthConfig = [...curMonthConfig]; const celldata = luckyData.data[0].celldata; const originC = getMonthCol(celldata); if (originC || originC == 0) { newMonthConfig = curMonthConfig.map((item) => { return { ...item, originC }; }); } allData = getPsrDataByAct(actConfig, preCeConfig, newMonthConfig); } const params = { id: excelData?.id, data_type: excelData?.data_type, project_id: excelData?.project_id, day: dayjs(excelData?.day).format('YYYY-MM-DD'), json_data: JSON.stringify(luckyData.data), psr_json_data: JSON.stringify(allData), ver_type: excelData?.ver_type, }; console.log(params, allData); runSave(params); }; //获取当月发生额的月份 const getMonthCol = (celldata) => { //计算出当月发生额的月份 originC const date = changeDate(excelData?.day); //转换成55078这种格式 const originC = celldata.find( (item) => item.r == 5 && Math.abs(item.v?.v - date) < 5, )?.c; return originC; }; const getPsrDataByAct = (...list) => { const luckyData = luckysheetRef.current?.toJson(); const fun = (configList) => { let otherValueTotal = 0; //获取除设备费之外的所有费用的和 const preValues = configList.map((item) => { const celldata = luckyData.data[0].celldata; const { type, originC, num, originR: { begin, end }, } = item; let value = 0; for (let i = begin; i <= end; i++) { const item = celldata.find( (item) => item.c == originC && item.r == i, ); if (item?.v?.v) value += item.v.v; } if (type !== ZeroNineType.Equipment) otherValueTotal += value; return { num, value }; }); //获取设备值 const EquPreItem = preValues.find((item) => { const shebeiNum = configList.find( (cur) => cur.type == ZeroNineType.Equipment, )?.num; return item.num == shebeiNum; }); //全部的费用 减去 除设备费之外的所有费用的和 得到设备费 if (EquPreItem?.value) EquPreItem.value = EquPreItem?.value - otherValueTotal; return preValues; }; let result = []; list.forEach((item) => { const list = fun(item); result = [...result, ...list]; }); console.log('------预算列的值---------', result); return result; }; const exportExcl = (className) => { const luckyData = luckysheetRef.current?.toJson(); let data = []; luckyData?.data.forEach((item) => { let sheet = JSON.parse(JSON.stringify(item)); // 只导出不隐藏的sheet页 if (sheet.hide == 1) return; let rows = [], cols = []; // 过滤隐藏的行 if (sheet.config.rowhidden) { rows = Object.keys(sheet.config.rowhidden); rows.forEach((row) => { sheet.data[row] = sheet.data[row].map((_) => null); }); } // 过滤隐藏的列 if (sheet.config.colhidden) { cols = Object.keys(sheet.config.colhidden); cols.forEach((col) => { sheet.data.forEach((row) => (row[col] = null)); }); } //处理时间错乱问题,把v全部换成m显示值 sheet.data?.forEach((row) => { row.forEach((cell) => { if (!cell) return; cell.v = cell.m; delete cell.f; }); }); data.push(sheet); }); console.log(data); exportExcel(data, className); }; const handlerLoad = () => { const contentWindow = iframeRef.current.contentWindow; luckysheetRef.current = contentWindow.luckysheet; }; //计算现金流表设备没数据的行隐藏 const setActHideRow = (data) => { const rowHide = {}; const rang = [6, 246]; const otherRang = [247, 297]; let otherBegin; data.celldata.forEach((cell) => { if (cell.c !== 2) return; if (cell.r >= rang[0] && cell.r <= rang[1]) { if (!cell.v?.v) { const key1 = cell.r.toString(); rowHide[key1] = 0; } } else if ( cell.r >= otherRang[0] && cell.r <= otherRang[1] && !cell.v?.v ) { if (!otherBegin) { otherBegin = cell.r + 5; } else if (cell.r >= otherBegin) { const key1 = cell.r.toString(); rowHide[key1] = 0; } } }); console.log('------------------rowHide--------------', rowHide); return rowHide; }; const fillWorkLoadData = async (day) => { const param = { project_id: projectId }; param.code = workConfig.map((item) => item.code).join(','); param.s_time = dayjs(day).add(-1, 'month').format('YYYY-MM') + '-26'; param.e_time = dayjs(day).format('YYYY-MM') + '-25'; const res = await queryPsrWorkLoad(param); if (res?.data) { const data = res?.data; //{ '02-010': [800, 100] }; Object.keys(data).forEach((code) => { const list = data[code]; //第一个是当月的,第二个是累计的 const fill = workConfig.find((item) => item.code == code)?.fill; if (list?.length > 0 && fill) { luckysheetRef.current.setCellValue(fill.r, fill.curC, list[0]); luckysheetRef.current.setCellValue(fill.r, fill.actC, list[1]); } }); console.log('--------------------', res.data); } }; const renderTitle = (data_type, name) => { if (compareValues?.length == 2) { return (