index.tsx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. import React, { useCallback, useEffect, useRef, useState } from 'react'
  2. import styles from './index.module.scss'
  3. import { Button, DatePicker, Form, FormInstance, Input, InputNumber, Radio, Select } from 'antd'
  4. import { A1EditInfoType } from '@/pages/A1event/data'
  5. import { A2_APIgetInfo, A2_APIsave } from '@/store/action/A2exhibition'
  6. import dayjs from 'dayjs'
  7. import { MessageFu } from '@/utils/message'
  8. import classNames from 'classnames'
  9. import ZupAudio from '@/components/ZupAudio'
  10. import ZupOne from '@/components/ZupOne'
  11. import MyPopconfirm from '@/components/MyPopconfirm'
  12. import ZRichTexts from '@/components/ZRichTexts'
  13. import TextArea from 'antd/es/input/TextArea'
  14. import ZupTypes from '@/components/ZupTypes'
  15. const { RangePicker } = DatePicker
  16. type Props = {
  17. editInfo: A1EditInfoType
  18. closeFu: () => void
  19. editTableFu: () => void
  20. addTableFu: () => void
  21. }
  22. function A2add({ editInfo, closeFu, editTableFu, addTableFu }: Props) {
  23. const [dirCode, setDirCode] = useState('')
  24. // 表单的ref
  25. const FormBoxRef = useRef<FormInstance>(null)
  26. // 封面图的ref
  27. const ZupThumbRef = useRef<any>(null)
  28. // PC海报图的ref
  29. const ZupPcImgRef = useRef<any>(null)
  30. // 富文本的ref
  31. const ZRichTextRef = useRef<any>(null)
  32. // 展品的ref
  33. const ZupFilesRef1 = useRef<any>(null)
  34. // 展馆的ref
  35. const ZupFilesRef2 = useRef<any>(null)
  36. // 标题的音频
  37. const [nameAudio, setNameAudio] = useState({
  38. fileName: '',
  39. filePath: ''
  40. })
  41. // 编辑/查看 进入页面 获取信息
  42. const getInfoFu = useCallback(async (id: number) => {
  43. const res = await A2_APIgetInfo(id)
  44. if (res.code === 0) {
  45. const data = res.data
  46. setDirCode(data.dirCode)
  47. // 展示展品
  48. ZupFilesRef1.current?.setFileComFileFu({
  49. type: 'img',
  50. fileList: data.exhibitsFile || []
  51. })
  52. // 展示展馆
  53. ZupFilesRef2.current?.setFileComFileFu({
  54. type: 'img',
  55. fileList: data.exhibitionFile || []
  56. })
  57. // 设置 临时展览 / 常设展览
  58. setTimeType(data.type)
  59. // 设置 常设展览描述
  60. setTimeVal(data.typeRemark)
  61. // 设置 临时展览 时间
  62. if (data.dateStart && data.dateEnd) {
  63. setTimeArr([dayjs(data.dateStart), dayjs(data.dateEnd)])
  64. }
  65. // 设置地址
  66. setAddrType({
  67. key: data.addrType,
  68. txt: data.address
  69. })
  70. // 设置标题的 音频
  71. if (data.fileName && data.filePath) {
  72. setNameAudio({
  73. fileName: data.fileName,
  74. filePath: data.filePath
  75. })
  76. }
  77. // 设置富文本
  78. ZRichTextRef.current?.ritxtShowFu(JSON.parse(data.rtf))
  79. const obj = {
  80. ...data,
  81. myTime: dayjs(data.datePublish)
  82. }
  83. FormBoxRef.current?.setFieldsValue(obj)
  84. // 设置封面图
  85. ZupThumbRef.current?.setFileComFileFu({
  86. fileName: '',
  87. filePath: data.thumb
  88. })
  89. // 设置Pc海报
  90. ZupPcImgRef.current?.setFileComFileFu({
  91. fileName: '',
  92. filePath: data.thumbPc
  93. })
  94. }
  95. }, [])
  96. // 临时展览 常设展览的切换
  97. const [timeType, setTimeType] = useState('long')
  98. const [timeVal, setTimeVal] = useState('')
  99. // 格式为dayjs的格式,需要转换
  100. const [timeArr, setTimeArr] = useState<any>(null)
  101. // 地址
  102. const [addrType, setAddrType] = useState({
  103. key: 'inland',
  104. txt: ''
  105. })
  106. const addrTypeChangeFu = useCallback(
  107. (key: 'key' | 'txt', val: string) => {
  108. setAddrType({ ...addrType, [key]: val })
  109. },
  110. [addrType]
  111. )
  112. // 附件 是否 已经点击过确定
  113. const [fileCheck, setFileCheck] = useState(false)
  114. // 没有通过校验
  115. const onFinishFailed = useCallback(() => {
  116. setFileCheck(true)
  117. }, [])
  118. // 通过校验点击确定
  119. const onFinish = useCallback(
  120. async (values: any) => {
  121. setFileCheck(true)
  122. const coverUrl1 = ZupThumbRef.current?.fileComFileResFu()
  123. // 没有传 封面图
  124. if (!coverUrl1.filePath) return MessageFu.warning('请上传封面图!')
  125. // 发布日期
  126. const datePublish = dayjs(values.myTime).format('YYYY-MM-DD')
  127. // 临时展览的时候要判断
  128. if (timeType === 'temp') {
  129. if (!timeArr || !timeArr[0]) return MessageFu.warning('请选择临时展览时间!')
  130. }
  131. // 地址校验
  132. if (!addrType.txt) return MessageFu.warning('请输入地址!')
  133. let dateStart = ''
  134. let dateEnd = ''
  135. if (timeArr && timeArr[0] && timeArr[1]) {
  136. dateStart = dayjs(timeArr[0]).format('YYYY-MM-DD')
  137. dateEnd = dayjs(timeArr[1]).format('YYYY-MM-DD')
  138. }
  139. // 富文本校验不通过
  140. const rtf = ZRichTextRef.current?.fatherBtnOkFu() || { flag: true }
  141. if (rtf.flag) return MessageFu.warning('请输入完整正文!')
  142. // 展品的校验
  143. const { sonFileIds: exhibitsFileIds } = ZupFilesRef1.current?.fileComFileResFu()
  144. if (exhibitsFileIds.length <= 0) {
  145. return MessageFu.warning('请最少上传一个展品!')
  146. }
  147. // 展馆的校验
  148. const { sonFileIds: exhibitionFileIds } = ZupFilesRef2.current?.fileComFileResFu()
  149. if (exhibitionFileIds.length <= 0) {
  150. return MessageFu.warning('请最少上传一个展馆!')
  151. }
  152. // pc海报
  153. const coverUrl2 = ZupPcImgRef.current?.fileComFileResFu()
  154. // 富文本标题集合
  155. let rtfNameArr: string[] = []
  156. if (rtf.val && rtf.val.txtArr && rtf.val.txtArr.length) {
  157. rtfNameArr = rtf.val.txtArr.map((v: any) => v.name)
  158. }
  159. const obj = {
  160. ...values,
  161. id: editInfo.id > 0 ? editInfo.id : null,
  162. datePublish,
  163. thumb: coverUrl1.filePath,
  164. thumbPc: coverUrl2.filePath,
  165. rtf: JSON.stringify(rtf.val || ''),
  166. fileName: nameAudio.fileName,
  167. filePath: nameAudio.filePath,
  168. type: timeType,
  169. dateStart,
  170. dateEnd,
  171. addrType: addrType.key,
  172. address: addrType.txt,
  173. exhibitsFileIds: exhibitsFileIds.join(','),
  174. exhibitionFileIds: exhibitionFileIds.join(','),
  175. dirCode,
  176. typeRemark: timeVal,
  177. rtfTitle: JSON.stringify(rtfNameArr)
  178. }
  179. // if (obj) {
  180. // console.log(123, obj);
  181. // return;
  182. // }
  183. const res = await A2_APIsave(obj)
  184. if (res.code === 0) {
  185. MessageFu.success(`${editInfo.txt}成功!`)
  186. editInfo.id > 0 ? editTableFu() : addTableFu()
  187. closeFu()
  188. }
  189. },
  190. [
  191. timeVal,
  192. dirCode,
  193. addTableFu,
  194. addrType.key,
  195. addrType.txt,
  196. closeFu,
  197. editInfo.id,
  198. editInfo.txt,
  199. editTableFu,
  200. nameAudio.fileName,
  201. nameAudio.filePath,
  202. timeArr,
  203. timeType
  204. ]
  205. )
  206. useEffect(() => {
  207. if (editInfo.id > 0) {
  208. getInfoFu(editInfo.id)
  209. } else {
  210. setDirCode(Date.now() + '')
  211. FormBoxRef.current?.setFieldsValue({
  212. myTime: dayjs(Date.now()),
  213. sort: 999,
  214. display: 1
  215. })
  216. }
  217. }, [editInfo.id, getInfoFu])
  218. return (
  219. <div className={styles.A2add}>
  220. <div className={classNames('A2eMain', editInfo.txt === '查看' ? 'A2eMainLook' : '')}>
  221. <Form
  222. ref={FormBoxRef}
  223. name='basic'
  224. labelCol={{ span: 3 }}
  225. onFinish={onFinish}
  226. onFinishFailed={onFinishFailed}
  227. autoComplete='off'
  228. scrollToFirstError
  229. >
  230. <div className='A2fromRow'>
  231. <Form.Item
  232. label='标题'
  233. name='name'
  234. rules={[{ required: true, message: '请输入标题!' }]}
  235. // getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
  236. >
  237. <TextArea
  238. readOnly={editInfo.txt === '查看'}
  239. style={{ width: '500px' }}
  240. maxLength={100}
  241. showCount
  242. placeholder='请输入内容'
  243. />
  244. </Form.Item>
  245. {/* 标题的无障碍音频 */}
  246. <div className='A2_1Frow'>
  247. <ZupAudio
  248. fileInfo={nameAudio}
  249. upDataFu={info => setNameAudio(info)}
  250. delFu={() => setNameAudio({ fileName: '', filePath: '' })}
  251. dirCode={dirCode}
  252. myUrl='cms/exhibition/upload'
  253. isLook={editInfo.txt === '查看'}
  254. />
  255. </div>
  256. </div>
  257. {/* 封面 */}
  258. <div className='formRow'>
  259. <div className='formLeft'>
  260. <span>* </span>
  261. 封面:
  262. </div>
  263. <div className='formRight'>
  264. <ZupOne
  265. ref={ZupThumbRef}
  266. isLook={editInfo.txt === '查看'}
  267. fileCheck={fileCheck}
  268. size={5}
  269. dirCode={dirCode}
  270. myUrl='cms/exhibition/upload'
  271. format={['image/jpeg', 'image/png']}
  272. formatTxt='png、jpg和jpeg'
  273. checkTxt='请上传封面图!'
  274. upTxt='最多1张'
  275. myType='thumb'
  276. />
  277. </div>
  278. </div>
  279. {/* PC海报 */}
  280. <div className='formRow'>
  281. <div className='formLeft'>
  282. <span> </span>
  283. PC海报:
  284. </div>
  285. <div className='formRight'>
  286. <ZupOne
  287. ref={ZupPcImgRef}
  288. isLook={editInfo.txt === '查看'}
  289. fileCheck={false}
  290. size={5}
  291. dirCode={dirCode}
  292. myUrl='cms/exhibition/upload'
  293. format={['image/jpeg', 'image/png']}
  294. formatTxt='png、jpg和jpeg'
  295. checkTxt='请上传封面图!'
  296. upTxt='最多1张'
  297. myType='thumb'
  298. />
  299. </div>
  300. </div>
  301. {editInfo.txt === '查看' ? <br /> : null}
  302. <Form.Item label='摘要' name='digest'>
  303. <TextArea
  304. readOnly={editInfo.txt === '查看'}
  305. placeholder='请输入内容'
  306. maxLength={1000}
  307. showCount
  308. />
  309. </Form.Item>
  310. {/* 时间 */}
  311. <div className='formRow'>
  312. <div className='formLeft'>
  313. <span>* </span>
  314. 时间:
  315. </div>
  316. <div className='formRight'>
  317. <div>
  318. <Select
  319. value={timeType}
  320. onChange={e => setTimeType(e)}
  321. style={{ width: 150 }}
  322. options={[
  323. { value: 'long', label: '常设展览' },
  324. { value: 'temp', label: '临时展览' }
  325. ]}
  326. />
  327. &emsp;
  328. {timeType === 'long' ? (
  329. <Input
  330. style={{ width: 536 }}
  331. maxLength={100}
  332. showCount
  333. value={timeVal}
  334. onChange={e => setTimeVal(e.target.value)}
  335. placeholder='在此填入时间备注(选填),如9:00 - 17:00 (closed on Mondays)'
  336. />
  337. ) : (
  338. <RangePicker
  339. value={timeArr && timeArr[0] ? timeArr : null}
  340. onChange={val => setTimeArr(val)}
  341. />
  342. )}
  343. </div>
  344. <div
  345. className={classNames(
  346. 'formRight5Tit',
  347. fileCheck && timeType === 'temp' && (!timeArr || !timeArr[0])
  348. ? 'formRight5TitErr'
  349. : ''
  350. )}
  351. >
  352. 请选择时间!
  353. </div>
  354. </div>
  355. </div>
  356. {/* 地址 */}
  357. <div className='formRow'>
  358. <div className='formLeft'>
  359. <span>* </span>
  360. 地址:
  361. </div>
  362. <div className='formRight'>
  363. <div>
  364. {[
  365. { name: '国内', key: 'inland' },
  366. { name: '国外', key: 'foreign' }
  367. ].map(item => (
  368. <Radio
  369. key={item.name}
  370. checked={addrType.key === item.key}
  371. onClick={() => addrTypeChangeFu('key', item.key)}
  372. >
  373. {item.name}
  374. </Radio>
  375. ))}
  376. &emsp;
  377. <Input
  378. readOnly={editInfo.txt === '查看'}
  379. style={{ width: 536, marginLeft: 14 }}
  380. maxLength={100}
  381. showCount
  382. value={addrType.txt}
  383. onChange={e => addrTypeChangeFu('txt', e.target.value)}
  384. placeholder='请输入内容'
  385. />
  386. </div>
  387. <div
  388. className={classNames(
  389. 'formRight5Tit',
  390. fileCheck && !addrType.txt ? 'formRight5TitErr' : ''
  391. )}
  392. >
  393. 请输入地址!
  394. </div>
  395. </div>
  396. </div>
  397. {/* 概况 */}
  398. <div className='formRow'>
  399. <div className='formLeft'>
  400. <span>* </span>
  401. 概况:
  402. </div>
  403. <div className='formRight'>
  404. <ZRichTexts
  405. check={fileCheck}
  406. dirCode={dirCode}
  407. isLook={editInfo.txt === '查看'}
  408. ref={ZRichTextRef}
  409. myUrl='cms/exhibition/upload'
  410. />
  411. </div>
  412. </div>
  413. {/* 展品 */}
  414. <div className='formRow'>
  415. <div className='formLeft'>
  416. <span>* </span>
  417. 展品:
  418. </div>
  419. <div className='formRight'>
  420. <ZupTypes
  421. ref={ZupFilesRef1}
  422. selecFlag='图片'
  423. fileCheck={fileCheck}
  424. dirCode={dirCode}
  425. myUrl='cms/exhibition/upload'
  426. isLook={editInfo.txt === '查看'}
  427. imgLength={30}
  428. isTypeShow={true}
  429. isUpName={true}
  430. />
  431. </div>
  432. </div>
  433. {/* 展馆 */}
  434. <div className='formRow'>
  435. <div className='formLeft'>
  436. <span>* </span>
  437. 展馆:
  438. </div>
  439. <div className='formRight'>
  440. <ZupTypes
  441. ref={ZupFilesRef2}
  442. selecFlag='图片'
  443. fileCheck={fileCheck}
  444. dirCode={dirCode}
  445. myUrl='cms/exhibition/upload'
  446. isLook={editInfo.txt === '查看'}
  447. imgLength={30}
  448. isTypeShow={true}
  449. />
  450. </div>
  451. </div>
  452. <Form.Item
  453. label='发布日期'
  454. name='myTime'
  455. rules={[{ required: true, message: '请选择发布日期!' }]}
  456. >
  457. <DatePicker />
  458. </Form.Item>
  459. <div className='A2fromRow'>
  460. <Form.Item
  461. label='排序值'
  462. name='sort'
  463. rules={[{ required: true, message: '请输入排序值!' }]}
  464. >
  465. <InputNumber min={1} max={999} precision={0} placeholder='请输入' />
  466. </Form.Item>
  467. <div className='A2_6Frow' hidden={editInfo.txt === '查看'}>
  468. 请输入1~999的数字。数字越小,排序越靠前。数字相同时,更新发布的内容排在前面
  469. </div>
  470. </div>
  471. <Form.Item
  472. label='状态'
  473. name='display'
  474. rules={[{ required: true, message: '请选择状态!' }]}
  475. >
  476. <Select
  477. placeholder='请选择状态'
  478. style={{ width: 149 }}
  479. options={[
  480. { value: 1, label: '发布' },
  481. { value: 0, label: '不发布' }
  482. ]}
  483. />
  484. </Form.Item>
  485. {/* 确定和取消按钮 */}
  486. <Form.Item className='A2Ebtn'>
  487. {editInfo.txt === '查看' ? (
  488. <Button onClick={closeFu}>返回</Button>
  489. ) : (
  490. <>
  491. <Button type='primary' htmlType='submit'>
  492. 提交
  493. </Button>
  494. <br />
  495. <br />
  496. <MyPopconfirm txtK='取消' onConfirm={closeFu} />
  497. </>
  498. )}
  499. </Form.Item>
  500. </Form>
  501. </div>
  502. </div>
  503. )
  504. }
  505. const MemoA2add = React.memo(A2add)
  506. export default MemoA2add