shaogen1995 2 лет назад
Родитель
Сommit
306feccc01

+ 65 - 0
src/pages/A2Dict/A2Tab1/A2Tab1Add/index.module.scss

@@ -0,0 +1,65 @@
+.A2Tab1Add{
+  :global{
+    .ant-modal-close {
+      display: none;
+    }
+    .ant-modal {
+      width: 800px !important;
+    }
+    .A2TableAddMain{
+      margin-top: 10px;
+      border-top: 1px solid #999999;
+      padding-top: 25px;
+      .A2TableAddRow {
+        margin-bottom: 20px;
+        position: relative;
+        display: flex;
+        padding: 0 24px 0 0px;
+        text-align: right;
+
+        .rowSpan {
+          display: inline-block;
+          width: 80px;
+          line-height: 32px;
+
+          &>span {
+            position: relative;
+            top: 2px;
+            color: #ff4d4f;
+          }
+        }
+
+        .bs {
+          &::before {
+            content: '*';
+            position: absolute;
+            top: 2px;
+            left: 1px;
+            z-index: 10;
+            color: #ff4d4f;
+          }
+        }
+
+        .inputBox {
+          width: calc(100% - 90px);
+
+        }
+
+        .inputBoxCheck {
+          width: 155px;
+
+          .rowCheck {
+            display: block;
+            display: flex;
+            margin-left: 4px;
+            margin-top: 5px;
+          }
+        }
+      }
+      .A2TableAddBtn {
+        margin-top: 30px;
+        text-align: center;
+      }
+    }
+  }
+}

+ 117 - 0
src/pages/A2Dict/A2Tab1/A2Tab1Add/index.tsx

@@ -0,0 +1,117 @@
+import React, { useCallback, useEffect, useMemo, useState } from "react";
+import styles from "./index.module.scss";
+import { A2Tab1_1 } from "@/types/api/A2Dict";
+import { Button, Input, Modal, Popconfirm } from "antd";
+import { MessageFu } from "@/utils/message";
+import TextArea from "antd/es/input/TextArea";
+import { A2_APIadd1 } from "@/store/action/A2Dict";
+
+type Props = {
+  info: A2Tab1_1;
+  closeFu: () => void;
+  addFu: () => void;
+};
+
+function A2Tab1Add({ info, closeFu, addFu }: Props) {
+  const [name, setName] = useState("");
+
+  const [description, setDescription] = useState("");
+
+  // 点击提交
+  const btnOkFu = useCallback(async () => {
+    if (!name) return MessageFu.warning("字典值不能为空!");
+
+    const obj = {
+      ...info,
+      id: info.id === -1 ? null : info.id,
+      name,
+      description,
+    };
+
+    const res = await A2_APIadd1(obj);
+
+    if (res.code === 0) {
+      MessageFu.success(info.id === -1 ? "新增成功!" : "编辑成功!");
+      addFu();
+      closeFu();
+    }
+  }, [addFu, closeFu, description, info, name]);
+
+  //  如果是编辑
+  useEffect(() => {
+    if (info.id !== -1) {
+      setName(info.name);
+      setDescription(info.description);
+    }
+  }, [info]);
+
+  const A2Tilele = useMemo(() => {
+    let txt1 = info.type === "job" ? "职能" : "状态";
+    let txt2 = info.id === -1 ? "新增" : "编辑";
+    return txt2 + txt1;
+  }, [info.id, info.type]);
+
+  return (
+    <Modal
+      wrapClassName={styles.A2Tab1Add}
+      destroyOnClose
+      open={true}
+      title={A2Tilele}
+      footer={
+        [] // 设置footer为空,去掉 取消 确定默认按钮
+      }
+    >
+      <div className="A2TableAddMain">
+        <div className="A2TableAddRow">
+          <span className="rowSpan">字典值:</span>
+          <div className="inputBox">
+            <Input
+              disabled={info.name === "未分类"}
+              maxLength={10}
+              value={name}
+              onChange={(e) => setName(e.target.value.replace(/\s+/g, ""))}
+              showCount
+              placeholder="请输入内容,不能重复"
+            />
+          </div>
+        </div>
+
+        <div className="A2TableAddRow">
+          <span className="rowSpan">字典说明:</span>
+          <div className="inputBox">
+            <TextArea
+              rows={4}
+              placeholder="请输入内容"
+              maxLength={100}
+              showCount
+              value={description}
+              onChange={(e) =>
+                setDescription(e.target.value.replace(/\s+/g, ""))
+              }
+            />
+          </div>
+        </div>
+
+        <div className="A2TableAddBtn">
+          <Popconfirm
+            title="放弃编辑后,信息将不会保存!"
+            okText="放弃"
+            cancelText="取消"
+            onConfirm={closeFu}
+            okButtonProps={{ loading: false }}
+          >
+            <Button>取消</Button>
+          </Popconfirm>
+          &emsp;
+          <Button type="primary" onClick={btnOkFu}>
+            提交
+          </Button>
+        </div>
+      </div>
+    </Modal>
+  );
+}
+
+const MemoA2Tab1Add = React.memo(A2Tab1Add);
+
+export default MemoA2Tab1Add;

+ 139 - 0
src/pages/A2Dict/A2Tab1/A2Table1.tsx

@@ -0,0 +1,139 @@
+import React, { useCallback, useMemo } from "react";
+import styles from "./index.module.scss";
+import { Button, Popconfirm, Table } from "antd";
+import { useSelector } from "react-redux";
+import { RootState } from "@/store";
+import { A2Tab1_1 } from "@/types/api/A2Dict";
+import { A2_APIdel, A2_APIsort } from "@/store/action/A2Dict";
+import { MessageFu } from "@/utils/message";
+
+type Props = {
+  editFu: (item: A2Tab1_1) => void;
+  upTaleFu: () => void;
+  type: "job" | "status";
+};
+
+function A2Table1({ editFu, upTaleFu, type }: Props) {
+  const tableArr = useSelector(
+    (state: RootState) => state.A2Dict.A2Tab1_1Obj[type]
+  );
+
+  // 点击删除
+  const delById = useCallback(
+    async (id: number) => {
+      const res = await A2_APIdel(id);
+      if (res.code === 0) {
+        MessageFu.success("删除成功!");
+        upTaleFu();
+      }
+    },
+    [upTaleFu]
+  );
+
+  // 点击排序
+  const sortFu = useCallback(
+    async (flag: 1 | -1, id: number, index: number) => {
+      const arr = tableArr.filter((v) => v.name !== "未分类");
+
+      const newId = arr[index + flag].id;
+
+      const res = await A2_APIsort(id, newId);
+
+      if (res.code === 0) {
+        MessageFu.success("排序修改成功!");
+        upTaleFu();
+      }
+    },
+    [tableArr, upTaleFu]
+  );
+
+  const columns = useMemo(() => {
+    return [
+      {
+        width: 100,
+        title: "序号",
+        render: (item: A2Tab1_1, __: any, index: number) =>
+          item.name !== "未分类" ? index + 1 : "-",
+      },
+      {
+        title: "字典值",
+        dataIndex: "name",
+      },
+      {
+        title: "说明",
+        render: (item: A2Tab1_1) =>
+          item.description ? (
+            item.description.length >= 30 ? (
+              <span style={{ cursor: "pointer" }} title={item.description}>
+                {item.description.substring(0, 30) + "..."}
+              </span>
+            ) : (
+              item.description
+            )
+          ) : (
+            "(空)"
+          ),
+      },
+      {
+        title: "操作",
+        render: (item: A2Tab1_1, _: any, index: number) => (
+          <>
+            {index !== 0 && item.name !== "未分类" ? (
+              <Button
+                size="small"
+                type="text"
+                onClick={() => sortFu(-1, item.id, index)}
+              >
+                上移
+              </Button>
+            ) : null}
+
+            {index < tableArr.length - 2 && item.name !== "未分类" ? (
+              <Button
+                size="small"
+                type="text"
+                onClick={() => sortFu(1, item.id, index)}
+              >
+                下移
+              </Button>
+            ) : null}
+
+            <Button size="small" type="text" onClick={() => editFu(item)}>
+              编辑
+            </Button>
+
+            {item.name !== "未分类" ? (
+              <Popconfirm
+                title="删除后无法恢复,是否删除?"
+                okText="删除"
+                cancelText="取消"
+                onConfirm={() => delById(item.id)}
+                okButtonProps={{ loading: false }}
+              >
+                <Button size="small" type="text" danger>
+                  删除
+                </Button>
+              </Popconfirm>
+            ) : null}
+          </>
+        ),
+      },
+    ];
+  }, [delById, editFu, sortFu, tableArr.length]);
+
+  return (
+    <div className={styles.A2Table1}>
+      <Table
+        size="small"
+        dataSource={tableArr}
+        columns={columns}
+        rowKey="id"
+        pagination={false}
+      />
+    </div>
+  );
+}
+
+const MemoA2Table1 = React.memo(A2Table1);
+
+export default MemoA2Table1;

+ 191 - 0
src/pages/A2Dict/A2Tab1/A2Table3.tsx

@@ -0,0 +1,191 @@
+import React, { useCallback, useMemo } from "react";
+import styles from "./index.module.scss";
+import { Button, Popconfirm, Table } from "antd";
+import { useSelector } from "react-redux";
+import { RootState } from "@/store";
+import { A2_APIdel, A2_APIsort } from "@/store/action/A2Dict";
+import { MessageFu } from "@/utils/message";
+import { A5TableType } from "@/types";
+
+type Props = {
+  editFu: (item: A5TableType) => void;
+  upTaleFu: () => void;
+  type: "job" | "status";
+};
+
+function A2Table3({ editFu, upTaleFu, type }: Props) {
+  // 获取表格数据
+  const tableList = useSelector((state: RootState) => state.A2Dict.A2Tab1_2Arr);
+
+  // 树型数组扁平化
+  const arrAllArr = useMemo(() => {
+    const arr: A5TableType[] = [...tableList];
+    const arr1: A5TableType[] = [];
+    arr.forEach((v) => {
+      arr1.push(v);
+      if (v.children && v.children.length) {
+        v.children.forEach((v2) => {
+          arr1.push(v2);
+          if (v2.children && v2.children.length) {
+            v2.children.forEach((v3) => {
+              arr1.push(v3);
+              if (v3.children && v3.children.length) {
+                v3.children.forEach((v4) => {
+                  arr1.push(v4);
+                });
+              }
+            });
+          }
+        });
+      }
+    });
+    return arr1;
+  }, [tableList]);
+
+  // 拿到当前点击 级别的 数组
+  const sonArrFu = useCallback(
+    (fId: string) => {
+      const arr: A5TableType[] = arrAllArr.filter(
+        (v) => v.parentId === fId && v.name !== "未分类"
+      );
+      return arr;
+    },
+    [arrAllArr]
+  );
+
+  // 点击 上移 和下移
+  const sortMoveFu = useCallback(
+    async (flag: 1 | -1, index: number, oldId: string, fId: string) => {
+      const arr = sonArrFu(fId);
+      const newId = arr[index + flag].id;
+
+      const res = await A2_APIsort(oldId, newId);
+
+      if (res.code === 0) {
+        upTaleFu();
+        MessageFu.success("排序修改成功!");
+      }
+    },
+    [upTaleFu, sonArrFu]
+  );
+
+  // 点击删除
+  const delById = useCallback(
+    async (id: string) => {
+      const res = await A2_APIdel(id);
+      if (res.code === 0) {
+        MessageFu.success("删除成功!");
+        upTaleFu();
+      }
+    },
+    [upTaleFu]
+  );
+
+  const columns = useMemo(() => {
+    return [
+      {
+        title: <>&emsp;&nbsp;部门名称</>,
+        dataIndex: "name",
+      },
+      {
+        title: "说明",
+        render: (item: A5TableType) =>
+          item.description ? (
+            item.description.length >= 30 ? (
+              <span style={{ cursor: "pointer" }} title={item.description}>
+                {item.description.substring(0, 30) + "..."}
+              </span>
+            ) : (
+              item.description
+            )
+          ) : (
+            "(空)"
+          ),
+      },
+      {
+        title: "同级排序",
+        render: (item: A5TableType) =>
+          item.name === "未分类" ? "-" : item.level + "级 - " + item.sort,
+      },
+      {
+        title: "操作",
+        render: (item: A5TableType, _: any, index: number) => (
+          <>
+            {item.level < 4 && item.name !== "未分类" ? (
+              <Button
+                size="small"
+                type="text"
+                onClick={() =>
+                  editFu({
+                    id: "-1",
+                    parentId: item.id,
+                    name: item.name,
+                    level: item.level,
+                  } as A5TableType)
+                }
+              >
+                新增子部门
+              </Button>
+            ) : null}
+
+            <Button size="small" type="text" onClick={() => editFu(item)}>
+              编辑
+            </Button>
+            {index !== 0 && item.name !== "未分类" ? (
+              <Button
+                size="small"
+                type="text"
+                onClick={() => sortMoveFu(-1, index, item.id, item.parentId)}
+              >
+                上移
+              </Button>
+            ) : null}
+
+            {sonArrFu(item.parentId).length - 1 !== index &&
+            item.name !== "未分类" ? (
+              <Button
+                size="small"
+                type="text"
+                onClick={() => sortMoveFu(1, index, item.id, item.parentId)}
+              >
+                下移
+              </Button>
+            ) : null}
+
+            {item.name !== "未分类" ? (
+              <Popconfirm
+                title="删除后无法恢复,是否删除?"
+                okText="删除"
+                cancelText="取消"
+                onConfirm={() => delById(item.id)}
+                okButtonProps={{ loading: false }}
+              >
+                <Button size="small" type="text" danger>
+                  删除
+                </Button>
+              </Popconfirm>
+            ) : null}
+          </>
+        ),
+      },
+    ];
+  }, [delById, editFu, sonArrFu, sortMoveFu]);
+
+  return (
+    <div className={styles.A2Table3}>
+      {tableList.length ? (
+        <Table
+          dataSource={tableList}
+          columns={columns}
+          rowKey="id"
+          pagination={false}
+          expandable={{ defaultExpandAllRows: true }}
+        />
+      ) : null}
+    </div>
+  );
+}
+
+const MemoA2Table3 = React.memo(A2Table3);
+
+export default MemoA2Table3;

+ 23 - 0
src/pages/A2Dict/A2Tab1/index.module.scss

@@ -0,0 +1,23 @@
+.A2Tab1 {
+  :global {
+
+    .A2tableBox {
+      margin-bottom: 20px;
+
+      .A2tableBoxBtn {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 10px;
+        padding: 0 10px;
+
+        &>h3 {
+          font-size: 18px;
+          font-weight: 700;
+        }
+      }
+    }
+
+
+  }
+}

+ 102 - 0
src/pages/A2Dict/A2Tab1/index.tsx

@@ -0,0 +1,102 @@
+import React, { useCallback, useEffect, useState } from "react";
+import styles from "./index.module.scss";
+import { useDispatch } from "react-redux";
+import { A2_APIgetList1, A2_APIgetList2 } from "@/store/action/A2Dict";
+import A2Table1 from "./A2Table1";
+import { Button } from "antd";
+import { A2Tab1_1 } from "@/types/api/A2Dict";
+import A2Tab1Add from "./A2Tab1Add";
+import A2Table3 from "./A2Table3";
+import { A5TableType } from "@/types";
+function A2Tab1() {
+  const dispatch = useDispatch();
+
+  const getListFu1 = useCallback(() => {
+    dispatch(A2_APIgetList1());
+  }, [dispatch]);
+
+  const getListFu2 = useCallback(() => {
+    dispatch(A2_APIgetList2());
+  }, [dispatch]);
+
+  useEffect(() => {
+    getListFu1();
+    getListFu2();
+  }, [getListFu1, getListFu2]);
+
+  // 职能 和 状态的信息
+  const [addInfo1, setAddInfo1] = useState({} as A2Tab1_1);
+
+  // 阶段的信息
+  const [addInfo2, setAddInfo2] = useState({} as A5TableType);
+
+  return (
+    <div className={styles.A2Tab1}>
+      <div className="A2tableBox">
+        <div className="A2tableBoxBtn">
+          <h3>职能</h3>
+          <Button
+            type="primary"
+            onClick={() => setAddInfo1({ id: -1, type: "job" } as A2Tab1_1)}
+          >
+            新增
+          </Button>
+        </div>
+        <A2Table1
+          editFu={(item) => setAddInfo1(item)}
+          upTaleFu={() => getListFu1()}
+          type="job"
+        />
+      </div>
+
+      <div className="A2tableBox">
+        <div className="A2tableBoxBtn">
+          <h3>状态</h3>
+          <Button
+            type="primary"
+            onClick={() => setAddInfo1({ id: -1, type: "status" } as A2Tab1_1)}
+          >
+            新增
+          </Button>
+        </div>
+        <A2Table1
+          editFu={(item) => setAddInfo1(item)}
+          upTaleFu={() => getListFu1()}
+          type="status"
+        />
+      </div>
+
+      <div className="A2tableBox">
+        <div className="A2tableBoxBtn">
+          <h3>阶段</h3>
+          <Button
+            type="primary"
+            onClick={() =>
+              setAddInfo2({ id: "-1", parentId: "0" } as A5TableType)
+            }
+          >
+            新增
+          </Button>
+        </div>
+        <A2Table3
+          editFu={(item) => setAddInfo2(item)}
+          upTaleFu={() => getListFu2()}
+          type="status"
+        />
+      </div>
+
+      {/* 新增职能 和 状态 */}
+      {addInfo1.id ? (
+        <A2Tab1Add
+          info={addInfo1}
+          closeFu={() => setAddInfo1({} as A2Tab1_1)}
+          addFu={() => getListFu1()}
+        />
+      ) : null}
+    </div>
+  );
+}
+
+const MemoA2Tab1 = React.memo(A2Tab1);
+
+export default MemoA2Tab1;

+ 18 - 3
src/pages/A2Dict/index.module.scss

@@ -1,5 +1,20 @@
-.A2Dict{
-  :global{
-    
+.A2Dict {
+  padding: 20px 15px;
+  background-color: #fff;
+  border-radius: 10px;
+
+  :global {
+    .A2Main {
+      width: 100%;
+      height: calc(100% - 27px);
+      margin-top: 15px;
+
+      &>div {
+        width: 100%;
+        height: 100%;
+        overflow-y: auto;
+
+      }
+    }
   }
   }
 }
 }

+ 30 - 5
src/pages/A2Dict/index.tsx

@@ -1,12 +1,37 @@
-import React from "react";
+import React, { useState } from "react";
 import styles from "./index.module.scss";
 import styles from "./index.module.scss";
- function A2Dict() {
-  
+import { Button } from "antd";
+import A2Tab1 from "./A2Tab1";
+
+const topBtnArr = [
+  { id: 1, name: "项目属性" },
+  { id: 2, name: "项目文件属性" },
+];
+
+function A2Dict() {
+  const [acId, setAcId] = useState(1);
+
   return (
   return (
     <div className={styles.A2Dict}>
     <div className={styles.A2Dict}>
-      <h1>A2Dict</h1>
+      <div className="pageTitle">字典管理</div>
+      <div className="A2Top">
+        {topBtnArr.map((v) => (
+          <Button
+            onClick={() => setAcId(v.id)}
+            key={v.id}
+            type={v.id === acId ? "primary" : "default"}
+          >
+            {v.name}
+          </Button>
+        ))}
+        &emsp;&emsp;注:删除字典值时,与该字典值关联的数据都将关联到“未分类”
+      </div>
+
+      <div className="A2Main">
+        {acId===1?<A2Tab1 />:null}
+      </div>
     </div>
     </div>
-  )
+  );
 }
 }
 
 
 const MemoA2Dict = React.memo(A2Dict);
 const MemoA2Dict = React.memo(A2Dict);

+ 0 - 6
src/pages/A4Role/RoleAdd/index.module.scss

@@ -60,11 +60,5 @@
         text-align: center;
         text-align: center;
       }
       }
     }
     }
-
-    .lookRole {
-      .row {
-        pointer-events: none;
-      }
-    }
   }
   }
 }
 }

+ 1 - 1
src/pages/A4Role/RoleAdd/index.tsx

@@ -63,7 +63,7 @@ function RoleAdd({ id, closePage, upTableList, addTableList }: Props) {
         [] // 设置footer为空,去掉 取消 确定默认按钮
         [] // 设置footer为空,去掉 取消 确定默认按钮
       }
       }
     >
     >
-      <div className={classNames("roleAddMain", id === 1 ? "lookRole" : "")}>
+      <div className={classNames("roleAddMain")}>
         <div className="row">
         <div className="row">
           <span className="bs rowSpan">角色名称:</span>
           <span className="bs rowSpan">角色名称:</span>
           <div className="inputBox">
           <div className="inputBox">

+ 70 - 0
src/pages/A5Section/A5Add/index.module.scss

@@ -0,0 +1,70 @@
+.A5Add {
+  :global {
+    .ant-modal-close {
+      display: none;
+    }
+
+    .ant-modal {
+      width: 800px !important;
+    }
+
+    .A5AddMain {
+      margin-top: 10px;
+      border-top: 1px solid #999999;
+      padding-top: 25px;
+
+      .A5AddRow {
+        margin-bottom: 20px;
+        position: relative;
+        display: flex;
+        padding: 0 24px 0 0px;
+        text-align: right;
+
+        .rowSpan {
+          display: inline-block;
+          width: 80px;
+          line-height: 32px;
+
+          &>span {
+            position: relative;
+            top: 2px;
+            color: #ff4d4f;
+          }
+        }
+
+        .bs {
+          &::before {
+            content: '*';
+            position: absolute;
+            top: 2px;
+            left: 1px;
+            z-index: 10;
+            color: #ff4d4f;
+          }
+        }
+
+        .inputBox {
+          width: calc(100% - 90px);
+
+        }
+
+        .inputBoxCheck {
+          width: 155px;
+
+          .rowCheck {
+            display: block;
+            display: flex;
+            margin-left: 4px;
+            margin-top: 5px;
+          }
+        }
+      }
+
+      .A5AddBtn {
+        margin-top: 30px;
+        text-align: center;
+      }
+
+    }
+  }
+}

+ 125 - 0
src/pages/A5Section/A5Add/index.tsx

@@ -0,0 +1,125 @@
+import React, { useCallback, useEffect, useMemo, useState } from "react";
+import styles from "./index.module.scss";
+import { Button, Input, Modal, Popconfirm } from "antd";
+import { A5TableType } from "@/types";
+import TextArea from "antd/es/input/TextArea";
+import { MessageFu } from "@/utils/message";
+import { A5_APIadd } from "@/store/action/A5Section";
+
+type Props = {
+  info: A5TableType;
+  closeFu: () => void;
+  addFu: () => void;
+};
+
+function A5Add({ info, closeFu, addFu }: Props) {
+  const [name, setName] = useState("");
+
+  const [description, setDescription] = useState("");
+
+  // 如果是编辑
+  useEffect(() => {
+    if (info.id !== "-1") {
+      setName(info.name);
+      setDescription(info.description);
+    }
+  }, [info]);
+
+  // 点击提交
+  const btnOkFu = useCallback(async () => {
+    if (!name) return MessageFu.warning("部门名称不能为空!");
+
+    const obj = {
+      ...info,
+      id: info.id === "-1" ? null : info.id,
+      level: info.level ? info.level+1 : 1,
+      name,
+      description,
+    };
+
+    const res = await A5_APIadd(obj);
+
+    if (res.code === 0) {
+      MessageFu.success(info.id === "-1" ? "新增成功!" : "编辑成功!");
+      addFu();
+      closeFu();
+    }
+  }, [addFu, closeFu, description, info, name]);
+
+  // 标题的动态显示
+  const A5Tilele = useMemo(() => {
+    let txt = "";
+    if (info.id === "-1") {
+      txt = "新增部门";
+      if (info.parentId && info.name) txt = `新增 ${info.name} 子部门`;
+    } else {
+      txt = "编辑部门";
+      if (info.parentId && info.name) txt = `编辑 ${info.name}`;
+    }
+    return txt;
+  }, [info.id, info.name, info.parentId]);
+
+  return (
+    <Modal
+      wrapClassName={styles.A5Add}
+      destroyOnClose
+      open={true}
+      title={A5Tilele}
+      footer={
+        [] // 设置footer为空,去掉 取消 确定默认按钮
+      }
+    >
+      <div className="A5AddMain">
+        <div className="A5AddRow">
+          <span className="bs rowSpan">部门名称:</span>
+          <div className="inputBox">
+            <Input
+              disabled={info.name === "未分类"}
+              maxLength={10}
+              value={name}
+              onChange={(e) => setName(e.target.value.replace(/\s+/g, ""))}
+              showCount
+              placeholder="请输入内容,不能重复"
+            />
+          </div>
+        </div>
+
+        <div className="A5AddRow">
+          <span className="rowSpan">部门说明:</span>
+          <div className="inputBox">
+            <TextArea
+              rows={4}
+              placeholder="请输入内容"
+              maxLength={100}
+              showCount
+              value={description}
+              onChange={(e) =>
+                setDescription(e.target.value.replace(/\s+/g, ""))
+              }
+            />
+          </div>
+        </div>
+
+        <div className="A5AddBtn">
+          <Popconfirm
+            title="放弃编辑后,信息将不会保存!"
+            okText="放弃"
+            cancelText="取消"
+            onConfirm={closeFu}
+            okButtonProps={{ loading: false }}
+          >
+            <Button>取消</Button>
+          </Popconfirm>
+          &emsp;
+          <Button type="primary" onClick={btnOkFu}>
+            提交
+          </Button>
+        </div>
+      </div>
+    </Modal>
+  );
+}
+
+const MemoA5Add = React.memo(A5Add);
+
+export default MemoA5Add;

+ 14 - 4
src/pages/A5Section/index.module.scss

@@ -9,7 +9,7 @@
       .A5Top {
       .A5Top {
         position: absolute;
         position: absolute;
         top: -60px;
         top: -60px;
-        left: 160px;
+        left: 190px;
         z-index: 101;
         z-index: 101;
       }
       }
 
 
@@ -19,7 +19,7 @@
         overflow: hidden;
         overflow: hidden;
 
 
         .ant-table-body {
         .ant-table-body {
-          height: 575px;
+          height: 750px;
           overflow-y: auto !important;
           overflow-y: auto !important;
 
 
           .ant-table-row {
           .ant-table-row {
@@ -28,8 +28,18 @@
             }
             }
           }
           }
 
 
-          .A5Sort{
-            .A5Sort1{
+          .ant-table-cell-with-append {
+            display: flex;
+            justify-content: start;
+          }
+
+          .ant-table-row-expand-icon {
+            background-color: var(--themeColor);
+            color: #fff;
+          }
+
+          .A5Sort {
+            .A5Sort1 {
               cursor: pointer;
               cursor: pointer;
             }
             }
           }
           }

+ 85 - 39
src/pages/A5Section/index.tsx

@@ -1,11 +1,12 @@
-import React, { useCallback, useEffect, useMemo } from "react";
+import React, { useCallback, useEffect, useMemo, useState } from "react";
 import styles from "./index.module.scss";
 import styles from "./index.module.scss";
 import { Button, Popconfirm, Table } from "antd";
 import { Button, Popconfirm, Table } from "antd";
 import { useDispatch, useSelector } from "react-redux";
 import { useDispatch, useSelector } from "react-redux";
-import { A5_APIgetList, A5_APIsort } from "@/store/action/A5Section";
+import { A5_APIdel, A5_APIgetList, A5_APIsort } from "@/store/action/A5Section";
 import { RootState } from "@/store";
 import { RootState } from "@/store";
 import { A5TableType } from "@/types";
 import { A5TableType } from "@/types";
 import { MessageFu } from "@/utils/message";
 import { MessageFu } from "@/utils/message";
+import A5Add from "./A5Add";
 
 
 function A5Section() {
 function A5Section() {
   const dispatch = useDispatch();
   const dispatch = useDispatch();
@@ -51,19 +52,25 @@ function A5Section() {
   // 拿到当前点击 级别的 数组
   // 拿到当前点击 级别的 数组
   const sonArrFu = useCallback(
   const sonArrFu = useCallback(
     (fId: string) => {
     (fId: string) => {
-      const arr: A5TableType[] = arrAllArr.filter((v) => v.parentId === fId);
+      const arr: A5TableType[] = arrAllArr.filter(
+        (v) => v.parentId === fId && v.name !== "未分类"
+      );
       return arr;
       return arr;
     },
     },
     [arrAllArr]
     [arrAllArr]
   );
   );
 
 
   // 点击删除
   // 点击删除
-  const delById = useCallback((id: string) => {}, []);
-
-  // 点击新增子部门
-  const addTree = useCallback((item: A5TableType) => {
-    console.log("----", item);
-  }, []);
+  const delById = useCallback(
+    async (id: string) => {
+      const res = await A5_APIdel(id);
+      if (res.code === 0) {
+        MessageFu.success("删除成功!");
+        getListFu();
+      }
+    },
+    [getListFu]
+  );
 
 
   // 点击 上移 和下移
   // 点击 上移 和下移
   const sortMoveFu = useCallback(
   const sortMoveFu = useCallback(
@@ -104,19 +111,34 @@ function A5Section() {
       },
       },
       {
       {
         title: "同级排序",
         title: "同级排序",
-        dataIndex: "sort",
+        render: (item: A5TableType) =>
+          item.name === "未分类" ? "-" : item.level + "级 - " + item.sort,
       },
       },
       {
       {
         title: "操作",
         title: "操作",
         render: (item: A5TableType, _: any, index: number) => (
         render: (item: A5TableType, _: any, index: number) => (
           <>
           <>
-            <Button size="small" type="text" onClick={() => addTree(item)}>
-              新增子部门
-            </Button>
-            <Button size="small" type="text">
+            {item.level < 4 && item.name !== "未分类" ? (
+              <Button
+                size="small"
+                type="text"
+                onClick={() =>
+                  setAddInfo({
+                    id: "-1",
+                    parentId: item.id,
+                    name:item.name,
+                    level:item.level
+                  } as A5TableType)
+                }
+              >
+                新增子部门
+              </Button>
+            ) : null}
+
+            <Button size="small" type="text" onClick={() => setAddInfo(item)}>
               编辑
               编辑
             </Button>
             </Button>
-            {index === 0 ? null : (
+            {index !== 0 && item.name !== "未分类" ? (
               <Button
               <Button
                 size="small"
                 size="small"
                 type="text"
                 type="text"
@@ -124,9 +146,10 @@ function A5Section() {
               >
               >
                 上移
                 上移
               </Button>
               </Button>
-            )}
+            ) : null}
 
 
-            {sonArrFu(item.parentId).length - 1 === index ? null : (
+            {sonArrFu(item.parentId).length - 1 !== index &&
+            item.name !== "未分类" ? (
               <Button
               <Button
                 size="small"
                 size="small"
                 type="text"
                 type="text"
@@ -134,44 +157,67 @@ function A5Section() {
               >
               >
                 下移
                 下移
               </Button>
               </Button>
-            )}
-
-            <Popconfirm
-              title="删除后无法恢复,是否删除?"
-              okText="删除"
-              cancelText="取消"
-              onConfirm={() => delById(item.id)}
-              okButtonProps={{ loading: false }}
-            >
-              <Button size="small" type="text" danger>
-                删除
-              </Button>
-            </Popconfirm>
+            ) : null}
+
+            {item.name !== "未分类" ? (
+              <Popconfirm
+                title="删除后无法恢复,是否删除?"
+                okText="删除"
+                cancelText="取消"
+                onConfirm={() => delById(item.id)}
+                okButtonProps={{ loading: false }}
+              >
+                <Button size="small" type="text" danger>
+                  删除
+                </Button>
+              </Popconfirm>
+            ) : null}
           </>
           </>
         ),
         ),
       },
       },
     ];
     ];
-  }, [addTree, delById, sonArrFu, sortMoveFu]);
+  }, [delById, sonArrFu, sortMoveFu]);
+
+  // 新增和编辑
+  const [addInfo, setAddInfo] = useState({} as A5TableType);
 
 
   return (
   return (
     <div className={styles.A5Section}>
     <div className={styles.A5Section}>
       <div className="pageTitle">部门管理</div>
       <div className="pageTitle">部门管理</div>
       <div className="A5Main">
       <div className="A5Main">
         <div className="A5Top">
         <div className="A5Top">
-          <Button type="primary">新增</Button>
+          <Button
+            type="primary"
+            onClick={() =>
+              setAddInfo({ id: "-1", parentId: "0" } as A5TableType)
+            }
+          >
+            新增
+          </Button>
         </div>
         </div>
 
 
         {/* 表格主体 */}
         {/* 表格主体 */}
         <div className="A5tableBox">
         <div className="A5tableBox">
-          <Table
-            scroll={{ y: 575 }}
-            dataSource={tableList}
-            columns={columns}
-            rowKey="id"
-            pagination={false}
-          />
+          {tableList.length ? (
+            <Table
+              scroll={{ y: 750 }}
+              dataSource={tableList}
+              columns={columns}
+              rowKey="id"
+              pagination={false}
+              expandable={{ defaultExpandAllRows: true }}
+            />
+          ) : null}
         </div>
         </div>
       </div>
       </div>
+
+      {addInfo.id ? (
+        <A5Add
+          info={addInfo}
+          closeFu={() => setAddInfo({} as A5TableType)}
+          addFu={() => getListFu()}
+        />
+      ) : null}
     </div>
     </div>
   );
   );
 }
 }

+ 81 - 0
src/store/action/A2Dict.ts

@@ -0,0 +1,81 @@
+import http from "@/utils/http";
+import { AppDispatch } from "..";
+import { A2Tab1Type, A2Tab1_1 } from "@/types/api/A2Dict";
+import { A5TableType } from "@/types";
+/**
+ * 获取项目属性 职能,状态
+ */
+export const A2_APIgetList1 = () => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.get("cms/dict/getList");
+
+    if (res.code === 0) {
+      const arrTemp: A2Tab1_1[] = res.data;
+
+      const arr1: A2Tab1_1[] = [];
+      const arr2: A2Tab1_1[] = [];
+
+      arrTemp.forEach((v) => {
+        if (v.type === "job") arr1.push(v);
+        else if (v.type === "status") arr2.push(v);
+      });
+
+      const obj: A2Tab1Type = {
+        job: arr1,
+        status: arr2,
+      };
+      dispatch({ type: "A2/getInfo1_1", payload: obj });
+    }
+  };
+};
+
+export const A2_APIgetList2 = () => {
+  return async (dispatch: AppDispatch) => {
+    // 获取阶段
+    const res = await http.post("cms/dict/getTree", { type: "stage" });
+    if (res.code === 0) {
+      const arr3: A5TableType[] = res.data;
+      arr3.forEach((v) => {
+        v.level = 1;
+        if (v.children && v.children.length) {
+          v.children.forEach((v2) => {
+            v2.level = 2;
+            if (v2.children && v2.children.length) {
+              v2.children.forEach((v3) => {
+                v3.level = 3;
+                if (v3.children && v3.children.length) {
+                  v3.children.forEach((v4) => {
+                    v4.level = 4;
+                  });
+                }
+              });
+            }
+          });
+        }
+      });
+      dispatch({ type: "A2/getInfo1_2", payload: arr3 });
+    }
+  };
+};
+
+/**
+ * 新增、编辑 项目属性
+ */
+export const A2_APIadd1 = (data: any) => {
+  return http.post("cms/dict/save", data);
+};
+
+/**
+ * 删除 项目属性
+ */
+export const A2_APIdel = (id: number|string) => {
+  return http.get(`cms/dict/remove/${id}`);
+};
+
+/**
+ * 排序
+ */
+export const A2_APIsort = (id1: number|string,id2:number|string) => {
+  return http.get(`cms/dict/sort/${id1}/${id2}`);
+};
+

+ 15 - 0
src/store/action/A5Section.ts

@@ -40,3 +40,18 @@ export const A5_APIgetList = () => {
 export const A5_APIsort = (id1: string, id2: string) => {
 export const A5_APIsort = (id1: string, id2: string) => {
   return http.get(`sys/dept/sort/${id1}/${id2}`);
   return http.get(`sys/dept/sort/${id1}/${id2}`);
 };
 };
+
+/**
+ * 新增和编辑
+ */
+export const A5_APIadd = (data: any) => {
+  return http.post("sys/dept/save", data);
+};
+
+
+/**
+ * 删除
+ */
+export const A5_APIdel = (id:string) => {
+  return http.get(`sys/dept/remove/${id}`);
+};

+ 31 - 0
src/store/reducer/A2Dict.ts

@@ -0,0 +1,31 @@
+import { A5TableType } from "@/types";
+import { A2Tab1Type } from "@/types/api/A2Dict";
+
+// 初始化状态
+const initState = {
+  // 项目属性的数据  职能,状态
+  A2Tab1_1Obj: {
+    status: [],
+    job: [],
+  } as A2Tab1Type,
+
+  A2Tab1_2Arr: [] as A5TableType[],
+};
+
+// 定义 action 类型
+type Props =
+  | { type: "A2/getInfo1_1"; payload: A2Tab1Type }
+  | { type: "A2/getInfo1_2"; payload: A5TableType[] };
+
+// 频道 reducer
+export default function A2Reducer(state = initState, action: Props) {
+  switch (action.type) {
+    // 项目属性的数据
+    case "A2/getInfo1_1":
+      return { ...state, A2Tab1_1Obj: action.payload };
+    case "A2/getInfo1_2":
+      return { ...state, A2Tab1_2Arr: action.payload };
+    default:
+      return state;
+  }
+}

+ 2 - 0
src/store/reducer/index.ts

@@ -4,6 +4,7 @@ import { combineReducers } from "redux";
 // 导入 登录 模块的 reducer
 // 导入 登录 模块的 reducer
 import A0Layout from "./layout";
 import A0Layout from "./layout";
 import A1Project from "./A1Project";
 import A1Project from "./A1Project";
+import A2Dict from "./A2Dict";
 import A3User from "./A3User";
 import A3User from "./A3User";
 import A4Role from "./A4Role";
 import A4Role from "./A4Role";
 import A5Section from "./A5Section";
 import A5Section from "./A5Section";
@@ -13,6 +14,7 @@ import A6Log from "./A6Log";
 const rootReducer = combineReducers({
 const rootReducer = combineReducers({
   A0Layout,
   A0Layout,
   A1Project,
   A1Project,
+  A2Dict,
   A3User,
   A3User,
   A4Role,
   A4Role,
   A5Section,
   A5Section,

+ 18 - 0
src/types/api/A2Dict.d.ts

@@ -0,0 +1,18 @@
+export type A2Tab1_1 = {
+  createTime: string;
+  creatorId?: any;
+  creatorName: string;
+  description: string;
+  display: number;
+  id: number;
+  name: string;
+  parentId: number;
+  sort: number;
+  type: "status" | "job"
+  updateTime: string;
+};
+
+export type A2Tab1Type = {
+  status: A2Tab1_1[];
+  job: A2Tab1_1[];
+};