shaogen1995 2 年之前
父节点
当前提交
0527141114

+ 132 - 0
src/pages/A1Project/A1Inner/A1IAudit.tsx

@@ -0,0 +1,132 @@
+import React, { useCallback, useEffect, useState } from "react";
+import styles from "./index.module.scss";
+import { Button, Modal, Popconfirm } from "antd";
+import TextArea from "antd/es/input/TextArea";
+import { MessageFu } from "@/utils/message";
+import { A1_APIIaudit } from "@/store/action/A1Project";
+
+const stateBtnArr = [
+  { id: 1, name: "审批通过" },
+  { id: 2, name: "审批驳回" },
+];
+
+type Props = {
+  info: { id: number; sta: 0 | 1 | 2; txt: string };
+  closeFu: () => void;
+  editSuFu: () => void;
+};
+
+function A1IAudit({ info, closeFu, editSuFu }: Props) {
+  // 备注
+  const [value, setValue] = useState("");
+
+  // 审批状态
+  const [state, setState] = useState<0 | 1 | 2>(0);
+
+  useEffect(() => {
+    setState(info.sta);
+    setValue(info.txt)
+  }, [info.sta, info.txt]);
+
+  // 点击确定
+  const btnOk = useCallback(async () => {
+    const obj = {
+      audit: state,
+      description: value,
+      id: info.id,
+    };
+
+    const res = await A1_APIIaudit(obj);
+
+    if (res.code === 0) {
+      MessageFu.success("审核成功!");
+      editSuFu();
+      closeFu();
+    }
+  }, [closeFu, editSuFu, info.id, state, value]);
+
+  return (
+    <Modal
+      wrapClassName={styles.A1IAudit}
+      destroyOnClose
+      open={true}
+      title="审批"
+      footer={
+        [] // 设置footer为空,去掉 取消 确定默认按钮
+      }
+    >
+      <div className="A1IAmain">
+        <div className="A1IAmainRow">
+          <div className="A1IAmainRow1">
+            <span> </span> 当前状态:
+          </div>
+          <div className="A1IAmainRow2">
+            {info.sta === 0
+              ? "待审批"
+              : info.sta === 1
+              ? "审批通过"
+              : "审批驳回"}
+          </div>
+        </div>
+
+        <div className="A1IAmainRow">
+          <div className="A1IAmainRow1 A1IAmainRow1_2">
+            <span>*</span> 审批状态:
+          </div>
+          <div className="A1IAmainRow2">
+            {stateBtnArr.map((v) => (
+              <div key={v.id}>
+                <Button
+                  onClick={() => setState(v.id as 1 | 2)}
+                  type={v.id === state ? "primary" : "default"}
+                >
+                  {v.name}
+                </Button>
+              </div>
+            ))}
+          </div>
+        </div>
+
+        <div className="A1IAmainRow">
+          <div className="A1IAmainRow1">
+            <span> </span> 备注:
+          </div>
+          <div className="A1IAmainRow2">
+            <TextArea
+              rows={4}
+              placeholder="请输入内容"
+              maxLength={100}
+              showCount
+              value={value}
+              onChange={(e) => setValue(e.target.value.replace(/\s+/g, ""))}
+            />
+          </div>
+        </div>
+
+        <div className="A1IABtn">
+          <Popconfirm
+            title="放弃编辑后,信息将不会保存!"
+            okText="放弃"
+            cancelText="取消"
+            onConfirm={closeFu}
+            okButtonProps={{ loading: false }}
+          >
+            <Button>取消</Button>
+          </Popconfirm>
+          &emsp;
+          <Button
+            type="primary"
+            onClick={btnOk}
+            disabled={state !== 1 && state !== 2}
+          >
+            确定
+          </Button>
+        </div>
+      </div>
+    </Modal>
+  );
+}
+
+const MemoA1IAudit = React.memo(A1IAudit);
+
+export default MemoA1IAudit;

+ 176 - 0
src/pages/A1Project/A1Inner/A1ILack.tsx

@@ -0,0 +1,176 @@
+import React, { useCallback, useEffect, useState } from "react";
+import styles from "./index.module.scss";
+import { Button, Checkbox, Empty, Input, Modal, Popconfirm } from "antd";
+import { A1_APIIgetLack, A1_APIIsaveLack } from "@/store/action/A1Project";
+import { A1IlackType } from "@/types";
+import classNames from "classnames";
+import { MessageFu } from "@/utils/message";
+
+type Props = {
+  closeFu: () => void;
+  addSuFu: () => void;
+  projectId: number;
+};
+
+function A1ILack({ closeFu, addSuFu, projectId }: Props) {
+  // 进来获取 根据 项目id 获取 列表信息
+
+  const getInfoFu = useCallback(async () => {
+    const res = await A1_APIIgetLack(projectId);
+
+    if (res.code === 0) {
+      const arr: A1IlackType[] = res.data;
+      setData(
+        arr.map((v) => ({
+          ...v,
+          done: false,
+        }))
+      );
+    }
+  }, [projectId]);
+
+  useEffect(() => {
+    getInfoFu();
+  }, [getInfoFu]);
+
+  // 渲染的数组
+  const [data, setData] = useState<A1IlackType[]>([]);
+
+  // 勾选框的变化
+  const selceFu = useCallback(
+    (id: number, val: boolean) => {
+      setData(
+        data.map((v) => ({
+          ...v,
+          done: v.attributeId === id ? val : v.done,
+        }))
+      );
+    },
+    [data]
+  );
+
+  // 输入框的变化
+  // setValue(e.target.value.replace(/\s+/g, ""))
+  const descChangeFu = useCallback(
+    (id: number, val: string) => {
+      setData(
+        data.map((v) => ({
+          ...v,
+          desc: v.attributeId === id ? val.replace(/\s+/g, "") : v.desc,
+        }))
+      );
+    },
+    [data]
+  );
+
+  // 点击确定
+  const btnOk = useCallback(async () => {
+    // 过滤掉已经 上传的 没有输入的
+    const arr = data.filter((v) => v.desc && v.done);
+
+    const arr2 = arr.map((v) => ({
+      attributeId: v.attributeId,
+      description: v.desc,
+    }));
+
+    const res = await A1_APIIsaveLack(projectId, arr2);
+
+    if (res.code === 0) {
+      MessageFu.success("登记成功!");
+      addSuFu();
+      closeFu();
+    }
+  }, [addSuFu, closeFu, data, projectId]);
+
+  return (
+    <Modal
+      wrapClassName={styles.A1ILack}
+      destroyOnClose
+      open={true}
+      title="登记缺失文件"
+      footer={
+        [] // 设置footer为空,去掉 取消 确定默认按钮
+      }
+    >
+      <div className="A1ILmain">
+        <div className="A1ILmain1">请勾选后再填写</div>
+
+        {/* 主体 */}
+
+        {data.length >= 1 ? (
+          <div className="A1ILmainC">
+            {data.map((v) => (
+              <div className="A1ILmainCRow" key={v.attributeId}>
+                <div
+                  className={classNames(
+                    "A1ILmainCRow1",
+                    v.hasUpload ? "A1ILmainCRow1No" : ""
+                  )}
+                >
+                  <Checkbox
+                    checked={v.done}
+                    onChange={(e) => selceFu(v.attributeId, e.target.checked)}
+                  >
+                    <div className="A1ILmainCRow1Txt" title={v.attributeName}>
+                      {v.attributeName}
+                    </div>
+                    <div className="A1ILmainCRow1Txt2">:</div>
+                  </Checkbox>
+                </div>
+                <div className="A1ILmainCRow2">
+                  {v.hasUpload ? (
+                    "已上传"
+                  ) : (
+                    <Input
+                      disabled={!v.done}
+                      placeholder="请输入缺失原因,为空则不会录入系统"
+                      maxLength={100}
+                      showCount
+                      value={v.desc}
+                      onChange={(e) =>
+                        descChangeFu(v.attributeId, e.target.value)
+                      }
+                    />
+                  )}
+                </div>
+              </div>
+            ))}
+          </div>
+        ) : (
+          <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
+        )}
+
+        {/* 底部按钮 */}
+        <div className="A1ILbtn">
+          {data.length >= 1 ? (
+            <>
+              <Popconfirm
+                title="放弃编辑后,信息将不会保存!"
+                okText="放弃"
+                cancelText="取消"
+                onConfirm={closeFu}
+                okButtonProps={{ loading: false }}
+              >
+                <Button>取消</Button>
+              </Popconfirm>
+              &emsp;
+              <Button
+                type="primary"
+                onClick={btnOk}
+                disabled={data.filter((v) => v.done).length < 1}
+              >
+                确定
+              </Button>
+            </>
+          ) : (
+            <Button onClick={closeFu}> 取消</Button>
+          )}
+        </div>
+      </div>
+    </Modal>
+  );
+}
+
+const MemoA1ILack = React.memo(A1ILack);
+
+export default MemoA1ILack;

+ 90 - 0
src/pages/A1Project/A1Inner/A1IRemove.tsx

@@ -0,0 +1,90 @@
+import React, { useCallback, useState } from "react";
+import styles from "./index.module.scss";
+import { Button, Modal, Popconfirm } from "antd";
+import TextArea from "antd/es/input/TextArea";
+import { MessageFu } from "@/utils/message";
+import { A1_APIIdel } from "@/store/action/A1Project";
+
+type Props = {
+  mId: number;
+  name: string;
+  colseFu: () => void;
+  delSuFu: () => void;
+};
+
+function A1IRemove({ mId, name, colseFu, delSuFu }: Props) {
+  const [value, setValue] = useState("");
+
+  // 点击删除
+  const delById = useCallback(async () => {
+    if (!value) return MessageFu.warning("删除原因不能为空!");
+
+    const obj = {
+      id: mId,
+      description: value,
+    };
+
+    const res = await A1_APIIdel(obj);
+
+    if (res.code === 0) {
+      MessageFu.success("删除成功,已移动文件到回收站!");
+      delSuFu();
+      colseFu();
+    }
+  }, [colseFu, delSuFu, mId, value]);
+
+  return (
+    <Modal
+      wrapClassName={styles.A1IRemove}
+      destroyOnClose
+      open={true}
+      title={`删除内控文件-${name}`}
+      footer={
+        [] // 设置footer为空,去掉 取消 确定默认按钮
+      }
+    >
+      <div className="A1IRmain">
+        <div className="A1IRmainRow">
+          <div className="A1IRmainRow1">
+            <span>* </span>删除原因:
+          </div>
+          <div className="A1IRmainRow2">
+            <TextArea
+              rows={4}
+              placeholder="请输入内容"
+              maxLength={100}
+              showCount
+              value={value}
+              onChange={(e) => setValue(e.target.value.replace(/\s+/g, ""))}
+            />
+            <div className="A1IRmainRow2Tit">
+              误删除的文档可联系管理员进行恢复
+            </div>
+          </div>
+        </div>
+
+        <div className="A1IRBtn">
+          <Button onClick={colseFu}>取消</Button>
+          &emsp;
+          <Popconfirm
+            disabled={!value}
+            title="确定删除吗?"
+            okText="删除"
+            cancelText="取消"
+            onConfirm={delById}
+            okButtonProps={{ loading: false }}
+          >
+            <Button type="primary" disabled={!value}>
+              删除
+            </Button>
+          </Popconfirm>
+          &emsp;
+        </div>
+      </div>
+    </Modal>
+  );
+}
+
+const MemoA1IRemove = React.memo(A1IRemove);
+
+export default MemoA1IRemove;

+ 144 - 0
src/pages/A1Project/A1Inner/A1IupFile/index.module.scss

@@ -0,0 +1,144 @@
+.A1IupFile {
+  :global {
+
+    .ant-modal-close {
+      display: none;
+    }
+
+    .ant-modal {
+      width: 800px !important;
+    }
+
+    .A1OMain {
+      padding: 15px 40px 0;
+      margin-top: 10px;
+      border-top: 1px solid #999999;
+      position: relative;
+      height: 500px;
+      overflow-y: auto;
+
+      .ant-upload-drag {
+        height: 160px;
+      }
+
+      .ant-upload-list-item-container {
+        transition: none !important;
+        height: 40px !important;
+      }
+
+      .ant-upload-list-item-action {
+        // display: none !important;
+        opacity: 1 !important;
+      }
+
+      .ant-upload-list-item-actions .anticon {
+        color: #ff4d4f !important;
+      }
+
+      .ant-upload-list-item-name {
+        width: calc(100% - 538px) !important;
+        transition: none !important;
+        flex: none !important;
+        margin-right: 506px;
+      }
+
+      .ant-upload-list-item-container {
+        margin-bottom: 15px;
+      }
+
+
+      .myIncoBox {
+        position: absolute;
+        right: 65px;
+        top: 174px;
+
+        .myIncoRow {
+          margin-bottom: 15px;
+          height: 40px;
+          line-height: 40px;
+          font-size: 14px;
+          display: flex;
+          justify-content: flex-end;
+          position: relative;
+
+          &>div {
+            cursor: pointer;
+            margin-left: 12px;
+
+            a {
+              position: relative;
+              top: -1px;
+              color: #333;
+            }
+          }
+
+          .mySortQ {
+            cursor: default;
+            position: absolute;
+            z-index: 15;
+            right: 470px;
+            top: -1px;
+            font-size: 12px;
+            height: 30px;
+
+          }
+
+          // 下拉框
+          .A1IUselect {
+            max-lines: 0;
+            cursor: default;
+            position: absolute;
+            left: -460px;
+            top: 0px;
+            z-index: 10;
+
+            .A1IUselectTit {
+              font-size: 12px;
+              position: absolute;
+              top: 25px;
+              left: -126px;
+              z-index: -1;
+              width: 650px;
+
+              .A1IUselectTit1 {
+                color: #ff4d4f;
+              }
+
+              .A1IUselectTit2 {
+                width: 100%;
+                display: flex;
+
+                &>div {
+                  flex: 1;
+                  cursor: pointer;
+                  overflow: hidden;
+                  text-overflow: ellipsis;
+                  white-space: nowrap;
+                }
+
+                .A1IUselectTit2Tit {
+                  color: #ff4d4f;
+                }
+              }
+            }
+          }
+
+        }
+
+
+
+      }
+
+    }
+
+    .A1OUpBtn {
+      padding-top: 20px;
+      text-align: center;
+    }
+
+    // .ant-upload-list-item-done{
+    //   justify-content: space-between !important;
+    // }
+
+  }
+}

+ 385 - 0
src/pages/A1Project/A1Inner/A1IupFile/index.tsx

@@ -0,0 +1,385 @@
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+import styles from "./index.module.scss";
+
+import { InboxOutlined } from "@ant-design/icons";
+import {
+  Button,
+  message,
+  Modal,
+  Popconfirm,
+  Select,
+  Upload,
+  UploadFile,
+  UploadProps,
+} from "antd";
+
+import { EyeOutlined, DownloadOutlined } from "@ant-design/icons";
+
+import history from "@/utils/history";
+import React from "react";
+import { getTokenFu } from "@/utils/storage";
+import { MessageFu } from "@/utils/message";
+import { A1_APIOupFileIds, A1_APIremoveSure } from "@/store/action/A1Project";
+import { authFilesLookFu, urlChangeFu } from "@/utils/authFilesLook";
+import { useSelector } from "react-redux";
+import { RootState } from "@/store";
+
+const { Dragger } = Upload;
+
+type SelectType = {
+  id: string;
+  value: number | undefined;
+  txt: string;
+  tit: string;
+  fileName: string;
+};
+
+type props = {
+  myUrl: string;
+  upFileFu: () => void;
+  closeFu: () => void;
+};
+
+function A1IupFile({ myUrl, closeFu, upFileFu }: props) {
+  // 从仓库获取 内控文件 属性
+  const typeData = useSelector((state: RootState) => state.A2Dict.A2Tab2Arr);
+
+  const [typeSelect, setTypeSelect] = useState([] as SelectType[]);
+
+  useEffect(() => {
+    console.log("pppppppp", typeSelect);
+  }, [typeSelect]);
+
+  // 下拉框改变
+  const selectChangeFu = useCallback(
+    (val: number, id: string) => {
+      const info = typeData.find((v) => v.id === val)!;
+
+      const tit = info.suffix ? info.suffix : "all";
+
+      setTypeSelect(
+        typeSelect.map((v) => ({
+          ...v,
+          value: v.id === id ? val : v.value,
+          txt: v.id === id ? info.description : v.txt,
+          tit: v.id === id ? tit : v.tit,
+        }))
+      );
+    },
+    [typeData, typeSelect]
+  );
+
+  // 校验指定格式
+  const typeGeShiFlag = useCallback((val: string, name: string) => {
+    if (val === "all") return false;
+    else {
+      let flag = true;
+
+      const arr = val.split(",");
+
+      arr.forEach((v) => {
+        if (name.includes("." + v)) flag = false;
+      });
+
+      return flag;
+    }
+  }, []);
+
+  // 确定按钮的格式校验
+  const disBtnOkRes = useMemo(() => {
+    let flag = false;
+    typeSelect.forEach((v) => {
+      if (v.tit !== "all") {
+        const arr = v.tit.split(","); //['pdf','gif']
+
+        const arr2 = v.fileName.split(".");
+
+        const str = arr2[arr2.length - 1]; //66666.pdf  =>pdf
+
+        if (arr.every((v2) => v2 !== str)) flag = true;
+      }
+    });
+    return flag;
+  }, [typeSelect]);
+
+  const [modal, contextHolder] = Modal.useModal();
+
+  const [fileList, setFileList] = useState<UploadFile[]>([]);
+
+  const timeRef = useRef(-1);
+
+  const FileProps: UploadProps = {
+    name: "file",
+    multiple: true,
+    action: myUrl,
+    headers: {
+      token: getTokenFu(),
+    },
+    // 支持上传文件夹
+    directory: true,
+    fileList,
+    //不要前面的图标
+    // iconRender: () => false,
+    // 文件上传之前 -- 这里不用校验
+    // beforeUpload(file, fileList) {
+    //   // console.log("文件上传之前-用于校验", file);
+    //   // if (file.fileName.includes("4dage")) {
+    //   //   // console.log("校验不通过,不上传");
+    //   //   message.error(`${file.fileName}不符合上传需求`);
+    //   //   return Upload.LIST_IGNORE;
+    //   // }
+    // },
+    onChange(info) {
+      setFileList([...info.fileList]);
+
+      const { status } = info.file;
+      if (status !== "uploading") {
+        // 检查请求状态
+        const response = info.file.response || {};
+
+        if (response.code !== 0) {
+          clearTimeout(timeRef.current);
+
+          timeRef.current = window.setTimeout(() => {
+            setFileList(info.fileList.filter((v) => v.uid !== info.file.uid));
+          }, 100);
+        }
+        if (response.code === 5001 || response.code === 5002) {
+          message.warning("登录失效!");
+          history.push("/login");
+          return false;
+        }
+
+        // console.log(info.file, info.fileList);
+      }
+      if (status === "done") {
+        // console.log("-----", info);
+
+        setTypeSelect([
+          ...typeSelect,
+          {
+            id: info.file.response.data.id,
+            value: undefined,
+            txt: "",
+            tit: "",
+            fileName: info.file.name,
+          },
+        ]);
+
+        // message.success(`${info.file.fileName} 上传成功.`);
+      } else if (status === "error") {
+        message.error(`${info.file.fileName} 上传失败.`);
+        // 去掉列表中的失败状态文件
+        clearTimeout(timeRef.current);
+
+        timeRef.current = window.setTimeout(() => {
+          setFileList(info.fileList.filter((v) => v.uid !== info.file.uid));
+        }, 100);
+      }
+    },
+    // onDrop(e) {
+    //   // console.log("拖动文件到上传区域", e.dataTransfer.files);
+    // },
+    // 点击删除
+    async onRemove(info) {
+      const promiseFu = new Promise((resolve: (value: boolean) => void) => {
+        modal.confirm({
+          title: "删除确认",
+          content: "删除后无法恢复,是否删除?",
+          okText: "删除",
+          cancelText: "取消",
+          async onOk() {
+            if (info.percent === 100) {
+              // console.log("-----还没有发请求删除", info);
+              const id = info.response.data.id;
+              // 已经上传完成,发请求删除
+              const res = await A1_APIremoveSure([id + ""]);
+
+              if (res.code === 0) {
+                setTypeSelect(typeSelect.filter((v) => v.id !== id));
+                resolve(true);
+                MessageFu.success("删除成功!");
+              }
+            } else {
+              resolve(true);
+              MessageFu.success("删除成功!");
+            }
+          },
+          onCancel() {
+            resolve(false);
+          },
+        });
+      });
+      return await promiseFu;
+    },
+  };
+
+  // 点击确定
+  const btnOkFu = useCallback(async () => {
+    if (fileList.some((v) => v.percent !== 100))
+      return message.warning("有文件未上传完成.");
+
+    // 拿到 id集合
+
+    const ids: number[] = [];
+
+    fileList.forEach((v) => {
+      ids.push(v.response.data.id);
+    });
+
+    const res = await A1_APIOupFileIds(ids.join(","));
+
+    if (res.code === 0) {
+      MessageFu.success("保存成功!");
+      upFileFu();
+      closeFu();
+    }
+  }, [closeFu, fileList, upFileFu]);
+
+  return (
+    <Modal
+      wrapClassName={styles.A1IupFile}
+      destroyOnClose
+      open={true}
+      title="内控文件上传"
+      footer={
+        [] // 设置footer为空,去掉 取消 确定默认按钮
+      }
+    >
+      <div className="A1OMain">
+        <Dragger {...FileProps}>
+          <p className="ant-upload-drag-icon">
+            <InboxOutlined rev={undefined} />
+          </p>
+          <br />
+          <p className="ant-upload-text">
+            点击上传整个文件夹,或拖动多个文件至此上传
+          </p>
+        </Dragger>
+        {/* 自定义 预览 下载 删除 */}
+        <div className="myIncoBox">
+          {fileList.map((v, i) => (
+            <div className="myIncoRow" key={v.uid}>
+              {v.percent === 100 && v.response && v.response.data ? (
+                <>
+                  {authFilesLookFu(v.response.data.fileName) ? (
+                    <>
+                      {/* // 1.预览(fileName里面有常用的,浏览器能识别的 图片 音频 视频 模型) */}
+                      <div title="预览文件">
+                        <EyeOutlined
+                          rev={undefined}
+                          onClick={() =>
+                            authFilesLookFu(
+                              v.response.data.fileName,
+                              v.response.data.filePath
+                            )
+                          }
+                        />
+                      </div>
+                    </>
+                  ) : null}
+                  {/* // 2.下载 */}
+                  <div
+                    title="下载文件"
+                    onClick={() =>
+                      urlChangeFu(
+                        v.response.data.filePath,
+                        true,
+                        undefined,
+                        v.response.data.fileName
+                      )
+                    }
+                  >
+                    <DownloadOutlined rev={undefined} />
+                  </div>
+
+                  {/* 下拉框 */}
+                  <div className="A1IUselect">
+                    <Select
+                      style={{ width: 200 }}
+                      placeholder="请选择"
+                      value={typeSelect[i] ? typeSelect[i].value : undefined}
+                      onChange={(e) => selectChangeFu(e, typeSelect[i].id)}
+                      options={typeData.map((v) => ({
+                        value: v.id,
+                        label: v.name,
+                      }))}
+                    />
+
+                    {/* 没选择的时候的提示 */}
+                    <div className="A1IUselectTit">
+                      {typeSelect[i] && typeSelect[i].value ? (
+                        <div className="A1IUselectTit2">
+                          <div title={typeSelect[i].txt}>
+                            {typeSelect[i].txt}
+                          </div>
+
+                          {typeGeShiFlag(
+                            typeSelect[i].tit,
+                            typeSelect[i].fileName
+                          ) ? (
+                            <div
+                              className="A1IUselectTit2Tit"
+                              title={`该文件类型只支持 ${typeSelect[i].tit}`}
+                            >
+                              &emsp;该文件类型只支持 {typeSelect[i].tit} 格式
+                            </div>
+                          ) : null}
+
+                          {/* {typeSelect[i].tit !== "all" &&
+                          typeSelect[i].fileName.includes(typeSelect[i].tit) ? (
+                            
+                          ) : (
+                            ""
+                          )} */}
+                        </div>
+                      ) : (
+                        <div className="A1IUselectTit1">请选择文件类型</div>
+                      )}
+                    </div>
+                  </div>
+                </>
+              ) : (
+                ""
+              )}
+
+              {/* 3.前面的序号 */}
+              {/* <div className="mySortQ" hidden={fileList.length <= 1}>
+                {i + 1}.
+              </div> */}
+            </div>
+          ))}
+        </div>
+      </div>
+
+      <div className="A1OUpBtn">
+        <Popconfirm
+          title="放弃编辑后,信息将不会保存!"
+          okText="放弃"
+          cancelText="取消"
+          onConfirm={closeFu}
+          okButtonProps={{ loading: false }}
+        >
+          <Button>取消</Button>
+        </Popconfirm>
+        &emsp;
+        <Button
+          type="primary"
+          onClick={btnOkFu}
+          disabled={
+            fileList.length <= 0 ||
+            typeSelect.some((v) => !v.value) ||
+            disBtnOkRes
+          }
+        >
+          确定
+        </Button>
+      </div>
+
+      {contextHolder}
+    </Modal>
+  );
+}
+
+const MemoA1IupFile = React.memo(A1IupFile);
+export default MemoA1IupFile;

+ 248 - 0
src/pages/A1Project/A1Inner/index.module.scss

@@ -0,0 +1,248 @@
+.A1Inner {
+  width: 100%;
+  height: 100%;
+
+  :global {
+    .A1Itop {
+      padding: 0 30px 0 5px;
+      margin-top: 15px;
+      display: flex;
+      position: relative;
+
+      .A1ItopRow {
+        margin-right: 20px;
+
+        &:last-child {
+          margin-right: 0;
+        }
+      }
+
+      .A1ItopRow2 {
+        position: absolute;
+        right: 0px;
+        top: 0px;
+        z-index: 10;
+      }
+    }
+
+
+    .A1ItableBox {
+      margin-top: 15px;
+      height: calc(100% - 57px);
+      overflow: hidden;
+
+      .ant-table-body {
+        height: 666px;
+        overflow-y: auto !important;
+
+        .ant-table-row {
+          .ant-table-cell {
+            padding: 10px 8px;
+          }
+        }
+      }
+    }
+
+    .iconHoverTit {
+      cursor: pointer;
+    }
+
+    .A1ItablauidtBox {
+      cursor: pointer;
+      color: var(--themeColor);
+
+      &:hover {
+        text-decoration: underline;
+      }
+    }
+  }
+}
+
+
+// ------删除的弹窗样式
+.A1IRemove {
+  :global {
+    .ant-modal-close {
+      display: none;
+    }
+
+    .A1IRmain {
+      width: 100%;
+      border-top: 1px solid #999999;
+      padding-top: 20px;
+
+
+      .A1IRmainRow {
+        display: flex;
+
+        .A1IRmainRow1 {
+          width: 80px;
+          text-align: right;
+
+          &>span {
+            color: #ff4d4f;
+          }
+        }
+
+        .A1IRmainRow2 {
+          width: calc(100% - 80px);
+
+          .A1IRmainRow2Tit {
+            color: #999;
+          }
+        }
+      }
+
+
+      .A1IRBtn {
+        width: 100%;
+        display: flex;
+        justify-content: center;
+        margin-top: 30px;
+      }
+    }
+  }
+}
+
+
+// -------登记缺失文件 弹窗 样式
+.A1ILack {
+  :global {
+    .ant-modal-close {
+      display: none;
+    }
+
+    .ant-modal {
+      width: 800px !important;
+    }
+
+    .A1ILmain {
+      width: 100%;
+      margin-top: 15px;
+      border-top: 1px solid #999999;
+
+      .A1ILmain1 {
+        color: #999;
+        margin-bottom: 20px;
+      }
+
+      .A1ILmainC {
+        max-height: 500px;
+        overflow-y: auto;
+
+        .A1ILmainCRow {
+          display: flex;
+          align-items: center;
+          margin-bottom: 20px;
+          height: 32px;
+
+          .A1ILmainCRow1 {
+            width: 140px;
+
+            label {
+              width: 140px;
+
+              &>span {
+                &:last-child {
+                  width: calc(100% - 16px);
+                  padding: 0 3px;
+                  display: flex;
+
+                  .A1ILmainCRow1Txt {
+                    max-width: calc(100% - 15px);
+                    overflow: hidden;
+                    text-overflow: ellipsis;
+                    white-space: nowrap;
+                  }
+                }
+              }
+            }
+
+          }
+
+          .A1ILmainCRow1No {
+            label {
+              pointer-events: none;
+
+              &>span {
+                &:first-child {
+                  opacity: 0;
+                }
+              }
+            }
+          }
+
+          .A1ILmainCRow2 {
+            width: calc(100% - 140px);
+            display: flex;
+            align-items: center;
+
+            input {
+              color: var(--themeColor);
+            }
+
+          }
+        }
+      }
+
+      .A1ILbtn {
+        width: 100%;
+        display: flex;
+        justify-content: center;
+        margin-top: 20px;
+      }
+
+    }
+
+  }
+}
+
+// -------审批的 弹窗 样式
+.A1IAudit {
+  :global {
+    .ant-modal-close {
+      display: none;
+    }
+
+    .A1IAmain {
+      width: 100%;
+      border-top: 1px solid #999999;
+      padding-top: 20px;
+
+
+      .A1IAmainRow {
+        display: flex;
+        margin-bottom: 20px;
+
+        .A1IAmainRow1 {
+          width: 80px;
+          text-align: right;
+
+          &>span {
+            color: #ff4d4f;
+          }
+        }
+        .A1IAmainRow1_2{
+          padding-top: 4px;
+        }
+
+        .A1IAmainRow2 {
+          width: calc(100% - 80px);
+          display: flex;
+          &>div{
+            margin-right: 20px;
+          }
+        }
+      }
+
+
+      .A1IABtn {
+        width: 100%;
+        display: flex;
+        justify-content: center;
+        margin-top: 30px;
+      }
+    }
+  }
+
+}

+ 381 - 0
src/pages/A1Project/A1Inner/index.tsx

@@ -0,0 +1,381 @@
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
+import styles from "./index.module.scss";
+import { Button, Cascader, Input, Select, Table, Tooltip } from "antd";
+import { useSelector } from "react-redux";
+import { RootState } from "@/store";
+import { A1_APIIgetList } from "@/store/action/A1Project";
+import { A1ItableType } from "@/types";
+import { authFilesLookFu, urlChangeFu } from "@/utils/authFilesLook";
+import A1IRemove from "./A1IRemove";
+import A1ILack from "./A1ILack";
+import A1IAudit from "./A1IAudit";
+import A1IupFile from "./A1IupFile";
+import { baseURL } from "@/utils/http";
+
+type FromType = {
+  searchKey: string;
+  attrId: number | "";
+  deptId: any;
+  auditStatus: 0 | 1 | 2 | "";
+  projectId: number;
+};
+
+type Props = {
+  projectId: number;
+};
+
+function A1Inner({ projectId }: Props) {
+  // 表单数据
+  const [fromData, setFromData] = useState<FromType>({
+    searchKey: "",
+    attrId: "",
+    deptId: [""],
+    auditStatus: "",
+    projectId,
+  });
+  // 关于表格的多选
+  const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
+
+  const getListFu = useCallback(async () => {
+    // 处理级联为最后一级的id
+    let deptId: "" | number = "";
+
+    if (fromData.deptId && fromData.deptId[0]) {
+      deptId = Number(fromData.deptId[fromData.deptId.length - 1]);
+    }
+
+    const obj = {
+      ...fromData,
+      deptId,
+    };
+    const res = await A1_APIIgetList(obj);
+
+    if (res.code === 0) {
+      // 清空选中
+      setSelectedRowKeys([]);
+      setData(res.data);
+    }
+  }, [fromData]);
+
+  useEffect(() => {
+    getListFu();
+  }, [getListFu]);
+
+  const fromTime = useRef(-1);
+
+  // 搜索项 的输入
+  const searchKeyChange = useCallback(
+    (e: React.ChangeEvent<HTMLInputElement>) => {
+      clearTimeout(fromTime.current);
+      fromTime.current = window.setTimeout(() => {
+        setFromData({
+          ...fromData,
+          searchKey: e.target.value,
+        });
+      }, 500);
+    },
+    [fromData]
+  );
+
+  // 从仓库获取文件类别数据
+  const arr1 = useSelector((state: RootState) => state.A2Dict.A2Tab2Arr);
+
+  // 从仓库获取部门 级联 信息
+  const deptList = useSelector((state: RootState) => state.A5Section.tableList);
+
+  // 表格信息
+  const [data, setData] = useState<A1ItableType[]>([]);
+
+  // 点击批量下载
+  const downSelectFu = useCallback(async () => {
+    // 清空选中
+    setSelectedRowKeys([]);
+  }, []);
+
+  // 删除的弹窗数据
+  const [delInfo, setDelInfo] = useState({ id: 0, name: "" });
+
+  // 关于 审核
+  const adidtDom = useCallback((item: A1ItableType) => {
+    const num = item.auditStatus;
+
+    const txt = num === 0 ? "待审批" : num === 1 ? "审批通过" : "审批驳回";
+
+    const dom = item.auditDesc ? (
+      <Tooltip title={item.auditDesc}>
+        <div
+          className="iconHoverTit A1ItablauidtBox"
+          onClick={() =>
+            setAuditInfo({ id: item.id, sta: num, txt: item.auditDesc || "" })
+          }
+        >
+          {txt}&nbsp;
+          <div className="iconHoverTitTxt">?</div>
+        </div>
+      </Tooltip>
+    ) : (
+      <div
+        className="A1ItablauidtBox"
+        onClick={() =>
+          setAuditInfo({ id: item.id, sta: num, txt: item.auditDesc || "" })
+        }
+      >
+        {txt}
+      </div>
+    );
+
+    return dom;
+  }, []);
+
+  const columns = useMemo(() => {
+    return [
+      {
+        title: "所属阶段",
+        dataIndex: "stageName",
+      },
+      {
+        title: "文件类别",
+        dataIndex: "attrName",
+      },
+      {
+        title: "责任部门",
+        dataIndex: "deptName",
+      },
+      {
+        title: "文件名称",
+        render: (item: A1ItableType) =>
+          item.hasLack === 1 ? (
+            <>
+              <Tooltip title={item.description}>
+                <div className="iconHoverTit">
+                  无法提供&nbsp;
+                  <div className="iconHoverTitTxt">?</div>
+                </div>
+              </Tooltip>
+            </>
+          ) : (
+            item.fileName
+          ),
+      },
+      {
+        title: "上传人",
+        dataIndex: "uploadName",
+      },
+      {
+        title: "上传时间",
+        dataIndex: "createTime",
+      },
+      {
+        title: "审批状态",
+        render: (item: A1ItableType) => adidtDom(item),
+      },
+      {
+        title: "审核人",
+        render: (item: A1ItableType) =>
+          item.auditorName ? item.auditorName : "(空)",
+      },
+      {
+        title: "审核时间",
+        render: (item: A1ItableType) =>
+          item.auditTime ? item.auditTime : "(空)",
+      },
+      {
+        title: "操作",
+        render: (item: A1ItableType) =>
+          item.hasLack === 1 ? (
+            "-"
+          ) : (
+            <>
+              {authFilesLookFu(item.fileName) ? (
+                <Button
+                  size="small"
+                  type="text"
+                  onClick={() => authFilesLookFu(item.fileName, item.filePath)}
+                >
+                  查看
+                </Button>
+              ) : null}
+              <Button
+                size="small"
+                type="text"
+                onClick={() =>
+                  urlChangeFu(item.filePath, true, undefined, item.fileName)
+                }
+              >
+                下载
+              </Button>
+
+              <Button
+                size="small"
+                type="text"
+                danger
+                onClick={() => setDelInfo({ id: item.id, name: item.fileName })}
+              >
+                删除
+              </Button>
+            </>
+          ),
+      },
+    ];
+  }, [adidtDom]);
+
+  // 登记缺失文件的开启和关闭
+  const [lack, setLack] = useState(false);
+
+  // 审批状态的开启和关闭
+  const [auditInfo, setAuditInfo] = useState<{
+    id: number;
+    sta: 0 | 1 | 2;
+    txt: string;
+  }>({
+    id: 0,
+    sta: 0,
+    txt: "",
+  });
+
+  // 批量上传的弹窗
+  const [upFileOpen, setUpFileOpen] = useState(false);
+
+  return (
+    <div className={styles.A1Inner}>
+      <div className="A1Itop">
+        <div className="A1ItopRow">
+          <span>搜索项:</span>
+          <Input
+            maxLength={30}
+            style={{ width: 210 }}
+            placeholder="请输入文件名称,最多30字"
+            allowClear
+            onChange={(e) => searchKeyChange(e)}
+          />
+        </div>
+
+        <div className="A1ItopRow">
+          <span>文件类别:</span>
+          <Select
+            style={{ width: 120 }}
+            value={fromData.attrId}
+            onChange={(e) => setFromData({ ...fromData, attrId: e })}
+            options={[
+              { value: "", label: "全部" },
+              ...arr1.map((v) => ({ value: v.id, label: v.name })),
+            ]}
+          />
+        </div>
+
+        <div className="A1ItopRow">
+          <span>审批状态:</span>
+          <Select
+            style={{ width: 120 }}
+            value={fromData.auditStatus}
+            onChange={(e) => setFromData({ ...fromData, auditStatus: e })}
+            options={[
+              { value: "", label: "全部" },
+              { value: 0, label: "待审批" },
+              { value: 1, label: "审批通过" },
+              { value: 2, label: "审批驳回" },
+            ]}
+          />
+        </div>
+
+        <div className="A1ItopRow">
+          <span>责任部门:</span>
+          <Cascader
+            allowClear={false}
+            style={{ width: 200 }}
+            options={[{ id: "", name: "全部" }, ...deptList]}
+            value={fromData.deptId}
+            onChange={(e) => setFromData({ ...fromData, deptId: e })}
+            fieldNames={{ label: "name", value: "id" }}
+            placeholder="请选择"
+          />
+        </div>
+
+        <div className="A1ItopRow A1ItopRow2">
+          <Button type="primary" onClick={() => setLack(true)}>
+            登记缺失文件
+          </Button>
+          &emsp;
+          <Button type="primary" onClick={() => setUpFileOpen(true)}>
+            批量上传
+          </Button>
+          &emsp;
+          <Button
+            type="primary"
+            onClick={downSelectFu}
+            disabled={selectedRowKeys.length <= 0}
+          >
+            批量下载
+          </Button>
+        </div>
+      </div>
+
+      <div className="A1ItableBox">
+        <Table
+          rowSelection={{
+            type: "checkbox",
+            selectedRowKeys,
+            onChange: (selectedRowKeys: React.Key[]) => {
+              setSelectedRowKeys(selectedRowKeys);
+            },
+            // 禁用
+            getCheckboxProps: (item) => ({
+              disabled: item.hasLack === 1, // 配置无法勾选的列
+            }),
+          }}
+          scroll={{ y: 666 }}
+          dataSource={data}
+          columns={columns}
+          rowKey="id"
+          pagination={false}
+        />
+      </div>
+
+      {/* 点击删除出来的弹窗 */}
+      {delInfo.id ? (
+        <A1IRemove
+          mId={delInfo.id}
+          name={delInfo.name}
+          colseFu={() => setDelInfo({ id: 0, name: "" })}
+          delSuFu={() => getListFu()}
+        />
+      ) : null}
+
+      {/* 点击登记缺失文件出来的弹窗 */}
+      {lack ? (
+        <A1ILack
+          projectId={projectId}
+          closeFu={() => setLack(false)}
+          addSuFu={() => getListFu()}
+        />
+      ) : null}
+
+      {/* 点击审批出来的弹窗 */}
+      {auditInfo.id ? (
+        <A1IAudit
+          info={auditInfo}
+          closeFu={() => setAuditInfo({ id: 0, sta: 0, txt: "" })}
+          editSuFu={() => getListFu()}
+        />
+      ) : null}
+
+      {upFileOpen ? (
+        <A1IupFile
+          myUrl={`${baseURL}cms/inside/upload/${projectId}`}
+          upFileFu={() => getListFu()}
+          closeFu={() => setUpFileOpen(false)}
+        />
+      ) : null}
+    </div>
+  );
+}
+
+const MemoA1Inner = React.memo(A1Inner);
+
+export default MemoA1Inner;

+ 5 - 2
src/pages/A1Project/A1Look/index.tsx

@@ -3,6 +3,7 @@ import styles from "./index.module.scss";
 import { Button } from "antd";
 import classNames from "classnames";
 import A1User from "../A1User";
+import A1Inner from "../A1Inner";
 
 const A1Add = React.lazy(() => import("../A1Add"));
 const A1Outer = React.lazy(() => import("../A1Outer"));
@@ -108,8 +109,10 @@ function A1Look({ pageType, closeFu, tabType, lookTit, editTopFu }: Props) {
           />
         ) : topType === 2 ? (
           <A1Outer projectId={pageType.id} projectName={myTitle} />
-        ) : topType === 3 ? null : topType === 4 ? (
-          <A1User projectId={pageType.id}/>
+        ) : topType === 3 ? (
+          <A1Inner projectId={pageType.id}/>
+        ) : topType === 4 ? (
+          <A1User projectId={pageType.id} />
         ) : null}
       </div>
     </div>

+ 5 - 5
src/pages/A1Project/A1Outer/A1OupFile/index.tsx

@@ -133,15 +133,11 @@ function A1OupFile({ myUrl, fromData, nowLoc, closeFu, upFileFu }: props) {
 
   // 点击确定
   const btnOkFu = useCallback(async () => {
-    console.log("-----", fileList);
-
     if (fileList.some((v) => v.percent !== 100))
       return message.warning("有文件未上传完成.");
 
     // 拿到 id集合
 
-    console.log("-----", fileList);
-
     const ids: number[] = [];
 
     fileList.forEach((v) => {
@@ -238,7 +234,11 @@ function A1OupFile({ myUrl, fromData, nowLoc, closeFu, upFileFu }: props) {
           <Button>取消</Button>
         </Popconfirm>
         &emsp;
-        <Button type="primary" onClick={btnOkFu}>
+        <Button
+          type="primary"
+          onClick={btnOkFu}
+          disabled={fileList.length <= 0}
+        >
           确定
         </Button>
       </div>

+ 38 - 7
src/pages/A1Project/A1User/A1UserAdd.tsx

@@ -1,17 +1,29 @@
 import { A1UtableType } from "@/types";
 import { Button, Form, FormInstance, Modal, Popconfirm, Select } from "antd";
-import React, { useCallback, useRef } from "react";
+import React, { useCallback, useEffect, useRef } from "react";
 import styles from "./index.module.scss";
 import { useSelector } from "react-redux";
 import { RootState } from "@/store";
+import { A1_APIUsave } from "@/store/action/A1Project";
+import { MessageFu } from "@/utils/message";
 
 type Props = {
   info: A1UtableType;
   closeFu: () => void;
   editFu: () => void;
+  addFu: () => void;
 };
 
-function A1UserAdd({ info, closeFu, editFu }: Props) {
+function A1UserAdd({ info, closeFu, editFu, addFu }: Props) {
+  useEffect(() => {
+    if (info.id > 0) {
+      FormBoxRef.current?.setFieldsValue({
+        dictJobId: info.dictJobId,
+        userId: info.userId,
+      });
+    }
+  }, [info]);
+
   // 表单的ref
   const FormBoxRef = useRef<FormInstance>(null);
 
@@ -25,9 +37,28 @@ function A1UserAdd({ info, closeFu, editFu }: Props) {
   const onFinishFailed = useCallback(() => {}, []);
 
   // 通过校验点击确定
-  const onFinish = useCallback(async (value: any) => {
-    console.log("ccc");
-  }, []);
+  const onFinish = useCallback(
+    async (value: any) => {
+      const res = await A1_APIUsave({
+        dictJobId: value.dictJobId,
+        userId: value.userId,
+        id: info.id > 0 ? info.id : null,
+        projectId: info.projectId,
+      });
+
+      if (res.code === 0) {
+        if (info.id > 0) {
+          MessageFu.success("编辑成功!");
+          editFu();
+        } else {
+          MessageFu.success("新增成功!");
+          addFu();
+        }
+        closeFu();
+      }
+    },
+    [addFu, closeFu, editFu, info.id, info.projectId]
+  );
 
   return (
     <Modal
@@ -51,7 +82,7 @@ function A1UserAdd({ info, closeFu, editFu }: Props) {
         >
           <Form.Item
             label="项目职能"
-            name="aaaa"
+            name="dictJobId"
             rules={[{ required: true, message: "请选择项目职能!" }]}
           >
             <Select
@@ -62,7 +93,7 @@ function A1UserAdd({ info, closeFu, editFu }: Props) {
 
           <Form.Item
             label="用户"
-            name="bbbb"
+            name="userId"
             rules={[{ required: true, message: "请选择用户!" }]}
           >
             <Select

+ 2 - 0
src/pages/A1Project/A1User/index.module.scss

@@ -14,6 +14,7 @@
       margin-top: 15px;
       height: calc(100% - 60px);
       overflow: hidden;
+
       .ant-table-body {
         height: 610px;
         overflow-y: auto !important;
@@ -26,6 +27,7 @@
       }
     }
 
+
   }
 }
 

+ 33 - 8
src/pages/A1Project/A1User/index.tsx

@@ -7,9 +7,13 @@ import React, {
 } from "react";
 import styles from "./index.module.scss";
 import { Button, Input, Popconfirm, Table } from "antd";
-import { A1_APIUgeiList } from "@/store/action/A1Project";
+import { A1_APIUdel, A1_APIUgeiList } from "@/store/action/A1Project";
 import { A1UtableType } from "@/types";
 import A1UserAdd from "./A1UserAdd";
+import { useSelector } from "react-redux";
+import { RootState } from "@/store";
+import lastIdresArrFu from "@/pages/A3User/UserAdd/dataRes";
+import { MessageFu } from "@/utils/message";
 
 type Props = {
   projectId: number;
@@ -44,8 +48,26 @@ function A1User({ projectId }: Props) {
     []
   );
 
+  // 新增 和 编辑 成功
+  const addSuFu = useCallback(() => {
+    if (searchKey.trim() === "") getListFu("");
+    else setSearchKey("");
+  }, [getListFu, searchKey]);
+
   // 点击删除
-  const delById = useCallback((id: number) => {}, []);
+  const delById = useCallback(
+    async (id: number) => {
+      const res = await A1_APIUdel(id);
+      if (res.code === 0) {
+        MessageFu.success("删除成功!");
+        getListFu(searchKey);
+      }
+    },
+    [getListFu, searchKey]
+  );
+
+  // 从仓库获取部门 级联 信息
+  const deptList = useSelector((state: RootState) => state.A5Section.tableList);
 
   const columns = useMemo(() => {
     return [
@@ -56,25 +78,27 @@ function A1User({ projectId }: Props) {
       // },
       {
         title: "项目职能",
-        dataIndex: "name",
+        dataIndex: "jobName",
       },
       {
         title: "部门",
-        dataIndex: "deptId",
+        render: (item: A1UtableType) =>
+          lastIdresArrFu(item.deptId + "", deptList, true),
+        // dataIndex: "deptId",
       },
       {
         title: "角色",
-        dataIndex: "projectId",
+        dataIndex: "roleName",
       },
       {
         title: "姓名",
-        dataIndex: "realName",
+        dataIndex: "userName",
       },
       {
         title: "操作",
         render: (item: A1UtableType) => (
           <>
-            <Button size="small" type="text">
+            <Button size="small" type="text" onClick={() => setAddInfo(item)}>
               编辑
             </Button>
 
@@ -93,7 +117,7 @@ function A1User({ projectId }: Props) {
         ),
       },
     ];
-  }, [delById]);
+  }, [delById, deptList]);
 
   // 编辑 新增 的数据
   const [addInfo, setAddInfo] = useState({} as A1UtableType);
@@ -139,6 +163,7 @@ function A1User({ projectId }: Props) {
           info={addInfo}
           closeFu={() => setAddInfo({ id: 0 } as A1UtableType)}
           editFu={() => getListFu(searchKey)}
+          addFu={() => addSuFu()}
         />
       ) : null}
     </div>

+ 13 - 13
src/pages/A1Project/index.tsx

@@ -34,7 +34,7 @@ function A1Project() {
     (state: RootState) => state.A3User.tableInfo.list
   );
 
-  const pmNameArr = useMemo(() => {
+  const pmUserIdArr = useMemo(() => {
     const arr1 = A3UserList.filter((v) => v.userName !== "admin");
     const arr2: { value: number; label: string }[] = arr1.map((v: any) => ({
       value: v.id,
@@ -54,8 +54,8 @@ function A1Project() {
   // 表单数据
   const [fromData, setFromData] = useState({
     searchKey: "",
-    pmName: "",
-    bmName: "",
+    pmUserId: "",
+    bmUserId: "",
     statusId: "",
     scheduleCollect: "",
     scheduleAudit: "",
@@ -91,12 +91,12 @@ function A1Project() {
   );
 
   // 项目经理 下拉 搜索 的 改变
-  const pmNameChange = useCallback(
+  const pmUserIdChange = useCallback(
     (value: string) => {
       const val = value ? value : "";
       setFromData({
         ...fromData,
-        pmName: val,
+        pmUserId: val,
         pageNum: 1,
       });
     },
@@ -104,12 +104,12 @@ function A1Project() {
   );
 
   // 商务经理 下拉 搜索 的 改变
-  const bmNameChange = useCallback(
+  const bmUserIdChange = useCallback(
     (value: string) => {
       const val = value ? value : "";
       setFromData({
         ...fromData,
-        bmName: val,
+        bmUserId: val,
         pageNum: 1,
       });
     },
@@ -123,8 +123,8 @@ function A1Project() {
     setInputKey(Date.now());
     setFromData({
       searchKey: "",
-      pmName: "",
-      bmName: "",
+      pmUserId: "",
+      bmUserId: "",
       statusId: "",
       scheduleCollect: "",
       scheduleAudit: "",
@@ -372,13 +372,13 @@ function A1Project() {
               allowClear
               placeholder="请选择或输入内容搜索"
               optionFilterProp="children"
-              onChange={pmNameChange}
+              onChange={pmUserIdChange}
               filterOption={(input, option) =>
                 (option?.label ?? "")
                   .toLowerCase()
                   .includes(input.toLowerCase())
               }
-              options={pmNameArr}
+              options={pmUserIdArr}
             />
           </div>
 
@@ -391,13 +391,13 @@ function A1Project() {
               allowClear
               placeholder="请选择或输入内容搜索"
               optionFilterProp="children"
-              onChange={bmNameChange}
+              onChange={bmUserIdChange}
               filterOption={(input, option) =>
                 (option?.label ?? "")
                   .toLowerCase()
                   .includes(input.toLowerCase())
               }
-              options={pmNameArr}
+              options={pmUserIdArr}
             />
           </div>
         </div>

+ 24 - 8
src/pages/A3User/UserAdd/dataRes.ts

@@ -6,21 +6,37 @@
 
 import { A5TableType } from "@/types";
 
-const lastIdresArrFu = (id: string, arrAll: A5TableType[]) => {
+const lastIdresArrFu = (id: string, arrAll: A5TableType[], flag?: boolean) => {
   let arr: string[] = [];
 
+  let str: string = "";
+
   arrAll.forEach((v1) => {
-    if (v1.id === id) arr = [id];
-    else {
+    if (v1.id === id) {
+      arr = [id];
+      str = v1.name;
+    } else {
       v1.children?.forEach((v2) => {
-        if (v2.id === id) arr = [v1.id, id];
-        else {
+        if (v2.id === id) {
+          arr = [v1.id, id];
+          str = v1.name + " / " + v2.name;
+        } else {
           v2.children?.forEach((v3) => {
-            if (v3.id === id) arr = [v1.id, v2.id, id];
-            else {
+            if (v3.id === id) {
+              arr = [v1.id, v2.id, id];
+              str = v1.name + " / " + v2.name + " / " + v3.name;
+            } else {
               v3.children?.forEach((v4) => {
                 if (v4.id === id) {
                   arr = [v1.id, v2.id, v3.id, id];
+                  str =
+                    v1.name +
+                    " / " +
+                    v2.name +
+                    " / " +
+                    v3.name +
+                    " / " +
+                    v4.name;
                 }
               });
             }
@@ -30,7 +46,7 @@ const lastIdresArrFu = (id: string, arrAll: A5TableType[]) => {
     }
   });
 
-  return arr;
+  return flag ? str : arr;
 };
 
 export default lastIdresArrFu;

+ 5 - 4
src/pages/A5Section/A5Add/index.tsx

@@ -60,14 +60,15 @@ function A5Add({ info, closeFu, addFu, myType }: Props) {
   const A5Tilele = useMemo(() => {
     let txt = "";
     if (info.id === "-1") {
-      txt = `新增${txtRes}`;
-      if (info.parentId && info.name) txt = `新增 ${info.name} 子${txtRes}`;
+      txt = `新增${myType === "字典" ? "阶段" : "部门"}`;
+      if (info.parentId && info.name)
+        txt = `新增 ${info.name} 子${myType === "字典" ? "阶段" : "部门"}`;
     } else {
-      txt = `编辑${txtRes}`;
+      txt = `编辑${myType === "字典" ? "阶段" : "部门"}`;
       if (info.parentId && info.name) txt = `编辑 ${info.name}`;
     }
     return txt;
-  }, [info.id, info.name, info.parentId, txtRes]);
+  }, [info.id, info.name, info.parentId, myType]);
 
   return (
     <Modal

+ 8 - 0
src/pages/Login/index.tsx

@@ -38,6 +38,14 @@ export default function Login() {
     const res: any = await userLoginAPI(obj);
     if (res.code === 0) {
       MessageFu.success("登录成功");
+
+      // 检查密码是不是默认密码,是的话给提示
+      if (passWord === userName + "4dage") {
+        window.setTimeout(() => {
+          MessageFu.warning("您的密码还是默认密码,请尽快修改!");
+        }, 1000);
+      }
+
       // 用户信息存到本地
       setTokenInfo(res.data);
       history.push("/");

+ 53 - 0
src/store/action/A1Project.ts

@@ -134,3 +134,56 @@ export const A1_APIremoveSure = (fileIds: string[]) => {
 export const A1_APIUgeiList = (projectId: number, val: string) => {
   return http.get(`cms/member/getList/${projectId}?searchKey=${val}`);
 };
+
+/**
+ * 项目成员---------新增/编辑
+ */
+export const A1_APIUsave = (data: any) => {
+  return http.post("cms/member/save", data);
+};
+
+/**
+ * 项目成员---------删除
+ */
+export const A1_APIUdel = (id: number) => {
+  return http.get(`cms/member/remove/${id}`);
+};
+
+// --------------------------  内控文件  --------------------------
+/**
+ * 内控文件---------获取列表
+ */
+export const A1_APIIgetList = (data: any) => {
+  return http.post("cms/inside/getList", data);
+};
+/**
+ * 内控文件---------删除列表(调用成功之后到回收站)
+ */
+export const A1_APIIdel = (data: any) => {
+  return http.post(`cms/inside/remove`, data);
+};
+
+/**
+ * 内控文件---------获取登记缺失文件列表
+ */
+export const A1_APIIgetLack = (projectId: number) => {
+  return http.get(`cms/inside/getRegister/${projectId}`);
+};
+
+/**
+ * 内控文件---------登记缺失文件
+ */
+export const A1_APIIsaveLack = (
+  projectId: number,
+  data: { attributeId: number; description: string }[]
+) => {
+  return http.post(`cms/inside/lack/save/${projectId}`, data);
+};
+
+
+/**
+ * 内控文件---------审批
+ */
+export const A1_APIIaudit = (data:any) => {
+  return http.post('cms/inside/audit',data);
+};

+ 57 - 26
src/types/api/A1Project.d.ts

@@ -16,33 +16,64 @@ export type A1TableType = {
   snapPmUser: string;
   unit: string;
   updateTime: string;
-  amount:string
+  amount: string;
 };
 
-export type A1OFileType ={
-	ancestors: string;
-	createTime: string;
-	creatorId: number;
-	creatorName: string;
-	filePath: string;
-	hasHardCoded: number;
-	id: number;
-	name: string;
-	parentId: number;
-	projectId?: any;
-	type: 0|1;
-	updateTime: string;
-}
+export type A1OFileType = {
+  ancestors: string;
+  createTime: string;
+  creatorId: number;
+  creatorName: string;
+  filePath: string;
+  hasHardCoded: number;
+  id: number;
+  name: string;
+  parentId: number;
+  projectId?: any;
+  type: 0 | 1;
+  updateTime: string;
+};
+
+export type A1UtableType = {
+  createTime: string;
+  creatorName: string;
+  deptId: number;
+  dictJobId: number;
+  id: number;
+  projectId: number;
+  realName: string;
+  roleName: string;
+  updateTime: string;
+  userId: number;
+};
+
+export type A1ItableType = {
+  attributeId: number;
+  auditStatus: 0|1|2;
+  auditorId: number;
+  auditorName: string;
+  createTime: string;
+  creatorId?: any;
+  creatorName: string;
+  deptName: string;
+  description: string;
+  fileName: string;
+  filePath: string;
+  fileSize: string;
+  id: number;
+  projectId: number;
+  stageName: string;
+  updateTime: string;
+  uploadName: string;
+  hasLack:number
+  auditTime:string
+  auditDesc:string
+};
 
-export type A1UtableType ={
-	createTime: string;
-	creatorName: string;
-	deptId: number;
-	id: number;
-	name: string;
-	projectId: number;
-	realName: string;
-	roleName: string;
-	updateTime: string;
-	userId: number;
+export type A1IlackType ={
+	attributeId: number;
+	attributeName: string;
+	hasUpload: boolean;
+  done:boolean
+  desc:string
 }

+ 1 - 1
src/types/api/A2Dict.d.ts

@@ -24,7 +24,7 @@ export type A2Tab2Type = {
   deptId:string;
   deptName: string;
   description: string;
-  formatType: string;
+  formatType: '0'|'1';
   id: number;
   name: string;
   stageId: string;