index.tsx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. import React, {
  2. useCallback,
  3. useEffect,
  4. useMemo,
  5. useRef,
  6. useState,
  7. } from "react";
  8. import styles from "./index.module.scss";
  9. import {
  10. Button,
  11. Cascader,
  12. DatePicker,
  13. Form,
  14. FormInstance,
  15. Input,
  16. InputNumber,
  17. Popconfirm,
  18. Select,
  19. Radio,
  20. Checkbox,
  21. } from "antd";
  22. import mapDataAll from "./data";
  23. import dayjs from "dayjs";
  24. import TextArea from "antd/es/input/TextArea";
  25. import { MessageFu } from "@/utils/message";
  26. import classNames from "classnames";
  27. import { useSelector } from "react-redux";
  28. import { RootState } from "@/store";
  29. import { A1_APIaddProject, A1_APIgetInfoById } from "@/store/action/A1Project";
  30. import { A1TableType } from "@/types";
  31. import AuthCom from "@/components/AuthCom";
  32. import { getTokenInfo } from "@/utils/storage";
  33. const { RangePicker } = DatePicker;
  34. type Props = {
  35. pageType: { txt: string; id: number };
  36. closeFu: () => void;
  37. addFu: () => void;
  38. editFu: (val: string) => void;
  39. };
  40. function A1Add({ pageType, closeFu, addFu, editFu }: Props) {
  41. const [lookInfo, setLookInfo] = useState({} as A1TableType);
  42. const [isOk, setIsOk] = useState(false);
  43. const userInfo = useMemo(() => {
  44. return getTokenInfo().user;
  45. }, []);
  46. const getInfoFu = useCallback(async (id: number) => {
  47. const res = await A1_APIgetInfoById(id);
  48. if (res.code === 0) {
  49. const info = res.data.entity;
  50. setLookInfo(info);
  51. // 创建人编辑的 提示 回显
  52. setCreatorIdValue(info.creatorId);
  53. const province = info.province ? info.province.split("-") : "";
  54. const dateScope = info.dateScope ? info.dateScope.split(" 至 ") : "";
  55. FormBoxRef.current?.setFieldsValue({
  56. ...info,
  57. province,
  58. dateScope: dateScope ? [dayjs(dateScope[0]), dayjs(dateScope[1])] : "",
  59. dictProjectBusinessIds: Number(info.dictProjectBusinessIds), // 提交表单时这一项数据类型是 number,获取表单数据时这一项数据类型是string。
  60. bidDate: dayjs(info.bidDate),
  61. });
  62. // 回显的时候闪动 问题
  63. setIsOk(true);
  64. }
  65. }, []);
  66. useEffect(() => {
  67. if (!pageType.id) {
  68. // 新增
  69. setIsOk(true);
  70. } else if (pageType.txt === 'look') {
  71. // 查看
  72. getInfoFu(pageType.id);
  73. } else if (pageType.txt === 'edit') {
  74. // 编辑
  75. setIsBid(lookInfo.isBid);
  76. }
  77. }, [getInfoFu, pageType.id, pageType.txt, lookInfo.isBid]);
  78. // 从仓库 获取 项目状态的下拉框 数据
  79. const statusArr = useSelector(
  80. (state: RootState) => state.A2Dict.A2Tab1_1Obj.status
  81. );
  82. // 从仓库 获取 签订主体 数据
  83. const mainArr = useSelector(
  84. (state: RootState) => state.A2Dict.A2Tab1_1Obj.main
  85. );
  86. // 从仓库 获取 业务部门 数据
  87. const deptArr = useSelector(
  88. (state: RootState) => state.A2Dict.A2Tab1_1Obj.dept
  89. );
  90. // 从仓库 获取 业务类型 数据
  91. const projectBusinessArr = useSelector(
  92. (state: RootState) => state.A2Dict.A2Tab1_1Obj.projectBusiness
  93. );
  94. // 从仓库 获取 项目范围 数据
  95. const projectScopeArr = useSelector(
  96. (state: RootState) => state.A2Dict.A2Tab1_1Obj.projectScope
  97. );
  98. // 从仓库 获取 客户端 数据
  99. const projectAppArr = useSelector(
  100. (state: RootState) => state.A2Dict.A2Tab1_1Obj.projectApp
  101. );
  102. // 表单的ref
  103. const FormBoxRef = useRef<FormInstance>(null);
  104. // 没有通过校验
  105. const onFinishFailed = useCallback(() => {
  106. console.log("没有通过校验");
  107. }, []);
  108. // 通过校验点击确定
  109. const onFinish = useCallback(
  110. async (value: any) => {
  111. // 项目周期的处理
  112. let dateScope = "";
  113. if (value.dateScope && value.dateScope.length >= 1) {
  114. dateScope =
  115. dayjs(value.dateScope[0]).format("YYYY-MM-DD") +
  116. " 至 " +
  117. dayjs(value.dateScope[1]).format("YYYY-MM-DD");
  118. }
  119. // 项目地点的处理
  120. let province = "";
  121. if (value.province && value.province.length)
  122. province = value.province.join("-");
  123. // 中标日期的处理
  124. let bidDate = "";
  125. if (value.bidDate) bidDate = dayjs(value.bidDate).format("YYYY-MM-DD");
  126. const obj = {
  127. ...value,
  128. id: pageType.txt === "add" ? null : pageType.id,
  129. dateScope,
  130. amount: value.amount ? value.amount : "",
  131. province,
  132. bidDate,
  133. };
  134. const res = await A1_APIaddProject(obj);
  135. if (res.code === 0) {
  136. if (pageType.txt === "add") {
  137. MessageFu.success("新增成功!");
  138. addFu();
  139. } else if (pageType.txt === "edit") {
  140. MessageFu.success("编辑成功!");
  141. editFu(value.num + " - " + value.name);
  142. }
  143. closeFu();
  144. }
  145. },
  146. [addFu, closeFu, editFu, pageType.id, pageType.txt]
  147. );
  148. // 从仓库中获取 用户列表数据(全部)
  149. const userListTemp = useSelector(
  150. (state: RootState) => state.A3User.tableInfo.list
  151. );
  152. const userList = useMemo(() => {
  153. return userListTemp.map((v: any) => ({
  154. value: v.id,
  155. label: `${v.userName} - ${v.roleName}${
  156. v.realName ? " - " + v.realName : ""
  157. }`,
  158. }));
  159. }, [userListTemp]);
  160. // 创建人 的 值
  161. const [creatorIdValue, setCreatorIdValue] = useState(userInfo.id);
  162. // 是否投标
  163. const [isBid, setIsBid] = useState<number | undefined>();
  164. return (
  165. <div className={styles.A1Add}>
  166. <div
  167. className={classNames(
  168. "A1AddMain",
  169. pageType.txt === "look" ? "A1AddMainLook" : ""
  170. )}
  171. >
  172. <Form
  173. scrollToFirstError={true}
  174. ref={FormBoxRef}
  175. name="basic"
  176. onFinish={onFinish}
  177. onFinishFailed={onFinishFailed}
  178. autoComplete="off"
  179. initialValues={{
  180. snapPmUser: userInfo.realName,
  181. creatorId: userInfo.id,
  182. }}
  183. onValuesChange={(changedValues, allValues) => {
  184. setIsBid(allValues.isBid);
  185. }}
  186. >
  187. <Form.Item
  188. label="项目编号"
  189. name="num"
  190. rules={[{ required: true, message: "请输入项目编号!" }]}
  191. getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
  192. >
  193. <Input
  194. style={{ width: 600 }}
  195. maxLength={30}
  196. showCount
  197. placeholder={
  198. isOk
  199. ? pageType.txt === "look"
  200. ? "(空)"
  201. : "请输入内容,不能重复"
  202. : ""
  203. }
  204. />
  205. </Form.Item>
  206. <Form.Item
  207. label="项目名称"
  208. name="name"
  209. rules={[{ required: true, message: "请输入项目名称!" }]}
  210. getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
  211. >
  212. <Input
  213. style={{ width: 600 }}
  214. maxLength={30}
  215. showCount
  216. placeholder={
  217. isOk ? (pageType.txt === "look" ? "(空)" : "请输入内容") : ""
  218. }
  219. />
  220. </Form.Item>
  221. <Form.Item label="建设单位" name="unit">
  222. <Input
  223. style={{ width: 600 }}
  224. maxLength={30}
  225. showCount
  226. placeholder={
  227. isOk ? (pageType.txt === "look" ? "(空)" : "请输入内容") : ""
  228. }
  229. />
  230. </Form.Item>
  231. <Form.Item label="项目地点" name="province">
  232. <Cascader
  233. style={{ width: 300 }}
  234. options={mapDataAll}
  235. placeholder={
  236. isOk ? (pageType.txt === "look" ? "(空)" : "请选择省/市") : ""
  237. }
  238. />
  239. </Form.Item>
  240. <Form.Item
  241. label="项目状态"
  242. name="statusId"
  243. rules={[{ required: true, message: "请选择项目状态!" }]}
  244. >
  245. <Select
  246. placeholder={
  247. isOk ? (pageType.txt === "look" ? "(空)" : "请选择") : ""
  248. }
  249. style={{ width: 300 }}
  250. options={statusArr.map((v) => ({ value: v.id, label: v.name }))}
  251. />
  252. </Form.Item>
  253. <Form.Item label="项目经理" name="snapPmUser">
  254. <Input
  255. style={{ width: 600 }}
  256. maxLength={30}
  257. showCount
  258. placeholder={
  259. isOk ? (pageType.txt === "look" ? "(空)" : "请输入内容") : ""
  260. }
  261. />
  262. </Form.Item>
  263. <Form.Item label="商务经理" name="snapBmUser">
  264. <Input
  265. style={{ width: 600 }}
  266. maxLength={30}
  267. showCount
  268. placeholder={
  269. isOk ? (pageType.txt === "look" ? "(空)" : "请输入内容") : ""
  270. }
  271. />
  272. </Form.Item>
  273. <Form.Item
  274. label="签订主体"
  275. name="dictMainId"
  276. >
  277. <Select
  278. placeholder={
  279. isOk ? (pageType.txt === "look" ? "(空)" : "请选择") : ""
  280. }
  281. style={{ width: 300 }}
  282. options={mainArr.map((v) => ({ value: v.id, label: v.name }))}
  283. />
  284. </Form.Item>
  285. <Form.Item
  286. label="业务部门"
  287. name="dictDeptId"
  288. >
  289. <Select
  290. placeholder={
  291. isOk ? (pageType.txt === "look" ? "(空)" : "请选择") : ""
  292. }
  293. style={{ width: 300 }}
  294. options={deptArr.map((v) => ({ value: v.id, label: v.name }))}
  295. />
  296. </Form.Item>
  297. <div className="form-item-group-one-row">
  298. <Form.Item
  299. label="是否投标"
  300. name="isBid"
  301. >
  302. <Radio.Group>
  303. <Radio value={0}>否</Radio>
  304. <Radio value={1}>是</Radio>
  305. </Radio.Group>
  306. </Form.Item>
  307. {pageType.txt !== 'look' && isBid ? (
  308. <Form.Item label="中标日期" name="bidDate"
  309. required={isBid === 1}
  310. >
  311. <DatePicker
  312. style={{ width: 300 }}
  313. disabled={isBid === 0}
  314. />
  315. </Form.Item>
  316. ) : (pageType.txt === "look" && lookInfo.isBid === 1) ? (
  317. <div>中标日期:{isOk ? lookInfo.bidDate : ""}</div>
  318. ) : (
  319. null
  320. )}
  321. </div>
  322. {pageType.txt === "look" ? (
  323. <div className="e_row">
  324. <div className="e_rowL">
  325. <span> </span>项目周期:
  326. </div>
  327. <div className="e_rowR e_rowRLook">
  328. {isOk
  329. ? lookInfo.dateScope
  330. ? lookInfo.dateScope
  331. : "(空)"
  332. : ""}
  333. </div>
  334. </div>
  335. ) : (
  336. <Form.Item label="项目周期" name="dateScope">
  337. <RangePicker style={{ width: 300 }} />
  338. </Form.Item>
  339. )}
  340. <Form.Item label="项目简介" name="description">
  341. <TextArea
  342. style={{ width: 600 }}
  343. autoSize
  344. placeholder={
  345. isOk ? (pageType.txt === "look" ? "(空)" : "请输入内容") : ""
  346. }
  347. showCount
  348. maxLength={500}
  349. />
  350. </Form.Item>
  351. {pageType.txt === "look" ? (
  352. <AuthCom aId="1082">
  353. <div className="e_row">
  354. <div className="e_rowL">
  355. <span> </span>项目金额:
  356. </div>
  357. <div className="e_rowR e_rowRLook">
  358. {isOk
  359. ? lookInfo.amount
  360. ? "¥" + lookInfo.amount
  361. : "(空)"
  362. : ""}
  363. </div>
  364. </div>
  365. </AuthCom>
  366. ) : (
  367. <Form.Item label="项目金额" name="amount">
  368. <InputNumber
  369. style={{ width: 300 }}
  370. addonBefore="¥"
  371. maxLength={10}
  372. placeholder="请输入数字,最多10位"
  373. />
  374. </Form.Item>
  375. )}
  376. {/* 新加的项目 创建人 */}
  377. <Form.Item
  378. label="创建人"
  379. name="creatorId"
  380. rules={[{ required: true, message: "请选择创建人!" }]}
  381. >
  382. <Select
  383. value={creatorIdValue}
  384. onChange={(e) => setCreatorIdValue(e)}
  385. placeholder={
  386. isOk ? (pageType.txt === "look" ? "(空)" : "请选择") : ""
  387. }
  388. style={{ width: 300 }}
  389. options={userList}
  390. />
  391. </Form.Item>
  392. {pageType.txt === "look" ? null : (
  393. <div
  394. className={classNames(
  395. "A1AtitTxt",
  396. creatorIdValue !== userInfo.id ? "A1AtitTxtShow" : ""
  397. )}
  398. >
  399. 创建人与当前用户不一致,请谨慎选择
  400. </div>
  401. )}
  402. <h3 className="form-item-group-title__porject-type">项目类型</h3>
  403. <div className="form-item-group__porject-type">
  404. {/* 表单项:业务类型,单选。 */}
  405. <Form.Item
  406. label="业务类型"
  407. name="dictProjectBusinessIds"
  408. tooltip="甲方的业务类型"
  409. >
  410. <Radio.Group>
  411. {projectBusinessArr.map((v) => (
  412. <Radio key={v.id} value={v.id}>
  413. <span title={v.description}>{v.name}</span>
  414. </Radio>
  415. ))}
  416. </Radio.Group>
  417. </Form.Item>
  418. {/* 表单项:项目范围,多选。 */}
  419. <Form.Item
  420. label="项目范围"
  421. name="dictProjectScopeIds"
  422. tooltip="项目的建设范围"
  423. >
  424. <Checkbox.Group>
  425. {projectScopeArr.map((v) => (
  426. <Checkbox key={v.id} value={v.id}>
  427. <span title={v.description}>{v.name}</span>
  428. </Checkbox>
  429. ))}
  430. </Checkbox.Group>
  431. </Form.Item>
  432. {/* 表单项:客户端,多选。 */}
  433. <Form.Item
  434. label="客户端"
  435. name="dictProjectAppIds"
  436. tooltip="项目成果的呈现载体"
  437. >
  438. <Checkbox.Group>
  439. {projectAppArr.map((v) => (
  440. <Checkbox key={v.id} value={v.id}>
  441. <span title={v.description}>{v.name}</span>
  442. </Checkbox>
  443. ))}
  444. </Checkbox.Group>
  445. </Form.Item>
  446. </div>
  447. {/* 确定和取消按钮 */}
  448. <div className="A1AddBtn">
  449. {pageType.txt === "look" ? null : (
  450. <>
  451. <Popconfirm
  452. title="放弃编辑后,信息将不会保存!"
  453. okText="放弃"
  454. cancelText="取消"
  455. onConfirm={closeFu}
  456. okButtonProps={{ loading: false }}
  457. >
  458. <Button>取消</Button>
  459. </Popconfirm>
  460. <Button type="primary" htmlType="submit">
  461. 保存
  462. </Button>
  463. </>
  464. )}
  465. </div>
  466. </Form>
  467. </div>
  468. </div>
  469. );
  470. }
  471. const MemoA1Add = React.memo(A1Add);
  472. export default MemoA1Add;