index.tsx 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  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 { Button, Cascader, Input, Select, Table, Tooltip } from "antd";
  10. import { useSelector } from "react-redux";
  11. import { RootState } from "@/store";
  12. import { A1_APIIgetList } from "@/store/action/A1Project";
  13. import { A1ItableType } from "@/types";
  14. import { authFilesLookFu, urlChangeFu } from "@/utils/authFilesLook";
  15. import A1IRemove from "./A1IRemove";
  16. import A1ILack from "./A1ILack";
  17. import A1IAudit from "./A1IAudit";
  18. import A1IupFile from "./A1IupFile";
  19. import { baseURL } from "@/utils/http";
  20. type FromType = {
  21. searchKey: string;
  22. attrId: number | "";
  23. deptId: any;
  24. auditStatus: 0 | 1 | 2 | "";
  25. projectId: number;
  26. };
  27. type Props = {
  28. projectId: number;
  29. myTitle:string
  30. };
  31. function A1Inner({ projectId,myTitle }: Props) {
  32. // 表单数据
  33. const [fromData, setFromData] = useState<FromType>({
  34. searchKey: "",
  35. attrId: "",
  36. deptId: [""],
  37. auditStatus: "",
  38. projectId,
  39. });
  40. // 关于表格的多选
  41. const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
  42. const getListFu = useCallback(async () => {
  43. // 处理级联为最后一级的id
  44. let deptId: "" | number = "";
  45. if (fromData.deptId && fromData.deptId[0]) {
  46. deptId = Number(fromData.deptId[fromData.deptId.length - 1]);
  47. }
  48. const obj = {
  49. ...fromData,
  50. deptId,
  51. };
  52. const res = await A1_APIIgetList(obj);
  53. if (res.code === 0) {
  54. // 清空选中
  55. setSelectedRowKeys([]);
  56. setData(res.data);
  57. }
  58. }, [fromData]);
  59. useEffect(() => {
  60. getListFu();
  61. }, [getListFu]);
  62. const fromTime = useRef(-1);
  63. // 搜索项 的输入
  64. const searchKeyChange = useCallback(
  65. (e: React.ChangeEvent<HTMLInputElement>) => {
  66. clearTimeout(fromTime.current);
  67. fromTime.current = window.setTimeout(() => {
  68. setFromData({
  69. ...fromData,
  70. searchKey: e.target.value,
  71. });
  72. }, 500);
  73. },
  74. [fromData]
  75. );
  76. // 从仓库获取文件类别数据
  77. const arr1 = useSelector((state: RootState) => state.A2Dict.A2Tab2Arr);
  78. // 从仓库获取部门 级联 信息
  79. const deptList = useSelector((state: RootState) => state.A5Section.tableList);
  80. // 表格信息
  81. const [data, setData] = useState<A1ItableType[]>([]);
  82. // 点击批量下载
  83. const downSelectFu = useCallback(async () => {
  84. // 清空选中
  85. setSelectedRowKeys([]);
  86. }, []);
  87. // 删除的弹窗数据
  88. const [delInfo, setDelInfo] = useState({ id: 0, name: "" });
  89. // 关于 审核
  90. const adidtDom = useCallback((item: A1ItableType) => {
  91. const num = item.auditStatus;
  92. const txt = num === 0 ? "待审批" : num === 1 ? "审批通过" : "审批驳回";
  93. const dom = item.auditDesc ? (
  94. <Tooltip title={item.auditDesc}>
  95. <div
  96. className="iconHoverTit A1ItablauidtBox"
  97. onClick={() =>
  98. setAuditInfo({ id: item.id, sta: num, txt: item.auditDesc || "" })
  99. }
  100. >
  101. {txt}&nbsp;
  102. <div className="iconHoverTitTxt">?</div>
  103. </div>
  104. </Tooltip>
  105. ) : (
  106. <div
  107. className="A1ItablauidtBox"
  108. onClick={() =>
  109. setAuditInfo({ id: item.id, sta: num, txt: item.auditDesc || "" })
  110. }
  111. >
  112. {txt}
  113. </div>
  114. );
  115. return dom;
  116. }, []);
  117. const columns = useMemo(() => {
  118. return [
  119. {
  120. title: "所属阶段",
  121. dataIndex: "stageName",
  122. },
  123. {
  124. title: "文件类别",
  125. dataIndex: "attrName",
  126. },
  127. {
  128. title: "责任部门",
  129. dataIndex: "deptName",
  130. },
  131. {
  132. title: "文件名称",
  133. render: (item: A1ItableType) =>
  134. item.hasLack === 1 ? (
  135. <>
  136. <Tooltip title={item.description}>
  137. <div className="iconHoverTit">
  138. 无法提供&nbsp;
  139. <div className="iconHoverTitTxt">?</div>
  140. </div>
  141. </Tooltip>
  142. </>
  143. ) : (
  144. item.fileName
  145. ),
  146. },
  147. {
  148. title: "上传人",
  149. dataIndex: "uploadName",
  150. },
  151. {
  152. title: "上传时间",
  153. dataIndex: "createTime",
  154. },
  155. {
  156. title: "审批状态",
  157. render: (item: A1ItableType) => adidtDom(item),
  158. },
  159. {
  160. title: "审核人",
  161. render: (item: A1ItableType) =>
  162. item.auditorName ? item.auditorName : "(空)",
  163. },
  164. {
  165. title: "审核时间",
  166. render: (item: A1ItableType) =>
  167. item.auditTime ? item.auditTime : "(空)",
  168. },
  169. {
  170. title: "操作",
  171. render: (item: A1ItableType) =>
  172. item.hasLack === 1 ? (
  173. "-"
  174. ) : (
  175. <>
  176. {authFilesLookFu(item.fileName) ? (
  177. <Button
  178. size="small"
  179. type="text"
  180. onClick={() => authFilesLookFu(item.fileName, item.filePath)}
  181. >
  182. 查看
  183. </Button>
  184. ) : null}
  185. <Button
  186. size="small"
  187. type="text"
  188. onClick={() =>
  189. urlChangeFu(item.filePath, true, undefined, item.fileName)
  190. }
  191. >
  192. 下载
  193. </Button>
  194. <Button
  195. size="small"
  196. type="text"
  197. danger
  198. onClick={() => setDelInfo({ id: item.id, name: item.fileName })}
  199. >
  200. 删除
  201. </Button>
  202. </>
  203. ),
  204. },
  205. ];
  206. }, [adidtDom]);
  207. // 登记缺失文件的开启和关闭
  208. const [lack, setLack] = useState(false);
  209. // 审批状态的开启和关闭
  210. const [auditInfo, setAuditInfo] = useState<{
  211. id: number;
  212. sta: 0 | 1 | 2;
  213. txt: string;
  214. }>({
  215. id: 0,
  216. sta: 0,
  217. txt: "",
  218. });
  219. // 批量上传的弹窗
  220. const [upFileOpen, setUpFileOpen] = useState(false);
  221. return (
  222. <div className={styles.A1Inner}>
  223. <div className="A1Itop">
  224. <div className="A1ItopRow">
  225. <span>搜索项:</span>
  226. <Input
  227. maxLength={30}
  228. style={{ width: 210 }}
  229. placeholder="请输入文件名称,最多30字"
  230. allowClear
  231. onChange={(e) => searchKeyChange(e)}
  232. />
  233. </div>
  234. <div className="A1ItopRow">
  235. <span>文件类别:</span>
  236. <Select
  237. style={{ width: 120 }}
  238. value={fromData.attrId}
  239. onChange={(e) => setFromData({ ...fromData, attrId: e })}
  240. options={[
  241. { value: "", label: "全部" },
  242. ...arr1.map((v) => ({ value: v.id, label: v.name })),
  243. ]}
  244. />
  245. </div>
  246. <div className="A1ItopRow">
  247. <span>审批状态:</span>
  248. <Select
  249. style={{ width: 120 }}
  250. value={fromData.auditStatus}
  251. onChange={(e) => setFromData({ ...fromData, auditStatus: e })}
  252. options={[
  253. { value: "", label: "全部" },
  254. { value: 0, label: "待审批" },
  255. { value: 1, label: "审批通过" },
  256. { value: 2, label: "审批驳回" },
  257. ]}
  258. />
  259. </div>
  260. <div className="A1ItopRow">
  261. <span>责任部门:</span>
  262. <Cascader
  263. allowClear={false}
  264. style={{ width: 200 }}
  265. options={[{ id: "", name: "全部" }, ...deptList]}
  266. value={fromData.deptId}
  267. onChange={(e) => setFromData({ ...fromData, deptId: e })}
  268. fieldNames={{ label: "name", value: "id" }}
  269. placeholder="请选择"
  270. />
  271. </div>
  272. <div className="A1ItopRow A1ItopRow2">
  273. <Button type="primary" onClick={() => setLack(true)}>
  274. 登记缺失文件
  275. </Button>
  276. &emsp;
  277. <Button type="primary" onClick={() => setUpFileOpen(true)}>
  278. 批量上传
  279. </Button>
  280. &emsp;
  281. <Button
  282. type="primary"
  283. onClick={downSelectFu}
  284. disabled={selectedRowKeys.length <= 0}
  285. >
  286. 批量下载
  287. </Button>
  288. </div>
  289. </div>
  290. <div className="A1ItableBox">
  291. <Table
  292. rowSelection={{
  293. type: "checkbox",
  294. selectedRowKeys,
  295. onChange: (selectedRowKeys: React.Key[]) => {
  296. setSelectedRowKeys(selectedRowKeys);
  297. },
  298. // 禁用
  299. getCheckboxProps: (item) => ({
  300. disabled: item.hasLack === 1, // 配置无法勾选的列
  301. }),
  302. }}
  303. scroll={{ y: 666 }}
  304. dataSource={data}
  305. columns={columns}
  306. rowKey="id"
  307. pagination={false}
  308. />
  309. </div>
  310. {/* 点击删除出来的弹窗 */}
  311. {delInfo.id ? (
  312. <A1IRemove
  313. mId={delInfo.id}
  314. name={delInfo.name}
  315. colseFu={() => setDelInfo({ id: 0, name: "" })}
  316. delSuFu={() => getListFu()}
  317. />
  318. ) : null}
  319. {/* 点击登记缺失文件出来的弹窗 */}
  320. {lack ? (
  321. <A1ILack
  322. projectId={projectId}
  323. closeFu={() => setLack(false)}
  324. addSuFu={() => getListFu()}
  325. />
  326. ) : null}
  327. {/* 点击审批出来的弹窗 */}
  328. {auditInfo.id ? (
  329. <A1IAudit
  330. info={auditInfo}
  331. closeFu={() => setAuditInfo({ id: 0, sta: 0, txt: "" })}
  332. editSuFu={() => getListFu()}
  333. />
  334. ) : null}
  335. {upFileOpen ? (
  336. <A1IupFile
  337. myUrl={`${baseURL}cms/inside/upload/${projectId}`}
  338. upFileFu={() => getListFu()}
  339. closeFu={() => setUpFileOpen(false)}
  340. myTitle={myTitle}
  341. projectId={projectId}
  342. />
  343. ) : null}
  344. </div>
  345. );
  346. }
  347. const MemoA1Inner = React.memo(A1Inner);
  348. export default MemoA1Inner;