Modal.jsx 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175
  1. import {
  2. Form,
  3. Modal,
  4. Row,
  5. Col,
  6. Input,
  7. DatePicker,
  8. Icon,
  9. Button,
  10. Divider,
  11. Steps,
  12. Select,
  13. TreeSelect,
  14. InputNumber,
  15. Upload,
  16. Space,
  17. Radio,
  18. message,
  19. } from 'antd';
  20. import ModuleTitle from '../../../components/ModuleTitle/moduleTitle';
  21. import { useEffect, useMemo, useState } from 'react';
  22. import {
  23. queryAuditByCode,
  24. queryCompany,
  25. queryContractCode,
  26. queryOAReCall,
  27. querySupplierList,
  28. } from '@/services/contract';
  29. import { queryDepsV2 } from '@/services/approval';
  30. import { useModel, useRequest } from '@umijs/max';
  31. import { CloudUploadOutlined } from '@ant-design/icons';
  32. import styles from '../index.less';
  33. import dayjs from 'dayjs';
  34. import { advanceSubmitNextNode, audit } from '@/services/boom';
  35. import AuditSteps from './AuditSteps';
  36. import FileViewerModal from '@/components/FileViewerNew';
  37. export const Type = {
  38. add: 0, //新增
  39. detail: 1, //详情
  40. cancel: 2, //作废
  41. save: 3, //保存草稿
  42. };
  43. export const StatusText = [
  44. '',
  45. '待审核',
  46. '审核拒绝',
  47. '已存档',
  48. '作废待审核',
  49. '作废拒绝',
  50. '已作废',
  51. ];
  52. export const Status = {
  53. ReCall: -1,
  54. None: 0,
  55. Checking: 1,
  56. CheckReject: 2,
  57. CheckSuccess: 3,
  58. CalChecking: 4,
  59. CalCheckReject: 5,
  60. CalCheckSuccess: 6,
  61. };
  62. const ContractModal = (props) => {
  63. const [form] = Form.useForm();
  64. const { initialState } = useModel('@@initialState');
  65. const user = initialState?.user || {};
  66. const { userList, run: userListRun } = useModel('userList');
  67. const { depList, run: depListRun } = useModel('depList');
  68. const [auditList, setAuditList] = useState([]);
  69. const [fileViewerVisible, setFileViewerVisible] = useState(false);
  70. const [fileViewerData, setFileViewerData] = useState();
  71. const FORMAT = 'YYYY-MM-DD';
  72. const {
  73. detail: data,
  74. type,
  75. visible,
  76. projectList = [],
  77. handleOk,
  78. handleCancel,
  79. parent_id,
  80. handlerReCall,
  81. } = props;
  82. const title =
  83. type == Type.add ? '新增' : type == Type.cancel ? '作废' : '详情';
  84. const archivesOptions = [
  85. {
  86. Name: '财务部',
  87. ID: '财务部',
  88. },
  89. {
  90. Name: '行政部',
  91. ID: '行政部',
  92. },
  93. ];
  94. const [companyDepList, setCompanyDepList] = useState(depList || []);
  95. const [archivesDepList, setArchivesDepList] = useState(archivesOptions);
  96. const [dealDisable, setDealDisable] = useState(false);
  97. const [attachData, setAttachData] = useState({
  98. attach: [],
  99. attach_extend: [],
  100. });
  101. const company = Form.useWatch('company_id', form);
  102. const project_name = Form.useWatch('project_name', form);
  103. const archives_dep = Form.useWatch('archives_dep', form);
  104. // 当为审核拒绝状态时,点击编辑按钮可以时为强制修改状态
  105. const [forceModify, setForceModify] = useState(false);
  106. //是否补充协议,是的话需要填合同编号
  107. const is_supplement = Form.useWatch('is_supplement', form);
  108. //请求合同编号用
  109. const dep_id = Form.useWatch('dep_id', form);
  110. const parent_code = Form.useWatch('parent_code', form);
  111. //审批流拼接
  112. const formData = [
  113. {
  114. name: '是否本部',
  115. id: 'DDSelectField_4ad8bda8-60ce-428b-88a3-bf1a18c24a50',
  116. type: 'DDSelectField',
  117. value: ['是'],
  118. },
  119. {
  120. name: '合同归档部门',
  121. id: 'DDSelectField_3b661423-9fb8-4498-9eda-bcadf2d98473',
  122. type: 'DDSelectField',
  123. value: ['财务部'],
  124. },
  125. {
  126. name: '合同编码',
  127. id: 'TextField_f73531d8-c2c0-4769-a8ef-68b2eae2dc3a',
  128. type: 'TextField',
  129. value: ['1'],
  130. },
  131. {
  132. name: '提审类型',
  133. id: 'DDSelectField_bed77d5f-d02c-4f1d-98bf-0638245a3331',
  134. type: 'DDSelectField',
  135. value: ['1'],
  136. },
  137. ];
  138. //计算审批流数据
  139. const advance = {
  140. flow_id: 47,
  141. form_list: null,
  142. formComponentValues: '',
  143. };
  144. //旧审批流兼容
  145. const oldAuditList = {
  146. OaAuditList: [
  147. {
  148. id: 14,
  149. auditor: 7,
  150. AuditorUser: {
  151. UserName: 'admin',
  152. CName: '管理员',
  153. IsSuper: true,
  154. ID: 7,
  155. },
  156. seq: 1,
  157. oa_id: 7,
  158. seq_name: '审批1',
  159. },
  160. ],
  161. audit_status: 3,
  162. current_seq: 1,
  163. };
  164. const { data: companyData, run: runCompany } = useRequest(queryCompany);
  165. // 新建合同时,选择本部时,需要用另一个接口请求部门数据
  166. const { data: companyDeps, run: runCompanyDeps } = useRequest(queryDepsV2, {
  167. manual: true,
  168. formatResult: (response) => {
  169. console.log(response.data);
  170. return response.data;
  171. },
  172. });
  173. //填写表单时计算审批流接口
  174. const { run: runAuditList } = useRequest(
  175. (data) => advanceSubmitNextNode(data),
  176. {
  177. debounceInterval: 500,
  178. manual: true,
  179. formatResult(res) {
  180. const list = res.data[0]?.map((item) => {
  181. const name = userList?.find(
  182. (user) => user.ID == item[0].value,
  183. )?.CName;
  184. return { ...item[0], name };
  185. });
  186. setAuditList(
  187. res.data[0]?.map((item) => {
  188. const name = userList?.find(
  189. (user) => user.ID == item[0].value,
  190. )?.CName;
  191. return { ...item[0], name };
  192. }),
  193. );
  194. },
  195. },
  196. );
  197. //计算合同编号接口
  198. const { run: runCode } = useRequest((data) => queryContractCode(data), {
  199. manual: true,
  200. onSuccess: (data) => {
  201. form.setFieldsValue({
  202. code: data?.code,
  203. });
  204. },
  205. });
  206. //供应商列表
  207. const { data: supplierList = [], loading } = useRequest(querySupplierList, {
  208. defaultParams: [
  209. {
  210. project_id: 1,
  211. is_super: user?.IsSuper,
  212. created_by: user?.CName,
  213. page_size: 99999,
  214. },
  215. ],
  216. formatResult: (res) => {
  217. return res?.data?.list
  218. ? res?.data.list.map((item) => {
  219. return { ...item, Name: item.name };
  220. })
  221. : [];
  222. },
  223. });
  224. //获取OA 归档审批列表
  225. const { data: auditData, run: runAudit } = useRequest(
  226. (data) => queryAuditByCode({ ...data, extend_type: 0 }),
  227. {
  228. manual: true,
  229. formatResult: (res) => {
  230. if (res?.data) {
  231. return res.data;
  232. } else {
  233. if (data?.status == Status.CheckReject) {
  234. return { ...oldAuditList, audit_status: 2 };
  235. }
  236. return oldAuditList;
  237. }
  238. },
  239. },
  240. );
  241. //获取OA 作废审批列表
  242. const { data: auditCelData, run: runCalAudit } = useRequest(
  243. (data) => queryAuditByCode({ ...data, extend_type: 1 }),
  244. {
  245. manual: true,
  246. formatResult: (res) => {
  247. if (res?.data) {
  248. return res.data;
  249. } else {
  250. if (data?.status == Status.CalCheckReject) {
  251. return { ...oldAuditList, audit_status: 2 };
  252. }
  253. return oldAuditList;
  254. }
  255. },
  256. },
  257. );
  258. useEffect(() => {
  259. if (!visible) {
  260. setDealDisable(false);
  261. setAuditList([]);
  262. setCompanyDepList([]);
  263. setArchivesDepList([]);
  264. } else {
  265. userListRun();
  266. depListRun();
  267. runCompany();
  268. runCompanyDeps();
  269. }
  270. }, [visible]);
  271. useEffect(() => {
  272. //兼容之前选择的所属部门,用的现在的接口匹配不到部门显示数字的问题
  273. if (data?.company_id) {
  274. const deps = getDepItemById(data?.company_id)?.children;
  275. setCompanyDepList(deps);
  276. }
  277. }, [data, depList]);
  278. useEffect(() => {
  279. form.resetFields();
  280. if (data?.status >= Status.Checking) runAudit({ extend_code: data.code });
  281. if (data?.status >= Status.CalChecking)
  282. runCalAudit({ extend_code: data.code });
  283. let result = { attach: [], attach_extend: [] };
  284. if (data?.attach) {
  285. let att = JSON.parse(data.attach);
  286. result.attach = att.map((item, idx) => {
  287. return { ...item, uid: idx, status: 'done' };
  288. });
  289. }
  290. if (data?.attach_extend) {
  291. let att = JSON.parse(data.attach_extend);
  292. result.attach_extend = att.map((item, idx) => {
  293. return { ...item, uid: idx, status: 'done' };
  294. });
  295. }
  296. setAttachData(result);
  297. }, [data]);
  298. const isSuper = useMemo(() => {
  299. if (
  300. type == Type.add ||
  301. type == Type.cancel ||
  302. data?.status == Status.ReCall ||
  303. (data?.status == Status.CheckReject && forceModify)
  304. )
  305. return true;
  306. }, [data, type, forceModify]);
  307. useEffect(() => {
  308. if (
  309. type !== Type.add &&
  310. data?.status !== Status.ReCall &&
  311. data?.status !== Status.CheckReject
  312. )
  313. return;
  314. const newCompony = company || data?.company_id; //recall状态时compony是空, 需要用data?.company_id
  315. if (!newCompony) {
  316. setCompanyDepList([]);
  317. setArchivesDepList([]);
  318. return;
  319. }
  320. const deps = getDepItemById(newCompony)?.children;
  321. deps ? setCompanyDepList(deps) : setCompanyDepList([]);
  322. const item = companyData?.find((item) => item.ID == newCompony);
  323. if (item?.Flag == 1) {
  324. //公司为本部 经办人为自己并不可编辑 合同存档部门从财务和行政部选
  325. setDealDisable(false);
  326. setArchivesDepList(archivesOptions);
  327. form.setFieldsValue({ deal_by: user?.CName });
  328. // 公司为本部时,使用另一个接口获取部门数据
  329. companyDeps ? setCompanyDepList(companyDeps) : setCompanyDepList([]);
  330. } else {
  331. //公司为分子公司 经办人为手动输入 合同存档部门从所选分子公司的子部门选择
  332. setDealDisable(true);
  333. setArchivesDepList(deps);
  334. form.setFieldsValue({ deal_by: '' });
  335. }
  336. }, [company, data, forceModify]);
  337. //获取合同编号逻辑 只有新增才请求
  338. useEffect(() => {
  339. if (type !== Type.add || !company || !dep_id) return;
  340. const item = companyData?.find((item) => item.ID == company);
  341. const dep_code = getDepItemById(dep_id)?.Code;
  342. if (item) {
  343. let params = {
  344. company_id: item.ID,
  345. company_code: item.Code,
  346. dep_code,
  347. parent_code,
  348. };
  349. runCode(params);
  350. }
  351. }, [dep_id, parent_code]);
  352. //获取审批流逻辑
  353. useEffect(() => {
  354. if (
  355. type !== Type.add &&
  356. data?.status !== Status.ReCall &&
  357. data?.status !== Status.CheckReject
  358. )
  359. return;
  360. const param = { ...advance };
  361. let formValues = [];
  362. const item = companyData?.find((item) => item.ID == company);
  363. formValues.push({
  364. ...formData[0],
  365. value: item?.Flag == 1 ? ['是'] : ['否'],
  366. });
  367. if (archives_dep)
  368. formValues.push({ ...formData[1], value: [archives_dep] });
  369. param.formComponentValues = formValues;
  370. runAuditList(param);
  371. }, [company, archives_dep]);
  372. //根据项目名称填充项目编号逻辑
  373. useEffect(() => {
  374. if (
  375. type !== Type.add &&
  376. data?.status !== Status.ReCall &&
  377. data?.status !== Status.CheckReject
  378. )
  379. return;
  380. const project_code = projectList?.find(
  381. (item) => item.project_name == project_name,
  382. )?.project_full_code;
  383. if (project_code) {
  384. form.setFieldsValue({ project_code });
  385. } else {
  386. form.setFieldsValue({ project_code: '' });
  387. }
  388. }, [project_name]);
  389. const supplyList = useMemo(() => {
  390. return companyData ? [...companyData, ...supplierList] : supplierList;
  391. }, [companyData, supplierList]);
  392. const disableds = useMemo(() => {
  393. // 当合同处于审核拒绝状态时,通过修改按钮可强制修改合同并重新进入审核
  394. if (forceModify && data?.status == Status.CheckReject) {
  395. return { contract: false, recall: false };
  396. }
  397. // if (data?.status == Status.ReCall) {
  398. // return { contract: false, recall: true };
  399. // }
  400. if (data?.status > Status.None) {
  401. return { contract: true, recall: true };
  402. }
  403. return { contract: false, recall: false };
  404. }, [visible, forceModify]);
  405. const UploadProps = {
  406. action: `/api/contract/v1/attach`,
  407. headers: {
  408. 'JWT-TOKEN': localStorage.getItem('JWT-TOKEN'),
  409. },
  410. defaultFileList: attachData?.attach,
  411. onChange({ file, fileList }) {
  412. if (file.status !== 'uploading') {
  413. const list = fileList.map((item) => item.response?.data?.attach);
  414. form.setFieldsValue({ attach: list });
  415. }
  416. },
  417. };
  418. const UploadPropsExtend = {
  419. action: `/api/contract/v1/attach`,
  420. headers: {
  421. 'JWT-TOKEN': localStorage.getItem('JWT-TOKEN'),
  422. },
  423. defaultFileList: attachData?.attach_extend,
  424. onChange({ file, fileList }) {
  425. if (file.status !== 'uploading') {
  426. const list = fileList.map((item) => item.response?.data?.attach);
  427. form.setFieldsValue({ attach_extend: list });
  428. }
  429. },
  430. };
  431. //获取提交审批流所需form字段
  432. const getAuditData = (values, type) => {
  433. // 合同类型type "1" 归档 “2”作废
  434. const flag =
  435. companyData?.find((item) => item.ID == values.company)?.Flag == 1
  436. ? '是'
  437. : '否';
  438. const newValues = [[flag], [values.archives_dep], [values.code], [type]];
  439. const form = formData.map((item, index) => {
  440. return { ...item, value: newValues[index] };
  441. });
  442. return form;
  443. };
  444. const handleSubmit = () => {
  445. form.validateFields().then((values) => {
  446. if (type == Type.add) {
  447. const form = getAuditData(values, '1');
  448. const audit_list = auditList.map((item) => item.value);
  449. values.effect_on = dayjs(values.effect_on).format(FORMAT);
  450. values.created_on = values.created_on || dayjs().format(FORMAT);
  451. if (parent_id) values.parent_id = parent_id;
  452. if (values.amount || values.amount == 0)
  453. values.amount = values.amount + '';
  454. if (values.attach) values.attach = JSON.stringify(values.attach);
  455. if (values.attach_extend)
  456. values.attach_extend = JSON.stringify(values.attach_extend);
  457. values.party_c = values.party_c?.join(',');
  458. const companyItem = companyData?.find(
  459. (item) => item.ID == values.company_id,
  460. );
  461. values.company_name = companyItem.Name;
  462. values.company_code = companyItem.Code;
  463. const depItem = getDepItemById(values.dep_id);
  464. values.dep_name = depItem?.Name;
  465. values.dep_code = depItem?.Code;
  466. values.created_by = user?.ID;
  467. handleOk(values, Type.add, form, audit_list);
  468. } else if (type == Type.cancel) {
  469. const form = getAuditData(values, '2');
  470. const audit_list = auditData?.OaAuditList?.map((item) => item?.auditor);
  471. let result = {
  472. id: data?.id,
  473. cancel_desc: values.cancel_desc,
  474. code: data?.code,
  475. };
  476. handleOk(result, Type.cancel, form, audit_list);
  477. } else if (
  478. data?.status == Status.ReCall ||
  479. data?.status == Status.CheckReject
  480. ) {
  481. const form = getAuditData(values, '1');
  482. const audit_list = auditList.map((item) => item.value);
  483. values.effect_on = dayjs(values.effect_on).format(FORMAT);
  484. values.created_on = values.created_on || dayjs().format(FORMAT);
  485. if (values.amount || values.amount == 0)
  486. values.amount = values.amount + '';
  487. if (values.attach) values.attach = JSON.stringify(values.attach);
  488. if (values.attach_extend)
  489. values.attach_extend = JSON.stringify(values.attach_extend);
  490. values.party_c = values.party_c?.join(',');
  491. const companyItem = companyData?.find(
  492. (item) => item.ID == values.company_id,
  493. );
  494. values.company_name = companyItem.Name;
  495. values.company_code = companyItem.Code;
  496. const depItem = getDepItemById(values.dep_id);
  497. values.dep_name = depItem?.Name;
  498. values.dep_code = depItem?.Code;
  499. values.created_by = user?.ID;
  500. values.id = data?.id;
  501. handleOk(values, Type.add, form, audit_list);
  502. }
  503. });
  504. };
  505. const handleSaveDraft = () => {
  506. let values = form.getFieldsValue();
  507. if (!values.name) {
  508. message.error('请填写合同名称!');
  509. return;
  510. }
  511. Object.keys(values).forEach((key) => {
  512. if (Array.isArray(values[key]))
  513. values[key].length == 0
  514. ? delete values[key]
  515. : (values[key] = JSON.stringify(values[key]));
  516. });
  517. if (values.effect_on)
  518. values.effect_on = dayjs(values.effect_on).format(FORMAT);
  519. const params = {
  520. name: values.name,
  521. content: JSON.stringify(values),
  522. };
  523. if (data?.id) params.id = data?.id;
  524. handleOk(params, Type.save);
  525. };
  526. const getDepItemById = (id) => {
  527. const fun = (list) => {
  528. for (let i = 0; i < list.length; i++) {
  529. let item = list[i];
  530. if (item.ID == id) {
  531. return item;
  532. } else if (item.children?.length > 0) {
  533. let res = fun(item.children);
  534. if (res) return res;
  535. }
  536. }
  537. };
  538. return fun(depList);
  539. };
  540. const handlePreViewSingle = (data) => {
  541. if (!data) return;
  542. const arr = data.name.split('.');
  543. const type = arr[arr.length - 1];
  544. const dataItem = { url: data.url, name: data.name, type };
  545. setFileViewerData(dataItem);
  546. setFileViewerVisible(true);
  547. };
  548. const renderFooter = () => {
  549. return (
  550. <Space>
  551. {data?.status == Status.Checking && (
  552. <Button onClick={() => handlerReCall(auditData?.id)}>撤回</Button>
  553. )}
  554. <Button
  555. onClick={() => {
  556. setForceModify(false);
  557. form.resetFields();
  558. handleCancel();
  559. }}
  560. >
  561. 取消
  562. </Button>
  563. {data?.status == Status.CheckReject && !forceModify && (
  564. <Button
  565. onClick={() => {
  566. setForceModify(true);
  567. }}
  568. >
  569. 修改
  570. </Button>
  571. )}
  572. {type == Type.add && (
  573. <Button type="primary" onClick={handleSaveDraft}>
  574. 保存草稿
  575. </Button>
  576. )}
  577. <Button type="primary" onClick={handleSubmit} disabled={!isSuper}>
  578. 提交
  579. </Button>
  580. </Space>
  581. );
  582. };
  583. return (
  584. <>
  585. <Modal
  586. width={'85%'}
  587. title={title}
  588. open={visible}
  589. footer={renderFooter()}
  590. onCancel={handleCancel}
  591. destroyOnClose
  592. >
  593. <Divider />
  594. <Form
  595. form={form}
  596. // initialValues={data}
  597. labelCol={{ span: 7 }}
  598. wrapperCol={{ span: 17 }}
  599. >
  600. <ModuleTitle title="存档人信息" />
  601. <Row>
  602. <Col span={10} offset={1}>
  603. <Form.Item
  604. name="created_name"
  605. initialValue={data?.created_name || user?.CName}
  606. label="存档人:"
  607. >
  608. <Input disabled />
  609. </Form.Item>
  610. <Form.Item
  611. name="company_id"
  612. label="所属公司:"
  613. tooltip="请选择该存档合同所属公司"
  614. initialValue={
  615. //不可编辑的时候直接赋值为company_name
  616. !disableds.contract ? data?.company_id : data?.company_name
  617. }
  618. rules={[
  619. {
  620. required: true,
  621. message: '请填写所属公司',
  622. },
  623. ]}
  624. >
  625. <Select
  626. showSearch
  627. style={{ width: '100%' }}
  628. placeholder="请选择"
  629. disabled={disableds.contract}
  630. filterOption={(input, option) =>
  631. (option?.label ?? '')
  632. .toLowerCase()
  633. .includes(input.toLowerCase())
  634. }
  635. options={companyData?.map((item) => {
  636. return {
  637. value: item.ID,
  638. label: item.Name,
  639. };
  640. })}
  641. />
  642. </Form.Item>
  643. </Col>
  644. <Col span={10}>
  645. <Form.Item
  646. name="created_on"
  647. initialValue={data?.created_on || dayjs().format(FORMAT)}
  648. label="存档时间:"
  649. >
  650. <Input disabled />
  651. </Form.Item>
  652. <Form.Item
  653. name="dep_id"
  654. label="所属部门:"
  655. initialValue={data?.dep_id}
  656. rules={[
  657. {
  658. required: true,
  659. message: '请选择所属部门',
  660. },
  661. ]}
  662. >
  663. <TreeSelect
  664. style={{ width: '100%' }}
  665. placeholder="请选择"
  666. showSearch
  667. allowClear
  668. fieldNames={{
  669. label: 'Name',
  670. value: 'ID',
  671. children: 'children',
  672. }}
  673. disabled={disableds.contract}
  674. dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
  675. treeData={
  676. data?.dep_id
  677. ? [
  678. ...companyDepList,
  679. { Name: data.dep_name, ID: data?.dep_id },
  680. ]
  681. : companyDepList
  682. }
  683. />
  684. </Form.Item>
  685. </Col>
  686. </Row>
  687. <ModuleTitle title="经办人信息" />
  688. <Row>
  689. <Col span={10} offset={1}>
  690. <Form.Item
  691. name="deal_by"
  692. label="经办人:"
  693. tooltip="经办人应负责合同审批流程、签字盖章、合同原件存档和电子档案存档。母公司的经办人为OA审批提交人,也是存档人。子公司经办人由子公司合同专员填写,一般是合同审批时的提交人或者是合同实际执行的负责人"
  694. initialValue={data?.deal_by}
  695. rules={[
  696. {
  697. required: true,
  698. message: '请选择经办人',
  699. },
  700. ]}
  701. >
  702. <Input disabled={!dealDisable} />
  703. </Form.Item>
  704. </Col>
  705. <Col span={10}>
  706. <Form.Item
  707. name="created_dep"
  708. label="签约承办部门:"
  709. tooltip="请选择该存档合同的实际履行部门,一般为经办人所在部门"
  710. initialValue={data?.created_dep}
  711. rules={[
  712. {
  713. required: true,
  714. message: '请选择签约承办部门',
  715. },
  716. ]}
  717. >
  718. <TreeSelect
  719. style={{ width: '100%' }}
  720. placeholder="请选择"
  721. showSearch
  722. allowClear
  723. disabled={disableds.contract}
  724. fieldNames={{
  725. label: 'Name',
  726. value: 'Name',
  727. children: 'children',
  728. }}
  729. dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
  730. treeData={companyDepList}
  731. />
  732. </Form.Item>
  733. </Col>
  734. </Row>
  735. <ModuleTitle title="合同信息" />
  736. <Row>
  737. <Col span={10} offset={1}>
  738. <Form.Item
  739. name="is_supplement"
  740. label="是否补充协议:"
  741. tooltip="合同名称"
  742. initialValue={0}
  743. rules={[
  744. {
  745. required: true,
  746. message: '请填写合同名称',
  747. },
  748. ]}
  749. >
  750. <Radio.Group disabled={disableds.contract}>
  751. <Radio value={1}>是</Radio>
  752. <Radio value={0}>否</Radio>
  753. </Radio.Group>
  754. </Form.Item>
  755. <Form.Item
  756. name="name"
  757. label="合同名称:"
  758. tooltip="请与OA审批时填写的合同名称一致"
  759. initialValue={data?.name}
  760. rules={[
  761. {
  762. required: true,
  763. message: '请填写合同名称',
  764. },
  765. ]}
  766. >
  767. <Input disabled={disableds.contract} />
  768. </Form.Item>
  769. <Form.Item
  770. name="effect_on"
  771. label="合同签订日期:"
  772. initialValue={
  773. data?.effect_on ? dayjs(data?.effect_on, FORMAT) : ''
  774. }
  775. tooltip="合同主体各方签字盖章完成之日,以最后签字盖章的为准"
  776. rules={[
  777. {
  778. required: true,
  779. message: '请填写合同名称',
  780. },
  781. ]}
  782. >
  783. <DatePicker
  784. style={{ width: '100%' }}
  785. disabled={disableds.contract}
  786. />
  787. </Form.Item>
  788. <Form.Item
  789. name="project_name"
  790. label="项目名称:"
  791. tooltip="不涉及项目请选“日常项目”"
  792. initialValue={data?.project_name}
  793. rules={[
  794. {
  795. required: true,
  796. message: '请填写项目名称',
  797. },
  798. ]}
  799. >
  800. <Select
  801. style={{ width: '100%' }}
  802. placeholder="请选择"
  803. showSearch
  804. options={projectList?.map((item) => {
  805. return {
  806. value: item.project_name,
  807. label: item.project_name,
  808. };
  809. })}
  810. disabled={disableds.contract}
  811. />
  812. </Form.Item>
  813. <Form.Item
  814. name="party_a"
  815. label="甲方:"
  816. tooltip="合同主体可以下拉选择,可选项需要经办人在“主页--供应商管理”中创建。经办人可以维护和更新供应商信息。"
  817. initialValue={data?.party_a}
  818. rules={[
  819. {
  820. required: true,
  821. message: '请选择甲方',
  822. },
  823. ]}
  824. >
  825. <Select
  826. style={{ width: '100%' }}
  827. placeholder="请选择"
  828. showSearch
  829. allowClear
  830. options={supplyList?.map((item) => {
  831. return {
  832. label: item.Name,
  833. value: item.Name,
  834. };
  835. })}
  836. disabled={disableds.contract}
  837. />
  838. </Form.Item>
  839. </Col>
  840. <Col span={10}>
  841. <Form.Item
  842. style={{ opacity: is_supplement ? 1 : 0 }}
  843. name="parent_code"
  844. tooltip="请先查询原合同编号,原合同未录入本系统的,需先录入存档。"
  845. initialValue={data?.parent_code}
  846. label="原合同编号:"
  847. rules={
  848. is_supplement
  849. ? [
  850. {
  851. required: true,
  852. message: '请填写原合同编号',
  853. },
  854. ]
  855. : []
  856. }
  857. >
  858. <Input placeholder="请填写" disabled={disableds.contract} />
  859. </Form.Item>
  860. <Form.Item
  861. name="code"
  862. tooltip="合同编号按《合同管理办法》的合同编码规则编号。"
  863. initialValue={data?.code}
  864. label="合同编号:"
  865. >
  866. <Input placeholder="提交后自动生成" disabled />
  867. </Form.Item>
  868. <Form.Item
  869. label="合同总价款:"
  870. name="amount"
  871. tooltip="请与OA审批时填写的“合同金额”一致。不涉及金额填“0”"
  872. initialValue={data?.amount}
  873. rules={[
  874. {
  875. required: true,
  876. message: '请输入合同总价款',
  877. },
  878. ]}
  879. >
  880. <InputNumber
  881. style={{ width: '100%' }}
  882. precision={2}
  883. addonAfter="万元"
  884. disabled={disableds.contract}
  885. />
  886. </Form.Item>
  887. <Form.Item
  888. name="project_code"
  889. initialValue={data?.project_code}
  890. label="项目编号:"
  891. >
  892. <Input disabled />
  893. </Form.Item>
  894. <Form.Item
  895. name="party_b"
  896. label="乙方:"
  897. tooltip="合同主体可以下拉选择,可选项需要经办人在“主页--供应商管理”中创建。经办人可以维护和更新供应商信息。"
  898. initialValue={data?.party_b}
  899. rules={[
  900. {
  901. required: true,
  902. message: '请选择乙方',
  903. },
  904. ]}
  905. >
  906. <Select
  907. style={{ width: '100%' }}
  908. placeholder="请选择"
  909. showSearch
  910. allowClear
  911. options={supplyList?.map((item) => {
  912. return {
  913. label: item.Name,
  914. value: item.Name,
  915. };
  916. })}
  917. disabled={disableds.contract}
  918. />
  919. </Form.Item>
  920. </Col>
  921. </Row>
  922. <Form.Item
  923. name="party_c"
  924. label="丙方(及其他):"
  925. tooltip="可多选。合同主体可以下拉选择,可选项需要经办人在“主页--供应商管理”中创建。经办人可以维护和更新供应商信息。"
  926. initialValue={data?.party_c ? data?.party_c?.split(',') : []}
  927. labelCol={{ span: 4 }}
  928. >
  929. <Select
  930. style={{ width: '100%' }}
  931. placeholder="请选择"
  932. mode="multiple"
  933. showSearch
  934. allowClear
  935. options={supplyList?.map((item) => {
  936. return {
  937. label: item.Name,
  938. value: item.Name,
  939. };
  940. })}
  941. disabled={disableds.contract}
  942. />
  943. </Form.Item>
  944. <Form.Item
  945. name="perform"
  946. initialValue={data?.perform}
  947. label="合同履行情况:"
  948. labelCol={{ span: 4 }}
  949. >
  950. <Input.TextArea disabled={disableds.contract} />
  951. </Form.Item>
  952. <Row>
  953. <Col span={10} offset={1}>
  954. <Form.Item
  955. label="合同及合同附件上传:"
  956. tooltip="请上传合同正式盖章文本的扫描件(含技术协议、质保承诺等附件),不得用照片、图片格式,不得遗漏附件"
  957. name="attach"
  958. rules={
  959. disableds.contract
  960. ? []
  961. : [
  962. {
  963. required: true,
  964. message: '请上传合同及合同相关附件',
  965. },
  966. ]
  967. }
  968. initialValue={attachData.attach}
  969. >
  970. {type == Type.add ||
  971. data?.status == Status.ReCall ||
  972. forceModify ? (
  973. <Upload {...UploadProps}>
  974. <Button icon={<CloudUploadOutlined />}>Upload</Button>
  975. </Upload>
  976. ) : (
  977. <ul>
  978. {data?.attach &&
  979. JSON.parse(data?.attach)?.map((item, idx) => (
  980. <li key={`${idx}_${item.name}`}>
  981. <a onClick={() => handlePreViewSingle(item)}>
  982. {item.name}
  983. </a>
  984. </li>
  985. ))}
  986. </ul>
  987. )}
  988. </Form.Item>
  989. <Form.Item
  990. name="archives_dep"
  991. initialValue={data?.archives_dep}
  992. label="合同原件存档部门:"
  993. tooltip="母公司财务部和采购部门的合同请选择“财务部”,其他部门请选择“行政部”,子公司合同选择“综合管理部”"
  994. rules={[
  995. {
  996. required: true,
  997. message: '请选择合同原件存档部门',
  998. },
  999. ]}
  1000. >
  1001. <Select
  1002. style={{ width: '100%' }}
  1003. options={archivesDepList?.map((item) => {
  1004. return { label: item.Name, value: item.Name };
  1005. })}
  1006. disabled={disableds.contract}
  1007. />
  1008. </Form.Item>
  1009. </Col>
  1010. <Col span={10}>
  1011. <Form.Item
  1012. name="attach_extend"
  1013. label="合同相关资料上传:"
  1014. initialValue={attachData.attach_extend}
  1015. tooltip={
  1016. <div>
  1017. 依据《合同管理办法》,合同相关资料需要作为合同电子档案的一部分,包括:
  1018. <br />
  1019. 1)合同会审纪要或投资决策通知书(如有);
  1020. <br />
  1021. 2)合同相对方的营业执照等资质证的复印件(首次签约的须加盖公章)、个人身份证复印件(合同一方为自然人时提供);
  1022. <br />
  1023. 3)合同相对方经办人员的授权委托书原件及其身份证复印件(如有);
  1024. <br />
  1025. 4)
  1026. 涉及房屋或场地租赁的,还应提供房屋及场地的权属证明资料,但如果续签租赁合同,且房屋所有权人没有发生变更的,在附具相关说明后可不再提供上述资料;
  1027. <br />
  1028. 5)其他资料。
  1029. </div>
  1030. }
  1031. >
  1032. {type == Type.add || forceModify ? (
  1033. <Upload {...UploadPropsExtend}>
  1034. <Button icon={<CloudUploadOutlined />}>Upload</Button>
  1035. </Upload>
  1036. ) : (
  1037. <ul>
  1038. {data?.attach_extend &&
  1039. JSON.parse(data?.attach_extend)
  1040. ?.filter((item) => item)
  1041. .map((item, idx) => (
  1042. <li key={`${idx}_${item.name}`}>
  1043. <a onClick={() => handlePreViewSingle(item)}>
  1044. {item.name}
  1045. </a>
  1046. </li>
  1047. ))}
  1048. </ul>
  1049. )}
  1050. </Form.Item>
  1051. </Col>
  1052. </Row>
  1053. {data?.status >= Status.Checking && !forceModify && (
  1054. <>
  1055. <ModuleTitle title="归档流程" />
  1056. <div className={styles.modelItem}>
  1057. <AuditSteps {...auditData} statusText="已归档" />
  1058. </div>
  1059. </>
  1060. )}
  1061. {(type == Type.cancel || data?.status >= Status.CalChecking) && (
  1062. <>
  1063. <ModuleTitle title="作废信息" />
  1064. <Form.Item
  1065. name="cancel_desc"
  1066. label="作废原因:"
  1067. initialValue={data?.cancel_desc}
  1068. labelCol={{ span: 4 }}
  1069. rules={[
  1070. {
  1071. required: true,
  1072. message: '请填写作废原因',
  1073. },
  1074. ]}
  1075. >
  1076. <Input disabled={type != Type.cancel} />
  1077. </Form.Item>
  1078. </>
  1079. )}
  1080. {type == Type.cancel && (
  1081. <Form.Item
  1082. name="cancel_on"
  1083. label="创建时间:"
  1084. initialValue={dayjs().format(FORMAT)}
  1085. labelCol={{ span: 4 }}
  1086. >
  1087. <Input
  1088. style={{ width: '460px' }}
  1089. defaultValue={dayjs().format('YYYY-MM-DD')}
  1090. disabled
  1091. />
  1092. <span
  1093. style={{ color: 'red', fontSize: '24px', marginLeft: '40px' }}
  1094. >
  1095. 确认作废该合同,作废提交后无法撤回
  1096. </span>
  1097. </Form.Item>
  1098. )}
  1099. {data?.status >= Status.CalChecking && (
  1100. <>
  1101. <ModuleTitle title="作废流程" />
  1102. <div className={styles.modelItem}>
  1103. <AuditSteps {...auditCelData} statusText="已作废" />
  1104. </div>
  1105. </>
  1106. )}
  1107. {(type == Type.add || data?.status == Status.ReCall || forceModify) &&
  1108. auditList.length > 0 && (
  1109. <>
  1110. <ModuleTitle title="审批流程" />
  1111. <div className={styles.modelItem}>
  1112. <Steps
  1113. current={1}
  1114. items={auditList.map((item, index) => {
  1115. return {
  1116. title: `审批${index + 1}`,
  1117. description: `审批人:${item.name}`,
  1118. };
  1119. })}
  1120. />
  1121. </div>
  1122. </>
  1123. )}
  1124. </Form>
  1125. <Divider />
  1126. </Modal>
  1127. <FileViewerModal
  1128. data={fileViewerData}
  1129. visible={fileViewerVisible}
  1130. onCancel={() => {
  1131. setFileViewerVisible(false);
  1132. }}
  1133. />
  1134. </>
  1135. );
  1136. };
  1137. export default ContractModal;