detail.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  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. } from '@umijs/max';
  13. import {
  14. queryPsrExcel,
  15. queryPsrMonthDetail,
  16. queryPsrMonthLast,
  17. queryPsrMonthList,
  18. queryPsrWorkLoad,
  19. querySavePsrMonth,
  20. } from '../../services/psr';
  21. import SaveModal from './components/saveOtherModal';
  22. import CompareModal from './components/compareModal';
  23. import CompareCom from './components/compareCom';
  24. import dayjs from 'dayjs';
  25. import { exportExcel, getUUID } from '../../utils/exportExcl';
  26. const PSRDetail = () => {
  27. const navigate = useNavigate();
  28. const params = useParams();
  29. const location = useLocation();
  30. const { id: projectId } = params;
  31. const {
  32. state: { project_name, flow_id, node_id },
  33. } = location;
  34. const [excelData, setExcelData] = useState();
  35. const [historyOpen, setHistoryOpen] = useState();
  36. const [open, setOpen] = useState(false);
  37. const [key, setKey] = useState();
  38. const [compareOpen, setCompareOpen] = useState(false);
  39. const [compareValues, setCompareValues] = useState([]);
  40. const [isOriginVer, setIsOriginVer] = useState(false); //是否原始版本 是的话只能另存不能编辑
  41. const luckysheetRef = useRef();
  42. const iframeRef = useRef();
  43. const unableEdit = (option) => {
  44. option.showtoolbar = false;
  45. option.enableAddRow = false;
  46. option.sheetFormulaBar = false;
  47. option.enableAddBackTop = false;
  48. option.showsheetbarConfig = {
  49. add: false,
  50. sheet: false,
  51. };
  52. option.cellRightClickConfig = {
  53. copy: false, // 复制
  54. copyAs: false, // 复制为
  55. paste: false, // 粘贴
  56. insertRow: false, // 插入行
  57. insertColumn: false, // 插入列
  58. deleteRow: false, // 删除选中行
  59. deleteColumn: false, // 删除选中列
  60. deleteCell: false, // 删除单元格
  61. hideRow: false, // 隐藏选中行和显示选中行
  62. hideColumn: false, // 隐藏选中列和显示选中列
  63. rowHeight: false, // 行高
  64. columnWidth: false, // 列宽
  65. clear: false, // 清除内容
  66. matrix: false, // 矩阵操作选区
  67. sort: false, // 排序选区
  68. filter: false, // 筛选选区
  69. chart: false, // 图表生成
  70. image: false, // 插入图片
  71. link: false, // 插入链接
  72. data: false, // 数据验证
  73. cellFormat: false, // 设置单元格格式
  74. };
  75. };
  76. //请求投标版、签字版psr excel
  77. const { run: runExcel } = useRequest(queryPsrExcel, {
  78. manual: true,
  79. formatResult: (res) => {
  80. if (res) {
  81. const jsonData = JSON.parse(res);
  82. renderSheet(jsonData);
  83. }
  84. },
  85. });
  86. //请求月度psr和现金流列表 data_type 1 psr 2 现金流
  87. const {
  88. data,
  89. run: runList,
  90. loading: listLoading,
  91. } = useRequest(
  92. (data) =>
  93. queryPsrMonthList({
  94. project_id: projectId,
  95. data_type: data_type,
  96. ...data,
  97. }),
  98. { manual: true },
  99. );
  100. //保存/另存为月度psr和现金流接口
  101. const { run: runSave, loading: saveLoading } = useRequest(
  102. (data) => querySavePsrMonth(data),
  103. {
  104. manual: true,
  105. onSuccess: () => {
  106. message.success('保存成功');
  107. if (open) setOpen(false);
  108. },
  109. onError: () => {
  110. message.success('添加失败');
  111. },
  112. },
  113. );
  114. //请求月度psr和现金流详情接口
  115. const { run: runDetail } = useRequest((data) => queryPsrMonthDetail(data), {
  116. manual: true,
  117. formatResult: (res) => {
  118. if (res?.data) {
  119. let data = res.data;
  120. console.log(data);
  121. const day = dayjs(data.day).format('YYYY-MM');
  122. setExcelData({ ...data, dayFormat: day });
  123. setHistoryOpen(false);
  124. const jsonData = JSON.parse(data.json_data);
  125. renderSheet(jsonData, data.is_edit);
  126. }
  127. },
  128. });
  129. const data_type = useMemo(() => {
  130. if (key == '3') return 1;
  131. if (key == '4') return 2;
  132. return null;
  133. }, [key]);
  134. useEffect(() => {
  135. setCompareValues([]);
  136. if (key) {
  137. onChange(key);
  138. } else {
  139. runExcel({ gridKey: node_id });
  140. }
  141. }, [key]);
  142. const onChange = (key) => {
  143. if (key == '1') {
  144. runExcel({ gridKey: node_id });
  145. } else if (key == '2') {
  146. runExcel({ gridKey: flow_id });
  147. } else {
  148. initPsrActrual(key);
  149. }
  150. };
  151. const initPsrActrual = async (key) => {
  152. const data_type = key == '3' ? 1 : 2;
  153. // runList({ data_type });
  154. const res = await queryPsrMonthLast({ project_id: projectId, data_type });
  155. if (res.data?.length > 0 && res.data[0].json_data) {
  156. const day = dayjs(res.data[0].day).format('YYYY-MM');
  157. const isOrigin = day.includes('1970-01') ? 1 : 0;
  158. setIsOriginVer(isOrigin);
  159. setExcelData({ ...res.data[0], dayFormat: day });
  160. const data = JSON.parse(res.data[0].json_data);
  161. console.log(data);
  162. if (data.cell_data) data.celldata = JSON.parse(data.cell_data);
  163. if (data.config) data.config = JSON.parse(data.config);
  164. renderSheet(
  165. Array.isArray(data) ? data : [data],
  166. isOrigin ? 0 : res.data[0].is_edit,
  167. );
  168. }
  169. };
  170. const handlerSaveOther = (date) => {
  171. const luckyData = luckysheetRef.current?.toJson();
  172. if (luckyData?.data) {
  173. const params = {
  174. day: date,
  175. project_id: Number(projectId),
  176. json_data: JSON.stringify(luckyData.data),
  177. data_type: data_type,
  178. };
  179. runSave(params);
  180. }
  181. };
  182. const handlerSave = () => {
  183. const luckyData = luckysheetRef.current?.toJson();
  184. const params = {
  185. id: excelData?.id,
  186. data_type: excelData?.data_type,
  187. project_id: excelData?.project_id,
  188. day: dayjs(excelData?.day).format('YYYY-MM-DD'),
  189. json_data: JSON.stringify(luckyData.data),
  190. };
  191. runSave(params);
  192. };
  193. const exportExcl = (title) => {
  194. const luckyData = luckysheetRef.current?.toJson();
  195. exportExcel(luckyData.data, title);
  196. };
  197. const handlerLoad = () => {
  198. const contentWindow = iframeRef.current.contentWindow;
  199. luckysheetRef.current = contentWindow.luckysheet;
  200. };
  201. const renderSheet = (currentData, is_edit = false) => {
  202. console.log('==================', luckysheetRef.current);
  203. const data = currentData;
  204. //设置单元格不可编辑
  205. data?.forEach((item) => {
  206. item.config.authority = is_edit
  207. ? null
  208. : {
  209. sheet: true,
  210. hintText: '当前excel不可编辑!',
  211. };
  212. });
  213. let option = {
  214. lang: 'zh',
  215. showinfobar: false,
  216. showstatisticBar: false,
  217. data: JSON.parse(JSON.stringify(data)),
  218. hook: {
  219. cellMousedown: (cell, position, sheet) => {
  220. console.log(cell, sheet);
  221. },
  222. cellUpdated: () => {
  223. luckysheetRef.current.refreshFormula();
  224. },
  225. workbookCreateAfter: async () => {
  226. //当前为为终版psr标签并且可编辑状态时填充人日数据
  227. if (key == '3' && is_edit) {
  228. const res = await queryPsrWorkLoad({ project_id: projectId });
  229. if (res.data) {
  230. luckysheetRef.current.setCellValue(8, 4, res.data.Total);
  231. luckysheetRef.current.setCellValue(8, 8, res.data.Month);
  232. }
  233. }
  234. },
  235. },
  236. };
  237. option.data.forEach((item) => {
  238. delete item.data;
  239. delete item.cell_data;
  240. if (item.celldata) {
  241. item.celldata.forEach((cell) => {
  242. // 生成uuid
  243. if (!cell.v.cid) cell.v.cid = getUUID();
  244. });
  245. }
  246. // 默认禁止编辑
  247. // item.config.authority = { sheet: true, hintText };
  248. });
  249. console.log(option.data);
  250. //设置不可编辑
  251. if (!is_edit) unableEdit(option);
  252. luckysheetRef.current.destroy();
  253. luckysheetRef.current.create(option);
  254. };
  255. const renderTitle = (data_type, title) => {
  256. if (compareValues?.length == 2) {
  257. return (
  258. <div className={styles.exportDiv}>
  259. <Button
  260. type="primary"
  261. onClick={() => {
  262. setCompareValues([]);
  263. setTimeout(() => {
  264. initPsrActrual(key);
  265. }, 500);
  266. }}
  267. >
  268. 退出比对
  269. </Button>
  270. </div>
  271. );
  272. }
  273. if (data_type == 0)
  274. return (
  275. <div className={styles.exportDiv}>
  276. <Button type="primary" onClick={() => exportExcl(title)}>
  277. 导出
  278. </Button>
  279. </div>
  280. );
  281. return (
  282. <div className={styles.excelTitle}>
  283. <div>
  284. 当前PSR表单:
  285. <span style={{ color: 'blue' }}>{excelData?.dayFormat}</span>
  286. </div>
  287. <Space>
  288. <Button
  289. type="primary"
  290. onClick={() => {
  291. runList();
  292. setHistoryOpen(true);
  293. }}
  294. >
  295. {`${title}历史版本`}
  296. </Button>
  297. <Button
  298. type="primary"
  299. onClick={() => setOpen(true)}
  300. disabled={!excelData?.is_edit}
  301. >
  302. 另存为
  303. </Button>
  304. <Button
  305. type="primary"
  306. onClick={handlerSave}
  307. disabled={!excelData?.is_edit || isOriginVer}
  308. >
  309. 保存
  310. </Button>
  311. <Button type="primary" onClick={() => setCompareOpen(true)}>
  312. 比对
  313. </Button>
  314. <Button type="primary" onClick={() => exportExcl(title)}>
  315. 导出
  316. </Button>
  317. </Space>
  318. </div>
  319. );
  320. };
  321. const items = [
  322. {
  323. key: '1',
  324. label: '投标版PSR',
  325. children: renderTitle(0, '投标版PSR'),
  326. },
  327. {
  328. key: '2',
  329. label: '签字版PSR',
  330. children: renderTitle(0, '签字版PSR'),
  331. },
  332. {
  333. key: '3',
  334. label: '终版PSR',
  335. children: renderTitle(1, '终版PSR'),
  336. },
  337. {
  338. key: '4',
  339. label: '现金流',
  340. children: renderTitle(2, '现金流'),
  341. },
  342. ];
  343. return (
  344. <PageContent>
  345. <div className={styles.titleDev}>
  346. <Button type="primary" onClick={() => navigate(-1)}>
  347. 返回
  348. </Button>
  349. <span className={styles.title}>{project_name}</span>
  350. </div>
  351. <Tabs defaultActiveKey="1" type="card" items={items} onChange={setKey} />
  352. {compareValues?.length == 2 ? (
  353. <CompareCom values={compareValues} />
  354. ) : (
  355. <iframe
  356. style={{
  357. width: '100%',
  358. height: '80vh',
  359. }}
  360. ref={iframeRef}
  361. onLoad={handlerLoad}
  362. src="/luckysheet.html"
  363. />
  364. )}
  365. <Drawer
  366. title="历史版本"
  367. placement="right"
  368. loading={listLoading}
  369. onClose={() => setHistoryOpen(false)}
  370. open={historyOpen}
  371. >
  372. <Timeline
  373. items={data?.list?.map((item) => {
  374. return {
  375. children: (
  376. <a onClick={() => runDetail({ id: item.id })}>
  377. {dayjs(item.day).format('YYYY-MM')}
  378. </a>
  379. ),
  380. };
  381. })}
  382. />
  383. </Drawer>
  384. <SaveModal
  385. loading={saveLoading}
  386. open={open}
  387. onCancel={() => setOpen(false)}
  388. onOk={handlerSaveOther}
  389. />
  390. <CompareModal
  391. list={data?.list}
  392. open={compareOpen}
  393. onOk={(values) => {
  394. setCompareValues(values);
  395. setCompareOpen(false);
  396. }}
  397. onCancel={() => setCompareOpen(false)}
  398. />
  399. </PageContent>
  400. );
  401. };
  402. export default PSRDetail;