index.tsx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
  2. import styles from './index.module.scss'
  3. import { pageTitTxtObj } from '../../D4impStor/D4edit'
  4. import { useParams } from 'react-router-dom'
  5. import { Button, Cascader, DatePicker, Input, Radio, Select } from 'antd'
  6. import dayjs from 'dayjs'
  7. import Z3upFiles from '@/components/Z3upFiles'
  8. import ZRichTexts from '@/components/ZRichTexts'
  9. import { MessageFu } from '@/utils/message'
  10. import history, { btnFlagFu2, cascaderObjFu, openGoodsInfoFu } from '@/utils/history'
  11. import ZGaddNow from '@/components/ZGaddNow'
  12. import MyTable from '@/components/MyTable'
  13. import classNames from 'classnames'
  14. import MyPopconfirm from '@/components/MyPopconfirm'
  15. import { D4goodsTableC, statusObj } from '@/utils/tableData'
  16. import Y1cathet from '@/pages/Y_goodsDetails/Y1cathet'
  17. import X3auditInfo from '@/pages/X_stock/X3auditInfo'
  18. import ZflowTable from '@/components/ZflowTable'
  19. import { useDispatch, useSelector } from 'react-redux'
  20. import { D2_APIgetList } from '@/store/action/D2storSet'
  21. import { RootState } from '@/store'
  22. import {
  23. D6_APIcreate,
  24. D6_APIdel,
  25. D6_APIgetInfo,
  26. D6_APIrevocation,
  27. D6_APIsaveApply,
  28. D6_APIsaveAudit,
  29. D6_APIsaveCreate,
  30. D6_APIsaveDraft
  31. } from '@/store/action/D6putsStor'
  32. import { C1GoodType } from '@/pages/A3_ledger/C1ledger/type'
  33. import { EXbtnFu } from '@/utils/EXBtn'
  34. import D6impRelation from '../D6impRelation'
  35. import { FourTableType } from '@/pages/B_enterTibet/B1collect/type'
  36. import { B3aForm1 } from '@/pages/B_enterTibet/B1collect/data'
  37. function D6edit() {
  38. const { key, id } = useParams<any>()
  39. // key:1 新增 2编辑 3审批 4查看
  40. // 滚到顶部
  41. const sollrDom = useRef<HTMLDivElement>(null)
  42. // 顶部数据
  43. const [topInfo, setTopInfo] = useState({} as FourTableType)
  44. // 出库库房数组信息
  45. const dispatch = useDispatch()
  46. useEffect(() => {
  47. dispatch(D2_APIgetList({ pageNum: 1, pageSize: 99999 }))
  48. }, [dispatch])
  49. const { list: storSetList } = useSelector((state: RootState) => state.D2storSet.tableInfo)
  50. // 库房负责人txt
  51. const managerUser = useMemo(() => {
  52. let txt = ''
  53. if (topInfo.storageId && storSetList.length) {
  54. let obj = storSetList.find(v => v.id === topInfo.storageId)
  55. if (obj) txt = obj.managerUser
  56. }
  57. return txt
  58. }, [storSetList, topInfo.storageId])
  59. // 创建订单
  60. const creatFu = useCallback(async () => {
  61. const res = await D6_APIcreate()
  62. if (res.code === 0) {
  63. setTopInfo({ ...res.data, isReturn: 0 })
  64. }
  65. }, [])
  66. // 获取详情
  67. const getInfoFu = useCallback(async () => {
  68. const res = await D6_APIgetInfo(id)
  69. if (res.code === 0) {
  70. setTopInfo(res.data)
  71. // 设置富文本
  72. ZRichTextRef.current?.ritxtShowFu(JSON.parse(res.data.rtf) || '{}')
  73. }
  74. }, [id])
  75. useEffect(() => {
  76. if (key === '1') creatFu()
  77. else getInfoFu()
  78. if (sollrDom.current) sollrDom.current.scrollTop = 0
  79. }, [creatFu, getInfoFu, key])
  80. // 上传附件的ref
  81. const filesRef = useRef<any>(null)
  82. // const filesRes = filesRef.current.filesIdRes();
  83. // 富文本的ref
  84. const ZRichTextRef = useRef<any>(null)
  85. // 审批意见的ref
  86. const ZAuditRef = useRef<any>(null)
  87. const pageTitTxt = useMemo(() => {
  88. return Reflect.get(pageTitTxtObj, key)
  89. }, [key])
  90. const timeChange = useCallback(
  91. (e: any) => {
  92. setTopInfo({ ...topInfo, date: dayjs(e).format('YYYY-MM-DD') })
  93. },
  94. [topInfo]
  95. )
  96. const checkDataFu = useCallback(() => {
  97. if (!topInfo.name) {
  98. MessageFu.warning('申请名称不能为空')
  99. return true
  100. }
  101. if (!topInfo.sonTypeName) {
  102. MessageFu.warning('请选择业务类型')
  103. return true
  104. }
  105. if (!topInfo.storageId) {
  106. MessageFu.warning('请选择出库库房')
  107. return true
  108. }
  109. return false
  110. }, [topInfo])
  111. // 审批的sta
  112. const [auditSta, setAuDitSta] = useState('')
  113. // 新增的底部按钮点击
  114. const btnClickFu = useCallback(
  115. async (val: '草稿' | '创建' | '保存' | '审批') => {
  116. if (checkDataFu()) return
  117. if (val !== '草稿') {
  118. if (!topInfo.goods || (topInfo.goods && topInfo.goods.length === 0)) {
  119. return MessageFu.warning('请添加藏品')
  120. }
  121. }
  122. if (val === '审批') {
  123. // console.log('审批信息富文本', rtf2)
  124. if (!auditSta) {
  125. if (sollrDom.current) sollrDom.current.scrollTop = 0
  126. return MessageFu.warning('请选择审批结果')
  127. }
  128. const rtf2 = ZAuditRef.current?.resData()
  129. const res = await D6_APIsaveAudit({
  130. orderId: topInfo.id,
  131. rtfOpinion: rtf2,
  132. status: auditSta === '同意' ? 1 : 2
  133. })
  134. if (res.code === 0) {
  135. MessageFu.success('审批成功')
  136. // 跳详情页
  137. history.push(`/putsStor_edit/4/${topInfo.id}`)
  138. }
  139. } else {
  140. const rtf1 = ZRichTextRef.current?.fatherBtnOkFu() || { flag: true }
  141. // console.log('申请信息富文本', JSON.stringify(rtf1.val || ''))
  142. // 上传附件
  143. const filesRes = filesRef.current.filesIdRes()
  144. const obj = {
  145. ...topInfo,
  146. fileIds: filesRes.join(','),
  147. rtf: JSON.stringify(rtf1.val || ''),
  148. goodsIds: topInfo.goods.map(v => v.id).join(',')
  149. }
  150. // console.log(123, obj)
  151. // if (1 + 1 === 2) return
  152. if (val === '草稿') {
  153. // 存草稿 当前页保存 不跳转
  154. const res = await D6_APIsaveDraft(obj)
  155. if (res.code === 0) {
  156. MessageFu.success('草稿保存成功')
  157. }
  158. } else {
  159. const res = val === '创建' ? await D6_APIsaveCreate(obj) : await D6_APIsaveApply(obj)
  160. if (res.code === 0) {
  161. MessageFu.success(`${val}成功`)
  162. // 跳到详情页
  163. history.push(`/putsStor_edit/4/${topInfo.id}`)
  164. }
  165. }
  166. }
  167. },
  168. [auditSta, checkDataFu, topInfo]
  169. )
  170. // 打开侧边栏
  171. const [cathet, setCathet] = useState(0)
  172. const startBtn = useMemo(() => {
  173. return [
  174. {
  175. title: '藏品编号',
  176. render: (item: C1GoodType) => {
  177. return (
  178. <span
  179. onClick={() => setCathet(item.id)}
  180. className={classNames('D1GtNum', item.id === cathet ? 'D1GtNumAc' : '')}
  181. >
  182. {item.num}
  183. </span>
  184. )
  185. }
  186. }
  187. ]
  188. }, [cathet])
  189. const tableLastBtn = useMemo(() => {
  190. return [
  191. {
  192. title: '出库位置',
  193. width: 200,
  194. render: (item: C1GoodType) => {
  195. return item.siteStr ? item.siteStr.replaceAll(',', ' / ') : '(空)'
  196. }
  197. },
  198. {
  199. title: '操作',
  200. render: (item: C1GoodType) => {
  201. return (
  202. <>
  203. <Button size='small' type='text' onClick={() => openGoodsInfoFu(item.id)}>
  204. 查看
  205. </Button>
  206. {['3', '4'].includes(key) ? null : (
  207. <MyPopconfirm
  208. txtK='删除'
  209. onConfirm={() =>
  210. setTopInfo({
  211. ...topInfo,
  212. goods: topInfo.goods.filter(v => v.id !== item.id)
  213. })
  214. }
  215. />
  216. )}
  217. </>
  218. )
  219. }
  220. }
  221. ]
  222. }, [key, topInfo])
  223. // 点击新增
  224. const [nowSta, setNowSta] = useState({ key: '', id: '' })
  225. // 查看的按钮创建-提交-撤回
  226. const lookBtnFu = useCallback(
  227. async (val: '创建' | '提交' | '撤回') => {
  228. if (val !== '撤回') {
  229. if (!topInfo.goods || (topInfo.goods && topInfo.goods.length === 0)) {
  230. return MessageFu.warning('请添加藏品')
  231. }
  232. }
  233. const rtf1 = ZRichTextRef.current?.fatherBtnOkFu() || { flag: true }
  234. // console.log('申请信息富文本', JSON.stringify(rtf1.val || ''))
  235. // 上传附件
  236. const filesRes = filesRef.current.filesIdRes()
  237. const obj = {
  238. ...topInfo,
  239. fileIds: filesRes.join(','),
  240. rtf: JSON.stringify(rtf1.val || ''),
  241. goodsIds: topInfo.goods.map(v => v.id).join(',')
  242. }
  243. const res =
  244. val === '创建'
  245. ? await D6_APIsaveCreate(obj)
  246. : val === '提交'
  247. ? await D6_APIsaveApply(obj)
  248. : await D6_APIrevocation(id)
  249. if (res.code === 0) {
  250. if (sollrDom.current) sollrDom.current.scrollTop = 0
  251. MessageFu.success(val + '成功')
  252. getInfoFu()
  253. }
  254. },
  255. [getInfoFu, id, topInfo]
  256. )
  257. // 查看模式点击删除
  258. const delFu = useCallback(async () => {
  259. const res = await D6_APIdel(id)
  260. if (res.code === 0) {
  261. MessageFu.success('删除成功')
  262. history.push('/putsStor')
  263. }
  264. }, [id])
  265. // 查看模式点击审批 编辑
  266. const lookJumpFu = useCallback(
  267. (val: '审批' | '编辑') => {
  268. history.push(`/putsStor_edit/${val === '审批' ? 3 : 2}/${id}`)
  269. MessageFu.success(`已跳转至${val}页面`)
  270. },
  271. [id]
  272. )
  273. // 查看模式下的按钮
  274. const lookBtn = useMemo(() => {
  275. return (
  276. <>
  277. {btnFlagFu2(topInfo)['创建'] ? (
  278. <Button type='primary' onClick={() => lookBtnFu('创建')}>
  279. 创建
  280. </Button>
  281. ) : null}
  282. {btnFlagFu2(topInfo)['提交'] ? (
  283. <Button type='primary' onClick={() => lookBtnFu('提交')}>
  284. 提交
  285. </Button>
  286. ) : null}
  287. {btnFlagFu2(topInfo)['撤回'] ? (
  288. <MyPopconfirm
  289. txtK='撤回'
  290. onConfirm={() => lookBtnFu('撤回')}
  291. Dom={
  292. <Button type='primary' danger>
  293. 撤回
  294. </Button>
  295. }
  296. />
  297. ) : null}
  298. {btnFlagFu2(topInfo)['审批'] ? (
  299. <Button type='primary' onClick={() => lookJumpFu('审批')}>
  300. 审批
  301. </Button>
  302. ) : null}
  303. {btnFlagFu2(topInfo)['编辑'] ? (
  304. <Button type='primary' onClick={() => lookJumpFu('编辑')}>
  305. 编辑
  306. </Button>
  307. ) : null}
  308. {btnFlagFu2(topInfo)['重新提交'] ? (
  309. <Button type='primary' onClick={() => lookBtnFu('提交')}>
  310. 重新提交
  311. </Button>
  312. ) : null}
  313. {EXbtnFu(topInfo)}
  314. {btnFlagFu2(topInfo)['删除'] ? (
  315. <MyPopconfirm
  316. txtK='删除'
  317. onConfirm={() => delFu()}
  318. Dom={
  319. <Button type='primary' danger>
  320. 删除
  321. </Button>
  322. }
  323. />
  324. ) : null}
  325. <Button onClick={() => history.push('/putsStor')}>返回</Button>
  326. </>
  327. )
  328. }, [delFu, lookBtnFu, lookJumpFu, topInfo])
  329. // 申请记录
  330. const [auditsShow, setAuditsShow] = useState(false)
  331. return (
  332. <div className={styles.D6edit}>
  333. <div className='pageTitle'>藏品出库-{pageTitTxt}</div>
  334. <div className='D6main' ref={sollrDom}>
  335. {['3'].includes(key) ? (
  336. <X3auditInfo
  337. dirCode='putsStor'
  338. myUrl='cms/orderOut/upload'
  339. auditSta={auditSta}
  340. auditStaFu={val => setAuDitSta(val)}
  341. ref={ZAuditRef}
  342. />
  343. ) : null}
  344. {/* 表单字段、附件等 */}
  345. <div className='D6Tit'>
  346. 申请信息
  347. {key === '1' ? null : (
  348. <Button type='dashed'>{Reflect.get(statusObj, topInfo.status)}</Button>
  349. )}
  350. </div>
  351. <div className='D6rowAll'>
  352. <div className='D6row'>
  353. <div className='D6rowll'>
  354. <span> * </span>申请名称:
  355. </div>
  356. <div className='D6rowrr'>
  357. <Input
  358. value={topInfo.name}
  359. onChange={e => setTopInfo({ ...topInfo, name: e.target.value.trim() })}
  360. readOnly={['3', '4'].includes(key)}
  361. placeholder='请输入内容'
  362. maxLength={30}
  363. showCount
  364. />
  365. </div>
  366. </div>
  367. <div className='D6row'>
  368. <div className='D6rowll'>
  369. <span> * </span>业务类型:
  370. </div>
  371. <div className='D6rowrr'>
  372. <Cascader
  373. value={topInfo.sonTypeName ? topInfo.sonTypeName.split(',') : []}
  374. onChange={e => setTopInfo({ ...topInfo, sonTypeName: e ? e.join(',') : '' })}
  375. disabled={['3', '4'].includes(key)}
  376. options={cascaderObjFu()['藏品出库']}
  377. changeOnSelect
  378. placeholder='请选择'
  379. fieldNames={{ label: 'name', value: 'id', children: 'children' }}
  380. allowClear={false}
  381. />
  382. </div>
  383. </div>
  384. {B3aForm1.map(v => (
  385. <div className='D6row' key={v.name}>
  386. <div className='D6rowll'>{v.name}:</div>
  387. <div className='D6rowrr'>
  388. {topInfo[v.key as 'name']}
  389. {['3', '4'].includes(key) && v.name === '发起人'
  390. ? ' - ' + topInfo.createTime || ''
  391. : ''}
  392. </div>
  393. </div>
  394. ))}
  395. <div className='D6row'>
  396. <div className='D6rowll'>
  397. <span> * </span>是否归还:
  398. </div>
  399. <div className='D6rowrr'>
  400. <Radio.Group
  401. disabled={['3', '4'].includes(key)}
  402. value={topInfo.isReturn}
  403. onChange={e =>
  404. setTopInfo({
  405. ...topInfo,
  406. isReturn: e.target.value,
  407. returnDate: e.target.value === 0 ? '' : topInfo.returnDate
  408. })
  409. }
  410. options={[
  411. { value: 1, label: '是' },
  412. { value: 0, label: '否' }
  413. ]}
  414. />
  415. </div>
  416. </div>
  417. <div className='D6row'>
  418. <div className='D6rowll'> 预计归还日期:</div>
  419. <div className='D6rowrr'>
  420. <DatePicker
  421. placeholder={topInfo.isReturn !== 1 ? '(空)' : '请选择日期'}
  422. disabled={['3', '4'].includes(key) || topInfo.isReturn !== 1}
  423. allowClear={true}
  424. value={topInfo.returnDate ? dayjs(topInfo.returnDate) : null}
  425. onChange={e =>
  426. setTopInfo({ ...topInfo, returnDate: e ? dayjs(e).format('YYYY-MM-DD') : '' })
  427. }
  428. />
  429. </div>
  430. </div>
  431. <div className='D6row'>
  432. <div className='D6rowll'>
  433. <span> * </span>业务日期:
  434. </div>
  435. <div className='D6rowrr'>
  436. <DatePicker
  437. disabled={['3', '4'].includes(key)}
  438. allowClear={false}
  439. value={dayjs(topInfo.date)}
  440. onChange={timeChange}
  441. />
  442. </div>
  443. </div>
  444. <div className='D6row'>
  445. <div className='D6rowll'>原因事由:</div>
  446. <div className='D6rowrr'>
  447. <Input
  448. value={topInfo.reason}
  449. onChange={e => setTopInfo({ ...topInfo, reason: e.target.value })}
  450. readOnly={['3', '4'].includes(key)}
  451. placeholder='请输入内容'
  452. maxLength={30}
  453. showCount
  454. />
  455. </div>
  456. </div>
  457. <div className='D6row D6row2'>
  458. <div className='D6rowll'>附件:</div>
  459. <div className='D6rowrr'>
  460. <Z3upFiles
  461. max={10}
  462. isLook={['3', '4'].includes(key)}
  463. ref={filesRef}
  464. fileCheck={false}
  465. dirCode='putsStor'
  466. myUrl='cms/orderOut/upload'
  467. lookData={topInfo.files || []}
  468. size={500}
  469. fromData={{ moduleId: topInfo.id }}
  470. />
  471. </div>
  472. </div>
  473. <div className='D6row D6rowFull'>
  474. <div className='D6rowll'>备注:</div>
  475. <div className='D6rowrr'>
  476. <ZRichTexts
  477. check={false}
  478. dirCode='putsStor'
  479. myUrl='cms/orderOut/upload'
  480. isLook={['3', '4'].includes(key)}
  481. ref={ZRichTextRef}
  482. isOne={true}
  483. upAudioBtnNone={true}
  484. />
  485. </div>
  486. </div>
  487. </div>
  488. <div className='D6Tit'>库房信息</div>
  489. <div className='D6rowAll'>
  490. <div className='D6row'>
  491. <div className='D6rowll'>
  492. <span> * </span>出库库房:
  493. </div>
  494. <div className='D6rowrr'>
  495. <Select
  496. options={storSetList}
  497. value={topInfo.storageId}
  498. onChange={(storageId, arr) => {
  499. setTopInfo({ ...topInfo, storageId, goods: [] })
  500. }}
  501. disabled={['3', '4'].includes(key)}
  502. fieldNames={{ value: 'id', label: 'name' }}
  503. placeholder='请选择'
  504. />
  505. </div>
  506. </div>
  507. <div className='D6row D6row3'>
  508. <div className='D6rowll'>库房负责人:</div>
  509. <div className='D6rowrr'>{managerUser || '(空)'}</div>
  510. </div>
  511. </div>
  512. {/* 藏品清单 */}
  513. <div className='D6googsBox'>
  514. <div className='D6Tit2'>
  515. <div className='D6Tit2ll'>藏品清单</div>
  516. <div className='D6Tit2rr'>
  517. {['3', '4'].includes(key) ? null : (
  518. <Button
  519. type='primary'
  520. onClick={() => {
  521. if (!topInfo.storageId) return MessageFu.warning('请先选择出库库房')
  522. setNowSta({ key: '5', id: 'cms/orderOut/goods/getList' })
  523. }}
  524. >
  525. 新增
  526. </Button>
  527. )}
  528. </div>
  529. </div>
  530. {/* 表格 */}
  531. <MyTable
  532. list={topInfo.goods || []}
  533. columnsTemp={D4goodsTableC}
  534. startBtn={startBtn}
  535. lastBtn={tableLastBtn}
  536. pagingInfo={false}
  537. />
  538. </div>
  539. {/* 相关入库单 */}
  540. {key === '4' ? <D6impRelation list={topInfo.relatedOrder || []} /> : null}
  541. {/* 申请流程 */}
  542. {auditsShow ? (
  543. <ZflowTable tableArr={topInfo.audits || []} closeFu={() => setAuditsShow(false)} />
  544. ) : null}
  545. </div>
  546. {/* 底部按钮 */}
  547. <div className='D6btn'>
  548. {['3', '4'].includes(key) && topInfo.audits && topInfo.audits.length ? (
  549. <Button type='primary' onClick={() => setAuditsShow(true)}>
  550. 申请记录
  551. </Button>
  552. ) : null}
  553. {key === '4' ? (
  554. lookBtn
  555. ) : (
  556. <>
  557. {key === '3' ? (
  558. <Button type='primary' onClick={() => btnClickFu('审批')}>
  559. 审批
  560. </Button>
  561. ) : (
  562. <Button type='primary' onClick={() => btnClickFu(key === '1' ? '创建' : '保存')}>
  563. {key === '1' ? '创建' : '保存'}
  564. </Button>
  565. )}
  566. {key === '1' ? (
  567. <Button type='primary' onClick={() => btnClickFu('草稿')}>
  568. 存草稿
  569. </Button>
  570. ) : null}
  571. <MyPopconfirm txtK='取消' onConfirm={() => history.push('/putsStor')} />
  572. </>
  573. )}
  574. </div>
  575. {/* 打开侧边栏 */}
  576. <Y1cathet sId={cathet} closeFu={() => setCathet(0)} />
  577. {/* 新增弹窗 */}
  578. {nowSta.id ? (
  579. <ZGaddNow
  580. nowSta={nowSta}
  581. closeFu={() => setNowSta({ key: '', id: '' })}
  582. dataResFu={data => setTopInfo({ ...topInfo, goods: data })}
  583. oldCheckArr={topInfo.goods || []}
  584. canObj={{ storageId: topInfo.storageId }}
  585. />
  586. ) : null}
  587. </div>
  588. )
  589. }
  590. const MemoD6edit = React.memo(D6edit)
  591. export default MemoD6edit