detail.js 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060
  1. import PageContent from '@/components/PageContent';
  2. import { Button, Tabs, Space, Drawer, Timeline, message } from 'antd';
  3. import styles from './index.less';
  4. import { useEffect, useMemo, useRef, useState } from 'react';
  5. import axios from 'axios';
  6. import {
  7. useLocation,
  8. useParams,
  9. useRequest,
  10. useSearchParams,
  11. useNavigate,
  12. useModel,
  13. } from '@umijs/max';
  14. import {
  15. queryPsrExcel,
  16. queryPsrExcelList,
  17. queryPsrMonthDetail,
  18. queryPsrMonthLast,
  19. queryPsrMonthList,
  20. queryPsrWorkLoad,
  21. querySavePsrMonth,
  22. } from '../../services/psr';
  23. import SaveModal from './components/saveOtherModal';
  24. import CompareModal from './components/compareModal';
  25. import CompareCom from './components/compareCom';
  26. import dayjs from 'dayjs';
  27. import { getToken } from '@/utils/utils';
  28. import { exportExcel, getUUID } from '../../utils/exportExcl';
  29. import { stringify } from 'qs';
  30. import LuckyExcel from 'luckyexcel';
  31. const ZeroNineType = {
  32. Equipment: '09-010', //设备费
  33. Production: '09-020', //金科制造中心设备制造费
  34. UF: '09-030', //金科制造中心-UF膜(
  35. AI: '09-040', //数字双胞胎
  36. Install: '09-050', //安装分包费用(包括增值税)
  37. Construction: '09-060', //土建分包费用(包括增值税)
  38. };
  39. const actConfig = [
  40. //实际支出
  41. {
  42. type: ZeroNineType.Equipment,
  43. originC: 8,
  44. originR: { begin: 6, end: 297 }, //总的减上面所有的
  45. fill: { c: 3, r: 36 },
  46. num: 291,
  47. },
  48. {
  49. type: ZeroNineType.Production,
  50. originC: 8,
  51. originR: { begin: 17, end: 27 },
  52. //填充到psr表中的位置
  53. fill: { c: 3, r: 37 },
  54. num: 299,
  55. },
  56. {
  57. type: ZeroNineType.UF,
  58. originC: 8,
  59. originR: { begin: 6, end: 16 },
  60. fill: { c: 3, r: 38 },
  61. num: 307,
  62. },
  63. {
  64. type: ZeroNineType.AI,
  65. originC: 8,
  66. originR: { begin: 172, end: 192 },
  67. fill: { c: 3, r: 39 },
  68. num: 315,
  69. },
  70. {
  71. type: ZeroNineType.Install,
  72. originC: 8,
  73. originR: { begin: 214, end: 224 },
  74. fill: { c: 3, r: 40 },
  75. num: 323,
  76. },
  77. {
  78. type: ZeroNineType.Construction,
  79. originC: 8,
  80. originR: { begin: 225, end: 235 },
  81. fill: { c: 3, r: 41 },
  82. num: 331,
  83. },
  84. ];
  85. const preCeConfig = [
  86. //预测列
  87. {
  88. type: ZeroNineType.Equipment,
  89. originC: 6,
  90. originR: { begin: 6, end: 297 }, //总的减上面所有的
  91. fill: { c: 5, r: 36 },
  92. num: 293,
  93. },
  94. {
  95. type: ZeroNineType.Production,
  96. originC: 6,
  97. originR: { begin: 17, end: 27 },
  98. //填充到psr表中的位置
  99. fill: { c: 5, r: 37 },
  100. num: 301,
  101. },
  102. {
  103. type: ZeroNineType.UF,
  104. originC: 6,
  105. originR: { begin: 6, end: 16 },
  106. fill: { c: 5, r: 38 },
  107. num: 309,
  108. },
  109. {
  110. type: ZeroNineType.AI,
  111. originC: 6,
  112. originR: { begin: 172, end: 192 },
  113. fill: { c: 5, r: 39 },
  114. num: 317,
  115. },
  116. {
  117. type: ZeroNineType.Install,
  118. originC: 6,
  119. originR: { begin: 214, end: 224 },
  120. fill: { c: 5, r: 40 },
  121. num: 325,
  122. },
  123. {
  124. type: ZeroNineType.Construction,
  125. originC: 6,
  126. originR: { begin: 225, end: 235 },
  127. fill: { c: 5, r: 41 },
  128. num: 333,
  129. },
  130. ];
  131. const curMonthConfig = [
  132. //当月发生额
  133. {
  134. type: ZeroNineType.Equipment,
  135. originC: null,
  136. originR: { begin: 6, end: 297 }, //总的减上面所有的
  137. fill: { c: 7, r: 36 },
  138. num: 295,
  139. },
  140. {
  141. type: ZeroNineType.Production,
  142. originC: null, //需要计算的出,当前表单是第几月,取当月的那列
  143. originR: { begin: 17, end: 27 },
  144. fill: { c: 7, r: 37 },
  145. num: 303,
  146. },
  147. {
  148. type: ZeroNineType.UF,
  149. originC: null,
  150. originR: { begin: 6, end: 16 },
  151. fill: { c: 7, r: 38 },
  152. num: 311,
  153. },
  154. {
  155. type: ZeroNineType.AI,
  156. originC: null,
  157. originR: { begin: 172, end: 192 },
  158. fill: { c: 7, r: 39 },
  159. num: 319,
  160. },
  161. {
  162. type: ZeroNineType.Install,
  163. originC: null,
  164. originR: { begin: 214, end: 224 },
  165. fill: { c: 7, r: 40 },
  166. num: 327,
  167. },
  168. {
  169. type: ZeroNineType.Construction,
  170. originC: null,
  171. originR: { begin: 225, end: 235 },
  172. fill: { c: 7, r: 41 },
  173. num: 335,
  174. },
  175. ];
  176. const workConfig = [
  177. {
  178. code: '02-010',
  179. fill: { r: 7, actC: 3, curC: 7 }, // actC实际支出 curC当月发生额
  180. },
  181. {
  182. code: '04-010',
  183. fill: { r: 11, actC: 3, curC: 7 },
  184. },
  185. {
  186. code: '05-010',
  187. fill: { r: 16, actC: 3, curC: 7 },
  188. },
  189. {
  190. code: '05-050',
  191. fill: { r: 20, actC: 3, curC: 7 },
  192. },
  193. {
  194. code: '06-010',
  195. fill: { r: 24, actC: 3, curC: 7 },
  196. },
  197. {
  198. code: '07-010',
  199. fill: { r: 28, actC: 3, curC: 7 },
  200. },
  201. {
  202. code: '08-010',
  203. fill: { r: 32, actC: 3, curC: 7 },
  204. },
  205. {
  206. code: '10-010',
  207. fill: { r: 44, actC: 3, curC: 7 },
  208. },
  209. {
  210. code: '11-010',
  211. fill: { r: 59, actC: 3, curC: 7 },
  212. },
  213. {
  214. code: '11-030',
  215. fill: { r: 61, actC: 3, curC: 7 },
  216. },
  217. {
  218. code: '11-050',
  219. fill: { r: 63, actC: 3, curC: 7 },
  220. },
  221. ];
  222. const PSRDetail = () => {
  223. const { initialState } = useModel('@@initialState');
  224. const user = initialState?.user || {};
  225. const navigate = useNavigate();
  226. const params = useParams();
  227. const location = useLocation();
  228. const token = getToken();
  229. const { id: projectId } = params;
  230. const {
  231. state: { project_name, flow_id, node_id, init_flow_id },
  232. } = location;
  233. const [historyList, setHistoryList] = useState([]);
  234. const [excelData, setExcelData] = useState();
  235. const [historyOpen, setHistoryOpen] = useState();
  236. const [open, setOpen] = useState(false);
  237. const [key, setKey] = useState();
  238. const [compareOpen, setCompareOpen] = useState(false);
  239. const [compareValues, setCompareValues] = useState([]);
  240. const [isOriginVer, setIsOriginVer] = useState(false); //是否原始版本 是的话只能另存不能编辑
  241. const [noData, setNoData] = useState(false); //是否展示导出按钮
  242. const titleRef = useRef('');
  243. const luckysheetRef = useRef();
  244. const iframeRef = useRef();
  245. const unableEdit = (option) => {
  246. option.showtoolbar = false;
  247. option.enableAddRow = false;
  248. option.sheetFormulaBar = false;
  249. option.enableAddBackTop = false;
  250. option.showsheetbarConfig = {
  251. add: false,
  252. sheet: false,
  253. };
  254. option.cellRightClickConfig = {
  255. copy: false, // 复制
  256. copyAs: false, // 复制为
  257. paste: false, // 粘贴
  258. insertRow: false, // 插入行
  259. insertColumn: false, // 插入列
  260. deleteRow: false, // 删除选中行
  261. deleteColumn: false, // 删除选中列
  262. deleteCell: false, // 删除单元格
  263. hideRow: false, // 隐藏选中行和显示选中行
  264. hideColumn: false, // 隐藏选中列和显示选中列
  265. rowHeight: false, // 行高
  266. columnWidth: false, // 列宽
  267. clear: false, // 清除内容
  268. matrix: false, // 矩阵操作选区
  269. sort: false, // 排序选区
  270. filter: false, // 筛选选区
  271. chart: false, // 图表生成
  272. image: false, // 插入图片
  273. link: false, // 插入链接
  274. data: false, // 数据验证
  275. cellFormat: false, // 设置单元格格式
  276. };
  277. };
  278. //请求投标版、签字版psr excel
  279. // const { run: runExcel } = useRequest(queryPsrExcel, {
  280. // manual: true,
  281. // formatResult: (res) => {
  282. // if (res) {
  283. // const jsonData = JSON.parse(res);
  284. // renderSheet(jsonData);
  285. // }
  286. // },
  287. // });
  288. //请求月度psr和现金流列表 data_type 1 psr 2 现金流
  289. const {
  290. // data: historyList,
  291. run: runList,
  292. loading: listLoading,
  293. } = useRequest(
  294. (data) =>
  295. queryPsrMonthList({
  296. project_id: projectId,
  297. data_type: data_type,
  298. ...data,
  299. }),
  300. {
  301. manual: true,
  302. formatResult: (res) => {
  303. if (res.code == 200) {
  304. const list = res?.data?.list?.map((item) => {
  305. let name = dayjs(item.day).format('YYYY-MM');
  306. if (item.ver_type == 1) name = '原始版本';
  307. if (item.ver_type == 2) name = '基础版本';
  308. return { ...item, name: `${titleRef.current}${name}` };
  309. });
  310. setHistoryList(list);
  311. }
  312. },
  313. },
  314. );
  315. //保存月度psr和现金流接口
  316. const { run: runSave, loading: saveLoading } = useRequest(
  317. (data) => querySavePsrMonth(data),
  318. {
  319. manual: true,
  320. onSuccess: () => {
  321. message.success('保存成功');
  322. },
  323. onError: () => {
  324. message.success('添加失败');
  325. },
  326. },
  327. );
  328. //另存为月度psr和现金流接口
  329. const { run: runSaveOther, loading: saveOtherLoading } = useRequest(
  330. (data) => querySavePsrMonth(data),
  331. {
  332. manual: true,
  333. onSuccess: (data) => {
  334. if (data) {
  335. message.error(data);
  336. return;
  337. }
  338. message.success('另存成功');
  339. if (open) setOpen(false);
  340. //另存成功之后切换到最新的记录
  341. initPsrActrual(key);
  342. },
  343. onError: () => {
  344. message.success('另存失败');
  345. },
  346. },
  347. );
  348. //请求月度psr和现金流详情接口
  349. const { run: runDetail } = useRequest((data) => queryPsrMonthDetail(data), {
  350. manual: true,
  351. formatResult: (res) => {
  352. if (res?.data) {
  353. let data = res.data;
  354. let name = `${titleRef.current}${dayjs(data.day).format('YYYY-MM')}`;
  355. if (data.ver_type == 1) name = '原始版本';
  356. if (data.ver_type == 2) name = '基础版本';
  357. setExcelData({ ...data, name });
  358. setHistoryOpen(false);
  359. const jsonData = JSON.parse(data.json_data);
  360. jsonData.map((item) => {
  361. if (item.celldata && typeof item.celldata == 'string')
  362. item.celldata = JSON.parse(item.celldata);
  363. if (item.config && typeof item.config == 'string')
  364. item.config = JSON.parse(item.config);
  365. if (item?.name == 'PSR') item.hide = 0;
  366. });
  367. renderSheet(jsonData, data.is_edit, data.day);
  368. } else {
  369. setExcelData({ name: '' });
  370. setNoData(true);
  371. }
  372. },
  373. });
  374. //请求签字版PSR历史版本列表
  375. const { run: run, loading: loading } = useRequest(
  376. (id) =>
  377. queryPsrExcelList({
  378. project_id: projectId,
  379. template_node_id: id,
  380. }),
  381. {
  382. manual: true,
  383. formatResult: (res) => {
  384. if (res.code == 200) {
  385. const list = res?.data?.list?.map((item) => {
  386. return { ...item, name: item.version_name };
  387. });
  388. setHistoryList(list);
  389. }
  390. },
  391. },
  392. );
  393. const data_type = useMemo(() => {
  394. if (key == '3') return 1;
  395. if (key == '4') return 2;
  396. return null;
  397. }, [key]);
  398. useEffect(() => {
  399. let str = '';
  400. switch (key) {
  401. case '2':
  402. str = '签字版PSR_';
  403. break;
  404. case '3':
  405. str = '过程/终版PSR_';
  406. runList({ data_type: 1 });
  407. break;
  408. case '4':
  409. str = '现金流_';
  410. runList({ data_type: 2 });
  411. break;
  412. }
  413. titleRef.current = str;
  414. setCompareValues([]);
  415. onChange(key);
  416. }, [key]);
  417. const onChange = (key) => {
  418. if (!key) return;
  419. if (key == '1') {
  420. queryPsrExcel({ gridKey: node_id });
  421. } else if (key == '2') {
  422. queryPsrExcel({ gridKey: flow_id });
  423. } else {
  424. initPsrActrual(key);
  425. }
  426. };
  427. //请求投标版、签字版psr excel
  428. const queryPsrExcel = (data) => {
  429. axios({
  430. url: `/api/v1/purchase/record/sheet?${stringify(data)}`,
  431. method: 'POST',
  432. data,
  433. headers: {
  434. 'JWT-TOKEN': token,
  435. },
  436. }).then((req) => {
  437. if (req.status == 200) {
  438. const jsonData = JSON.parse(req.data);
  439. renderSheet(jsonData);
  440. }
  441. });
  442. };
  443. //请求 过程/终版PSR 现金流最近一条数据
  444. const initPsrActrual = async (key) => {
  445. const data_type = key == '3' ? 1 : 2;
  446. const res = await queryPsrMonthLast({ project_id: projectId, data_type });
  447. if (res.data?.length > 0 && res.data[0].json_data) {
  448. let name = `${titleRef.current}${dayjs(res.data[0].day).format(
  449. 'YYYY-MM',
  450. )}`;
  451. if (res.data[0].ver_type == 1) name = '原始版本';
  452. if (res.data[0].ver_type == 2) name = '基础版本';
  453. console.log('------------------', res.data);
  454. const isOrigin = res.data[0].ver_type == 1 ? 1 : 0;
  455. setIsOriginVer(isOrigin);
  456. setExcelData({ ...res.data[0], name });
  457. let data = JSON.parse(res.data[0].json_data);
  458. const canEdit = isOrigin ? 0 : res.data[0].is_edit;
  459. if (!Array.isArray(data)) {
  460. data = [data];
  461. }
  462. data.map((item) => {
  463. if (item.name == 'PSR') item.hide = 0;
  464. if (data_type == 2) item.hide = 0;
  465. if (item.celldata && typeof item.celldata == 'string')
  466. item.celldata = JSON.parse(item.celldata);
  467. if (item.config && typeof item.config == 'string')
  468. item.config = JSON.parse(item.config);
  469. });
  470. renderSheet(data, canEdit, res.data[0].day);
  471. } else {
  472. setIsOriginVer(false);
  473. setExcelData({ name: '' });
  474. setNoData(true);
  475. }
  476. };
  477. //另存为月版本
  478. const handlerSaveOther = (data) => {
  479. const luckyData = luckysheetRef.current?.toJson();
  480. luckyData?.data.forEach((item) => delete item.data);
  481. //设置表单日期
  482. const date =
  483. data.ver_type == 2 //基础版本是创建当天的日期 月版本是创建月份的最后一天
  484. ? dayjs().format('YYYY-MM-DD')
  485. : dayjs(data.day).endOf('month').format('YYYY-MM-DD');
  486. const days = changeDate(date);
  487. const celldata = luckyData?.data[0]?.celldata;
  488. const rc = key == '3' ? { r: 1, c: 1 } : { r: 1, c: 3 }; //psr日期位置是1 1 现金流日期位置是 1 3
  489. const dateItem = celldata?.find((item) => item.r == rc.r && item.c == rc.c);
  490. if (dateItem) {
  491. dateItem.v.v = days + '';
  492. // dateItem.v.m = days;
  493. }
  494. if (luckyData?.data) {
  495. const params = {
  496. ...data,
  497. project_id: Number(projectId),
  498. json_data: JSON.stringify(luckyData.data),
  499. data_type: data_type,
  500. };
  501. console.log(params);
  502. runSaveOther(params);
  503. }
  504. };
  505. //保存
  506. const handlerSave = () => {
  507. // 手动触发单元格的完成编辑事件
  508. const $ = iframeRef.current.contentWindow.$;
  509. const e = $.Event('keydown');
  510. e.keyCode = 13;
  511. $('.luckysheet-cell-input').trigger(e);
  512. const luckyData = luckysheetRef.current?.toJson();
  513. let allData;
  514. //如果是现金流的保存。需要计算一些数值填充到psr中;
  515. if (key == '4') {
  516. //当月发生额数据 计算当月发生额的月份 originC
  517. let newMonthConfig = [...curMonthConfig];
  518. const celldata = luckyData.data[0].celldata;
  519. const originC = getMonthCol(celldata);
  520. if (originC || originC == 0) {
  521. newMonthConfig = curMonthConfig.map((item) => {
  522. return { ...item, originC };
  523. });
  524. }
  525. allData = getPsrDataByAct(actConfig, preCeConfig, newMonthConfig);
  526. }
  527. const params = {
  528. id: excelData?.id,
  529. data_type: excelData?.data_type,
  530. project_id: excelData?.project_id,
  531. day: dayjs(excelData?.day).format('YYYY-MM-DD'),
  532. json_data: JSON.stringify(luckyData.data),
  533. psr_json_data: JSON.stringify(allData),
  534. ver_type: excelData?.ver_type,
  535. };
  536. console.log(params, allData);
  537. runSave(params);
  538. };
  539. //获取当月发生额的月份
  540. const getMonthCol = (celldata) => {
  541. //计算出当月发生额的月份 originC
  542. const date = changeDate(excelData?.day); //转换成55078这种格式
  543. const originC = celldata.find(
  544. (item) => item.r == 5 && Math.abs(item.v?.v - date) < 5,
  545. )?.c;
  546. return originC;
  547. };
  548. const getPsrDataByAct = (...list) => {
  549. const luckyData = luckysheetRef.current?.toJson();
  550. const fun = (configList) => {
  551. let otherValueTotal = 0; //获取除设备费之外的所有费用的和
  552. const preValues = configList.map((item) => {
  553. const celldata = luckyData.data[0].celldata;
  554. const {
  555. type,
  556. originC,
  557. num,
  558. originR: { begin, end },
  559. } = item;
  560. let value = 0;
  561. for (let i = begin; i <= end; i++) {
  562. const item = celldata.find(
  563. (item) => item.c == originC && item.r == i,
  564. );
  565. if (item?.v?.v) value += item.v.v;
  566. }
  567. if (type !== ZeroNineType.Equipment) otherValueTotal += value;
  568. return { num, value };
  569. });
  570. //获取设备值
  571. const EquPreItem = preValues.find((item) => {
  572. const shebeiNum = configList.find(
  573. (cur) => cur.type == ZeroNineType.Equipment,
  574. )?.num;
  575. return item.num == shebeiNum;
  576. });
  577. //全部的费用 减去 除设备费之外的所有费用的和 得到设备费
  578. if (EquPreItem?.value)
  579. EquPreItem.value = EquPreItem?.value - otherValueTotal;
  580. return preValues;
  581. };
  582. let result = [];
  583. list.forEach((item) => {
  584. const list = fun(item);
  585. result = [...result, ...list];
  586. });
  587. console.log('------预算列的值---------', result);
  588. return result;
  589. };
  590. const exportExcl = (className) => {
  591. const luckyData = luckysheetRef.current?.toJson();
  592. let data = [];
  593. luckyData?.data.forEach((item) => {
  594. let sheet = JSON.parse(JSON.stringify(item));
  595. // 只导出不隐藏的sheet页
  596. if (sheet.hide == 1) return;
  597. let rows = [],
  598. cols = [];
  599. // 过滤隐藏的行
  600. if (sheet.config.rowhidden) {
  601. rows = Object.keys(sheet.config.rowhidden);
  602. rows.forEach((row) => {
  603. sheet.data[row] = sheet.data[row].map((_) => null);
  604. });
  605. }
  606. // 过滤隐藏的列
  607. if (sheet.config.colhidden) {
  608. cols = Object.keys(sheet.config.colhidden);
  609. cols.forEach((col) => {
  610. sheet.data.forEach((row) => (row[col] = null));
  611. });
  612. }
  613. //处理时间错乱问题,把v全部换成m显示值
  614. sheet.data?.forEach((row) => {
  615. row.forEach((cell) => {
  616. if (!cell) return;
  617. cell.v = cell.m;
  618. delete cell.f;
  619. });
  620. });
  621. data.push(sheet);
  622. });
  623. console.log(data);
  624. exportExcel(data, className);
  625. };
  626. const handlerLoad = () => {
  627. const contentWindow = iframeRef.current.contentWindow;
  628. luckysheetRef.current = contentWindow.luckysheet;
  629. };
  630. //计算现金流表设备没数据的行隐藏
  631. const setActHideRow = (data) => {
  632. const rowHide = {};
  633. const rang = [6, 246];
  634. const otherRang = [247, 297];
  635. let otherBegin;
  636. data.celldata.forEach((cell) => {
  637. if (cell.c !== 2) return;
  638. if (cell.r >= rang[0] && cell.r <= rang[1]) {
  639. if (!cell.v?.v) {
  640. const key1 = cell.r.toString();
  641. rowHide[key1] = 0;
  642. }
  643. } else if (
  644. cell.r >= otherRang[0] &&
  645. cell.r <= otherRang[1] &&
  646. !cell.v?.v
  647. ) {
  648. if (!otherBegin) {
  649. otherBegin = cell.r + 5;
  650. } else if (cell.r >= otherBegin) {
  651. const key1 = cell.r.toString();
  652. rowHide[key1] = 0;
  653. }
  654. }
  655. });
  656. console.log('------------------rowHide--------------', rowHide);
  657. return rowHide;
  658. };
  659. const fillWorkLoadData = async (day) => {
  660. const param = { project_id: projectId };
  661. param.code = workConfig.map((item) => item.code).join(',');
  662. param.s_time = dayjs(day).add(-1, 'month').format('YYYY-MM') + '-26';
  663. param.e_time = dayjs(day).format('YYYY-MM') + '-25';
  664. const res = await queryPsrWorkLoad(param);
  665. if (res?.data) {
  666. const data = res?.data; //{ '02-010': [800, 100] };
  667. Object.keys(data).forEach((code) => {
  668. const list = data[code]; //第一个是当月的,第二个是累计的
  669. const fill = workConfig.find((item) => item.code == code)?.fill;
  670. if (list?.length > 0 && fill) {
  671. luckysheetRef.current.setCellValue(fill.r, fill.curC, list[0]);
  672. luckysheetRef.current.setCellValue(fill.r, fill.actC, list[1]);
  673. }
  674. });
  675. console.log('--------------------', res.data);
  676. }
  677. };
  678. const renderTitle = (data_type, name) => {
  679. if (compareValues?.length == 2) {
  680. return (
  681. <div className={styles.exportDiv}>
  682. <Button
  683. type="primary"
  684. onClick={() => {
  685. setCompareValues([]);
  686. setTimeout(() => {
  687. initPsrActrual(key);
  688. }, 500);
  689. }}
  690. >
  691. 退出比对
  692. </Button>
  693. </div>
  694. );
  695. }
  696. let content;
  697. switch (data_type) {
  698. case 0:
  699. //投标版psr
  700. if (user?.Permission['func-psr-export-01'])
  701. content = (
  702. <div className={styles.exportDiv}>
  703. <Button
  704. type="primary"
  705. onClick={() => exportExcl(name)}
  706. disabled={noData}
  707. >
  708. 导出
  709. </Button>
  710. </div>
  711. );
  712. break;
  713. case 3:
  714. //签字版psr
  715. if (user?.Permission['func-psr-export-02'])
  716. content = (
  717. <div className={styles.excelTitle}>
  718. <div style={{ minWidth: '10px' }}>
  719. {/* 当前PSR表单:
  720. <span style={{ color: 'blue' }}>{excelData?.name}</span> */}
  721. </div>
  722. <Space>
  723. <Button
  724. type="primary"
  725. onClick={() => {
  726. run(init_flow_id);
  727. setHistoryOpen(true);
  728. }}
  729. disabled={noData}
  730. >
  731. 历史版本
  732. </Button>
  733. <Button
  734. type="primary"
  735. onClick={() => exportExcl(name)}
  736. disabled={noData}
  737. >
  738. 导出
  739. </Button>
  740. </Space>
  741. </div>
  742. );
  743. break;
  744. default:
  745. let text, canExport, canSaveAs;
  746. if (data_type == 1) {
  747. text = 'PSR';
  748. canExport = user?.Permission['func-psr-export-03'];
  749. canSaveAs = user.Permission['func-psr-saveas-03'];
  750. } else {
  751. text = '现金流';
  752. canExport = user?.Permission['func-psr-export-04'];
  753. canSaveAs = user.Permission['func-actual-saveas-04'];
  754. }
  755. //过程/终版psr 现金流
  756. content = (
  757. <div className={styles.excelTitle}>
  758. <div>
  759. 当前{text}表单:
  760. <span style={{ color: 'blue' }}>{excelData?.name}</span>
  761. </div>
  762. <Space>
  763. <Button
  764. type="primary"
  765. onClick={() => {
  766. setHistoryOpen(true);
  767. }}
  768. disabled={noData}
  769. >
  770. 历史版本
  771. </Button>
  772. {canSaveAs && (
  773. <Button
  774. type="primary"
  775. onClick={() => setOpen(true)}
  776. disabled={!excelData?.is_edit}
  777. >
  778. 另存为
  779. </Button>
  780. )}
  781. <Button
  782. type="primary"
  783. onClick={handlerSave}
  784. loading={saveLoading}
  785. disabled={!excelData?.is_edit || isOriginVer}
  786. >
  787. 保存
  788. </Button>
  789. <Button
  790. type="primary"
  791. onClick={() => setCompareOpen(true)}
  792. disabled={noData}
  793. >
  794. 比对
  795. </Button>
  796. {canExport && (
  797. <Button
  798. type="primary"
  799. onClick={() => exportExcl(excelData?.name)}
  800. disabled={noData}
  801. >
  802. 导出
  803. </Button>
  804. )}
  805. </Space>
  806. </div>
  807. );
  808. }
  809. return content;
  810. };
  811. const renderSheet = (currentData, is_edit = false, day = '') => {
  812. if (!currentData || !currentData[0]?.celldata) {
  813. setNoData(true);
  814. return;
  815. }
  816. console.log('------------currentData------', currentData);
  817. setNoData(false);
  818. if (!luckysheetRef.current) {
  819. setTimeout(() => {
  820. renderSheet(currentData, is_edit, day);
  821. }, 500);
  822. return;
  823. }
  824. const data = currentData;
  825. //设置单元格不可编辑
  826. let isEdit = (key == '3' || key == '4') && is_edit;
  827. const authority = isEdit
  828. ? null
  829. : {
  830. sheet: true,
  831. hintText: '当前excel不可编辑!',
  832. };
  833. data?.forEach((item) => {
  834. // 公式计算
  835. let calcChain = [];
  836. let index = item.index;
  837. item.celldata?.forEach((cell) => {
  838. if (typeof cell.v.f !== 'undefined') {
  839. calcChain.push({
  840. r: cell.r,
  841. c: cell.c,
  842. index,
  843. });
  844. }
  845. });
  846. item.calcChain = calcChain;
  847. //现金流表设置隐藏行
  848. if (item.name == '现金流') item.config.rowhidden = setActHideRow(item);
  849. });
  850. let option = {
  851. lang: 'zh',
  852. showinfobar: false,
  853. showstatisticBar: false,
  854. permissions: user?.Permission,
  855. authority,
  856. data: JSON.parse(JSON.stringify(data)),
  857. hook: {
  858. cellMousedown: (cell, position, sheet) => {
  859. console.log(cell, sheet);
  860. },
  861. cellUpdated: () => {
  862. luckysheetRef.current.refreshFormula();
  863. },
  864. workbookCreateAfter: async () => {
  865. //设置到现金流可编辑的行,修改点击保存提示不能编辑问题
  866. luckysheetRef.current.setRangeShow('A3');
  867. setTimeout(() => {
  868. luckysheetRef.current.refreshFormula();
  869. }, 800);
  870. //当前为为终版psr标签并且可编辑状态时填充人日数据
  871. if (key == '3' && is_edit) {
  872. fillWorkLoadData(day);
  873. }
  874. },
  875. },
  876. };
  877. option.data.forEach((item) => {
  878. delete item.data;
  879. if (item.celldata) {
  880. item.celldata.forEach((cell) => {
  881. // 生成uuid
  882. if (!cell.v.cid) cell.v.cid = getUUID();
  883. });
  884. }
  885. // 默认禁止编辑
  886. // item.config.authority = { sheet: true, hintText };
  887. });
  888. console.log('-----------', data);
  889. //设置不可编辑
  890. if (!is_edit) unableEdit(option);
  891. luckysheetRef.current.destroy();
  892. luckysheetRef.current.create(option);
  893. };
  894. const changeDate = (date) => {
  895. date = dayjs(date);
  896. const startDate = dayjs('1900-01-01');
  897. const daysDifference = date.diff(startDate, 'day');
  898. return daysDifference;
  899. };
  900. const items = useMemo(() => {
  901. const { Permission } = user;
  902. console.log('-00000000000000----------Permission-----', Permission);
  903. const list = [];
  904. if (Permission['func-psr-tab-01'])
  905. list.push({
  906. key: '1',
  907. label: '投标版PSR',
  908. children: renderTitle(0, '投标版PSR'),
  909. });
  910. if (Permission['func-psr-tab-02'])
  911. list.push({
  912. key: '2',
  913. label: '签字版PSR',
  914. children: renderTitle(3, '签字版PSR'),
  915. });
  916. if (Permission['func-psr-tab-03'])
  917. list.push({
  918. key: '3',
  919. label: '过程/终版PSR',
  920. children: renderTitle(1, '过程/终版PSR'),
  921. });
  922. if (Permission['func-psr-tab-04'])
  923. list.push({
  924. key: '4',
  925. label: '现金流',
  926. children: renderTitle(2, '现金流'),
  927. });
  928. if (list.length == 0) {
  929. setNoData(true);
  930. } else if (!key) {
  931. setKey(list[0].key);
  932. }
  933. return list;
  934. }, [user, excelData?.name, compareValues?.length]);
  935. const handlerDetailClick = (id) => {
  936. if (key == '2') {
  937. queryPsrExcel({ gridKey: id });
  938. setHistoryOpen(false);
  939. return;
  940. }
  941. runDetail({ id });
  942. };
  943. console.log('__----------------', historyList);
  944. return (
  945. <PageContent>
  946. <div className={styles.titleDev}>
  947. <Button type="primary" onClick={() => navigate(-1)}>
  948. 返回
  949. </Button>
  950. <span className={styles.title}>{project_name}</span>
  951. </div>
  952. <Tabs
  953. type="card"
  954. items={items}
  955. onChange={(key) => {
  956. setKey(key);
  957. titleRef.current = '';
  958. }}
  959. />
  960. {noData && <div className={styles.noData}>暂无数据</div>}
  961. {compareValues?.length == 2 ? (
  962. <CompareCom values={compareValues} permissions={user?.Permission} />
  963. ) : (
  964. <iframe
  965. style={{
  966. width: '100%',
  967. height: '60vh',
  968. overflowX: 'hidden',
  969. display: noData ? 'none' : 'block',
  970. }}
  971. ref={iframeRef}
  972. onLoad={handlerLoad}
  973. src="/luckysheet.html"
  974. />
  975. )}
  976. <Drawer
  977. title="历史版本"
  978. placement="right"
  979. loading={listLoading}
  980. onClose={() => setHistoryOpen(false)}
  981. open={historyOpen}
  982. >
  983. <Timeline
  984. items={historyList?.map((item) => {
  985. return {
  986. children: (
  987. <a onClick={() => handlerDetailClick(item.id)}>
  988. {/* {titleRef.current} */}
  989. {item.name}
  990. </a>
  991. ),
  992. };
  993. })}
  994. />
  995. </Drawer>
  996. <SaveModal
  997. showType={key == '4'}
  998. loading={saveOtherLoading}
  999. open={open}
  1000. onCancel={() => setOpen(false)}
  1001. onOk={handlerSaveOther}
  1002. />
  1003. <CompareModal
  1004. list={historyList}
  1005. open={compareOpen}
  1006. onOk={(values) => {
  1007. setCompareValues(values);
  1008. setCompareOpen(false);
  1009. }}
  1010. onCancel={() => setCompareOpen(false)}
  1011. />
  1012. </PageContent>
  1013. );
  1014. };
  1015. export default PSRDetail;