瀏覽代碼

库房管理01

shaogen1995 2 年之前
父節點
當前提交
98c241cb0e

+ 292 - 0
src/components/LookObjTable/LookModal.tsx

@@ -0,0 +1,292 @@
+import React, { useCallback, useEffect, useMemo, useState } from "react";
+import classNames from "classnames";
+import { Button, Modal, Select, Table } from "antd";
+import { useDispatch, useSelector } from "react-redux";
+import { RootState } from "@/store";
+import ImageLazy from "../ImageLazy";
+import { getInfoInAPI } from "@/store/action/object1";
+
+type Props = {
+  show: boolean;
+  closeShow: any;
+  id: number;
+};
+
+function LookModal({ show, closeShow, id }: Props) {
+  const dispatch = useDispatch();
+  // 根据id发送请求把数据存到仓库
+
+  const getInfoInAPIFu = useCallback(async () => {
+    const res = await getInfoInAPI(id);
+    const info = res.data.entity;
+    const fileList = {
+      img: [],
+      video: [],
+      audio: [],
+      model: [],
+      doc: [],
+    } as any;
+    res.data.file.forEach((v: any) => {
+      fileList[v.type].push(v);
+    });
+
+    dispatch({
+      type: "object1/getOneGoodsInfo",
+      payload: { info, fileList },
+    });
+  }, [dispatch, id]);
+
+  useEffect(() => {
+    getInfoInAPIFu();
+  }, [getInfoInAPIFu]);
+
+  // 选择商品信息还是附近(默认商品信息)
+  const [titSelect, setTitSelect] = useState("tit1");
+
+  // 附件类型下拉框
+  const { info, fileList } = useSelector(
+    (state: RootState) => state.object1Store.oneGoodsInfo
+  );
+
+  // 外形尺寸和具体质量
+  let sizeRes = "";
+  if (info.size && info.size.length) {
+    const sizeArr = info.size.split(",");
+    sizeRes = `(通长)${sizeArr[0]}cm (通宽)${sizeArr[1]}cm (通高)${sizeArr[2]}cm`;
+  }
+
+  let qualityRes = "-";
+  if (info.quality && info.quality.length) {
+    const qualityArr = info.quality.split(",");
+    qualityRes = qualityArr[0] + qualityArr[1];
+  }
+
+  const fileSelectList = useMemo(() => {
+    return [
+      { id: 1, value: "img", label: "高清图片" },
+      { id: 2, value: "video", label: "视频文件" },
+      { id: 3, value: "audio", label: "音频文件" },
+      { id: 4, value: "model", label: "三维模型" },
+      { id: 5, value: "doc", label: "文档资料" },
+    ];
+  }, []);
+  const [fileSelect, setFileSelect] = useState("img");
+  const fileSelectChangeFu = (value: string) => {
+    setFileSelect(value);
+  };
+
+  // 里面表格格式
+  const columns2 = useMemo(() => {
+    const tempArr = [
+      {
+        title: "附件名称",
+        dataIndex: "name",
+      },
+      {
+        title: "上传时间",
+        dataIndex: "createTime",
+      },
+    ] as any;
+    if (fileSelect === "img") {
+      tempArr.unshift({
+        title: "缩略图",
+        render: (item: any) => (
+          <ImageLazy width={120} height={70} src={item.filePath} />
+        ),
+      });
+    }
+    return tempArr;
+  }, [fileSelect]);
+
+  return (
+    <>
+      <Modal
+        wrapClassName="lookObjTable"
+        destroyOnClose
+        open={show}
+        title="查看藏品"
+        onCancel={closeShow}
+        footer={
+          [] // 设置footer为空,去掉 取消 确定默认按钮
+        }
+      >
+        {/* 商品信息和附件切换 */}
+        <div className="ObjectAddTit">
+          <div
+            onClick={() => setTitSelect("tit1")}
+            className={classNames(titSelect === "tit1" ? "active" : "")}
+          >
+            藏品信息
+          </div>
+          <div
+            onClick={() => setTitSelect("tit2")}
+            className={classNames(
+              "ObjectAddTitTow",
+              titSelect === "tit2" ? "active" : ""
+            )}
+          >
+            附件
+          </div>
+        </div>
+
+        {/* 藏品信息 */}
+        <div className="goodsInfo" hidden={titSelect !== "tit1"}>
+          <div className="row">
+            <div>
+              <span>藏品名称:</span>
+              <p>{info.name}</p>
+            </div>
+            <div>
+              <span>原名:</span>
+              <p>{info.namePrimitive ? info.namePrimitive : "-"}</p>
+            </div>
+          </div>
+          <div className="row">
+            <div>
+              <span>藏品编号名称:</span>
+              <p>{info.dictNum}</p>
+            </div>
+            <div>
+              <span>藏品编号:</span>
+              <p>{info.num ? info.num : "-"}</p>
+            </div>
+          </div>
+          <div className="row">
+            <div>
+              <span>年代:</span>
+              <p>{info.dictAge}</p>
+            </div>
+            <div>
+              <span>文物质地:</span>
+              <p>{info.dictTexture}</p>
+            </div>
+          </div>
+          <div className="row">
+            <div>
+              <span>具体年代:</span>
+              <p>{info.ageSpecific ? info.ageSpecific : "-"}</p>
+            </div>
+            <div>
+              <span>文物类别:</span>
+              <p>{info.dictGoodType}</p>
+            </div>
+          </div>
+
+          <div className="row">
+            <div>
+              <span>实际数量:</span>
+              <p>{info.pcs}</p>
+            </div>
+            <div>
+              <span>文物级别:</span>
+              <p>{info.dictLevel}</p>
+            </div>
+          </div>
+          <div className="rowFull">
+            <span>外形尺寸:</span>
+            <p dangerouslySetInnerHTML={{ __html: sizeRes }}></p>
+          </div>
+          <div className="rowFull">
+            <span>具体尺寸:</span>
+            <p>{info.sizeSpecific}</p>
+          </div>
+
+          <div className="row">
+            <div>
+              <span>质量范围:</span>
+              <p>{info.dictQualityScope}</p>
+            </div>
+            <div>
+              <span>具体质量:</span>
+              <p>{qualityRes}</p>
+            </div>
+          </div>
+
+          <div className="row">
+            <div>
+              <span>完残程度:</span>
+              <p>{info.complete}</p>
+            </div>
+            <div>
+              <span>保存状态:</span>
+              <p>{info.repair ? info.repair : "-"}</p>
+            </div>
+          </div>
+
+          <div className="row">
+            <div>
+              <span>入藏时间范围:</span>
+              <p>{info.dictCheckInScope}</p>
+            </div>
+            <div>
+              <span>入藏年度:</span>
+              <p>{info.checkInYear ? info.checkInYear : "-"}</p>
+            </div>
+          </div>
+
+          <div className="row">
+            <div>
+              <span>著者:</span>
+              <p>{info.author ? info.author : "-"}</p>
+            </div>
+            <div>
+              <span>版本:</span>
+              <p>{info.vision ? info.vision : "-"}</p>
+            </div>
+          </div>
+
+          <div className="rowFull">
+            <span>存卷:</span>
+            <p>{info.onFile ? info.onFile : "-"}</p>
+          </div>
+          <div className="rowFull">
+            <span>来源说明:</span>
+            <p>{info.description ? info.description : "-"}</p>
+          </div>
+        </div>
+
+        <div className="goodsFile" hidden={titSelect !== "tit2"}>
+          <div className="row">
+            <div className="rowTit">藏品图片:</div>
+            <div className="rowRr">
+              <ImageLazy width={120} height={120} src={info.thumb} />
+            </div>
+          </div>
+
+          <div className="row">
+            <div className="rowTit">附件类型:</div>
+            <div className="rowRr">
+              <Select
+                style={{ width: 150 }}
+                value={fileSelect}
+                onChange={fileSelectChangeFu}
+                options={fileSelectList}
+              />
+            </div>
+          </div>
+
+          {/* 表格主体 */}
+          <Table
+            size="small"
+            scroll={{ y: 300 }}
+            dataSource={fileList[fileSelect]}
+            columns={columns2}
+            rowKey="id"
+            pagination={false}
+          />
+        </div>
+
+        {/* 确定按钮 */}
+        <div className="goodsBtn">
+          <Button type="primary" onClick={closeShow}>
+            确定
+          </Button>
+        </div>
+      </Modal>
+    </>
+  );
+}
+
+const MemoLookModal = React.memo(LookModal);
+
+export default MemoLookModal;

+ 15 - 269
src/components/LookObjTable/index.tsx

@@ -1,11 +1,8 @@
-import { Button, Modal, Select, Table } from "antd";
-import React, { useCallback, useMemo, useState } from "react";
+import { Button, Table } from "antd";
+import React, { useCallback, useMemo, useRef, useState } from "react";
 import ImageLazy from "../ImageLazy";
 import "./index.css";
-import classNames from "classnames";
-import { useDispatch, useSelector } from "react-redux";
-import { RootState } from "@/store";
-import { getInfoInAPI } from "@/store/action/object1";
+import LookModal from "./LookModal";
 
 type Props = {
   data: any;
@@ -13,32 +10,13 @@ type Props = {
 };
 
 function LookObjTable({ data, y }: Props) {
-  const dispatch = useDispatch();
+  const lookIdRef = useRef(-1);
 
   // 点击表格里面的查看
-  const lookGoods = useCallback(
-    async (id: number) => {
-      const res = await getInfoInAPI(id);
-      const info = res.data.entity;
-      const fileList = {
-        img: [],
-        video: [],
-        audio: [],
-        model: [],
-        doc: [],
-      } as any;
-      res.data.file.forEach((v: any) => {
-        fileList[v.type].push(v);
-      });
-
-      dispatch({
-        type: "object1/getOneGoodsInfo",
-        payload: { info, fileList },
-      });
-      setShow(true);
-    },
-    [dispatch]
-  );
+  const lookGoods = useCallback((id: number) => {
+    lookIdRef.current = id;
+    setShow(true);
+  }, []);
 
   // 外层表格格式
   const columns = useMemo(() => {
@@ -90,62 +68,6 @@ function LookObjTable({ data, y }: Props) {
 
   // 控制弹窗的显示隐藏
   const [show, setShow] = useState(false);
-  // 选择商品信息还是附近(默认商品信息)
-  const [titSelect, setTitSelect] = useState("tit1");
-
-  // 附件类型下拉框
-  const { info, fileList } = useSelector(
-    (state: RootState) => state.object1Store.oneGoodsInfo
-  );
-  // 外形尺寸和具体质量
-  let sizeRes = "";
-  if (info.size && info.size.length) {
-    const sizeArr = info.size.split(",");
-    sizeRes = `(通长)${sizeArr[0]}cm&emsp;(通宽)${sizeArr[1]}cm&emsp;(通高)${sizeArr[2]}cm`;
-  }
-
-  let qualityRes ='-'
-  if(info.quality&&info.quality.length){
-    const qualityArr =info.quality.split(',')
-    qualityRes=qualityArr[0]+qualityArr[1]
-  }
-
-  const fileSelectList = useMemo(() => {
-    return [
-      { id: 1, value: "img", label: "高清图片" },
-      { id: 2, value: "video", label: "视频文件" },
-      { id: 3, value: "audio", label: "音频文件" },
-      { id: 4, value: "model", label: "三维模型" },
-      { id: 5, value: "doc", label: "文档资料" },
-    ];
-  }, []);
-  const [fileSelect, setFileSelect] = useState("img");
-  const fileSelectChangeFu = (value: string) => {
-    setFileSelect(value);
-  };
-
-  // 里面表格格式
-  const columns2 = useMemo(() => {
-    const tempArr = [
-      {
-        title: "附件名称",
-        dataIndex: "name",
-      },
-      {
-        title: "上传时间",
-        dataIndex: "createTime",
-      },
-    ] as any;
-    if (fileSelect === "img") {
-      tempArr.unshift({
-        title: "缩略图",
-        render: (item: any) => (
-          <ImageLazy width={120} height={70} src={item.filePath} />
-        ),
-      });
-    }
-    return tempArr;
-  }, [fileSelect]);
 
   return (
     <div>
@@ -158,189 +80,13 @@ function LookObjTable({ data, y }: Props) {
         pagination={false}
       />
       {/* 点击查看出来的对话框 */}
-      <Modal
-        wrapClassName="lookObjTable"
-        // destroyOnClose
-        open={show}
-        title="查看藏品"
-        onCancel={() => setShow(false)}
-        footer={
-          [] // 设置footer为空,去掉 取消 确定默认按钮
-        }
-      >
-        {/* 商品信息和附件切换 */}
-        <div className="ObjectAddTit">
-          <div
-            onClick={() => setTitSelect("tit1")}
-            className={classNames(titSelect === "tit1" ? "active" : "")}
-          >
-            藏品信息
-          </div>
-          <div
-            onClick={() => setTitSelect("tit2")}
-            className={classNames(
-              "ObjectAddTitTow",
-              titSelect === "tit2" ? "active" : ""
-            )}
-          >
-            附件
-          </div>
-        </div>
-
-        {/* 藏品信息 */}
-        <div className="goodsInfo" hidden={titSelect !== "tit1"}>
-          <div className="row">
-            <div>
-              <span>藏品名称:</span>
-              <p>{info.name}</p>
-            </div>
-            <div>
-              <span>原名:</span>
-              <p>{info.namePrimitive?info.namePrimitive:'-'}</p>
-            </div>
-          </div>
-          <div className="row">
-            <div>
-              <span>藏品编号名称:</span>
-              <p>{info.dictNum}</p>
-            </div>
-            <div>
-              <span>藏品编号:</span>
-              <p>{info.num ? info.num : "-"}</p>
-            </div>
-          </div>
-          <div className="row">
-            <div>
-              <span>年代:</span>
-              <p>{info.dictAge}</p>
-            </div>
-            <div>
-              <span>文物质地:</span>
-              <p>{info.dictTexture}</p>
-            </div>
-          </div>
-          <div className="row">
-            <div>
-              <span>具体年代:</span>
-              <p>{info.ageSpecific ? info.ageSpecific : "-"}</p>
-            </div>
-            <div>
-              <span>文物类别:</span>
-              <p>{info.dictGoodType}</p>
-            </div>
-          </div>
-
-          <div className="row">
-            <div>
-              <span>实际数量:</span>
-              <p>{info.pcs}</p>
-            </div>
-            <div>
-              <span>文物级别:</span>
-              <p>{info.dictLevel}</p>
-            </div>
-          </div>
-          <div className="rowFull">
-            <span>外形尺寸:</span>
-            <p dangerouslySetInnerHTML={{ __html: sizeRes }}></p>
-          </div>
-          <div className="rowFull">
-            <span>具体尺寸:</span>
-            <p>{info.sizeSpecific}</p>
-          </div>
-
-          <div className="row">
-            <div>
-              <span>质量范围:</span>
-              <p>{info.dictQualityScope}</p>
-            </div>
-            <div>
-              <span>具体质量:</span>
-              <p>{qualityRes}</p>
-            </div>
-          </div>
-
-          <div className="row">
-            <div>
-              <span>完残程度:</span>
-              <p>{info.complete}</p>
-            </div>
-            <div>
-              <span>保存状态:</span>
-              <p>{info.repair ? info.repair : "-"}</p>
-            </div>
-          </div>
-
-          <div className="row">
-            <div>
-              <span>入藏时间范围:</span>
-              <p>{info.dictCheckInScope}</p>
-            </div>
-            <div>
-              <span>入藏年度:</span>
-              <p>{info.checkInYear ? info.checkInYear : "-"}</p>
-            </div>
-          </div>
-
-          <div className="row">
-            <div>
-              <span>著者:</span>
-              <p>{info.author ? info.author : "-"}</p>
-            </div>
-            <div>
-              <span>版本:</span>
-              <p>{info.vision ? info.vision : "-"}</p>
-            </div>
-          </div>
-
-          <div className="rowFull">
-            <span>存卷:</span>
-            <p>{info.onFile ? info.onFile : "-"}</p>
-          </div>
-          <div className="rowFull">
-            <span>来源说明:</span>
-            <p>{info.description ? info.description : "-"}</p>
-          </div>
-        </div>
-
-        <div className="goodsFile" hidden={titSelect !== "tit2"}>
-          <div className="row">
-            <div className="rowTit">藏品图片:</div>
-            <div className="rowRr">
-              <ImageLazy width={120} height={120} src={info.thumb} />
-            </div>
-          </div>
-
-          <div className="row">
-            <div className="rowTit">附件类型:</div>
-            <div className="rowRr">
-              <Select
-                style={{ width: 150 }}
-                value={fileSelect}
-                onChange={fileSelectChangeFu}
-                options={fileSelectList}
-              />
-            </div>
-          </div>
-
-          {/* 表格主体 */}
-          <Table
-            size="small"
-            scroll={{ y: 300 }}
-            dataSource={fileList[fileSelect]}
-            columns={columns2}
-            rowKey="id"
-            pagination={false}
-          />
-        </div>
-
-        {/* 确定按钮 */}
-        <div className="goodsBtn">
-          <Button type="primary" onClick={() => setShow(false)}>
-            确定
-          </Button>
-        </div>
-      </Modal>
+      {show ? (
+        <LookModal
+          id={lookIdRef.current}
+          show={show}
+          closeShow={() => setShow(false)}
+        />
+      ) : null}
     </div>
   );
 }

+ 37 - 2
src/pages/ObjectSon/Object3/AddObject3/index.tsx

@@ -3,7 +3,13 @@ import { object3AddAPI, object3infoOutAPI } from "@/store/action/object3";
 import history, { urlParameter } from "@/utils/history";
 import { Button, Input, Popconfirm, Table } from "antd";
 import TextArea from "antd/es/input/TextArea";
-import React, { useCallback, useEffect, useMemo, useState } from "react";
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
 import { useLocation } from "react-router-dom";
 import _ from "lodash";
 import styles from "./index.module.scss";
@@ -11,6 +17,7 @@ import { useDispatch, useSelector } from "react-redux";
 import { RootState } from "@/store";
 import ImageLazy from "@/components/ImageLazy";
 import GoodsAll from "./GoodsAll";
+import LookModal from "@/components/LookObjTable/LookModal";
 function AddObject3() {
   const dispatch = useDispatch();
   // 顶部数据
@@ -89,6 +96,15 @@ function AddObject3() {
     setTableSelectList(data);
   }, [dispatch, results, tableSelectList]);
 
+  // 控制弹窗的显示隐藏
+  const [show, setShow] = useState(false);
+  // 点击表格里面的查看
+  const lookIdRef = useRef(-1);
+  const lookGoods = useCallback((id: number) => {
+    lookIdRef.current = id;
+    setShow(true);
+  }, []);
+
   // 表格数据
   const columns = useMemo(() => {
     return [
@@ -123,8 +139,18 @@ function AddObject3() {
         title: "藏品位置",
         render: (item: any) => <>123</>,
       },
+      {
+        title: "操作",
+        render: (item: any) => (
+          <>
+            <Button type="text" danger onClick={() => lookGoods(item.id)}>
+              查看
+            </Button>
+          </>
+        ),
+      },
     ];
-  }, []);
+  }, [lookGoods]);
 
   return (
     <div className={styles.AddObject3}>
@@ -215,6 +241,15 @@ function AddObject3() {
       </div>
       {/* 点击添加或者编辑出来的页面 */}
       {addPage ? <GoodsAll colsePage={() => setAddPage(false)} /> : null}
+
+      {/* 点击查看出来的对话框 */}
+      {show ? (
+        <LookModal
+          id={lookIdRef.current}
+          show={show}
+          closeShow={() => setShow(false)}
+        />
+      ) : null}
     </div>
   );
 }

+ 0 - 1
src/pages/Stores/index.module.scss

@@ -1,5 +1,4 @@
 .Stores{
-  background-color: rebeccapurple;
   :global{
     
   }

+ 35 - 5
src/pages/Stores/index.tsx

@@ -1,6 +1,11 @@
+import AuthRoute from "@/components/AuthRoute";
 import LeftBar from "@/components/LeftBar";
-import React from "react";
+import NotFound from "@/components/NotFound";
+import SpinLoding from "@/components/SpinLoding";
+import history from "@/utils/history";
+import React, { useEffect } from "react";
 import { useMemo } from "react";
+import { Route, Switch } from "react-router-dom";
 import styles from "./index.module.scss";
 export default function Stores() {
   const data = useMemo(() => {
@@ -8,29 +13,54 @@ export default function Stores() {
       {
         id: 1,
         name: "库房设置",
-        Com: React.lazy(() => import("../ObjectSon/Object1")),
+        Com: React.lazy(() => import("../StoresSon/Stores1")),
         path: "/stores",
       },
       {
         id: 2,
         name: "统计报表",
-        Com: React.lazy(() => import("../ObjectSon/Object2")),
+        Com: React.lazy(() => import("../StoresSon/Stores2")),
         path: "/stores/2",
       },
       {
         id: 3,
         name: "藏品移库",
-        Com: React.lazy(() => import("../ObjectSon/Object3")),
+        Com: React.lazy(() => import("../StoresSon/Stores3")),
         path: "/stores/3",
-      }
+      },
     ];
   }, []);
 
+  // 没有库房设置页面的权限 跳到有权限的页面
+  useEffect(() => {
+    if (data[0].id !== 1) {
+      history.replace(data[0].path);
+    }
+  }, [data]);
+
   return (
     <div className={styles.Stores}>
       <div className="leftBar">
         <LeftBar data={data} />
       </div>
+      {/* 三级路由页面 */}
+      <div className="rightMain">
+        <React.Suspense fallback={<SpinLoding />}>
+          <Switch>
+            {data.map((v, i) => (
+              <AuthRoute
+                exact
+                // exact={i === 0 ? true : false}
+                key={v.id}
+                path={v.path}
+                component={v.Com}
+              />
+            ))}
+
+            <Route path="*" component={NotFound} />
+          </Switch>
+        </React.Suspense>
+      </div>
     </div>
   );
 }

+ 32 - 0
src/pages/StoresSon/Stores1/index.css

@@ -0,0 +1,32 @@
+.Stores1Modal .ant-modal {
+  width: 1000px !important;
+}
+.Stores1Modal .modalMain {
+  padding: 0 20px;
+  border-top: 1px solid #ccc;
+  padding-top: 15px;
+}
+.Stores1Modal .modalMain .row {
+  margin-bottom: 20px;
+  display: flex;
+  align-items: center;
+  position: relative;
+}
+.Stores1Modal .modalMain .row .bs {
+  position: absolute;
+  top: 7px;
+  left: -8px;
+  color: #ff4d4f;
+}
+.Stores1Modal .modalMain .row > span {
+  font-weight: 700;
+}
+.Stores1Modal .modalMain .row .ant-input-textarea {
+  width: 800px;
+}
+.Stores1Modal .modalMain .rowAll {
+  align-items: flex-start;
+}
+.Stores1Modal .modalBtn {
+  text-align: center;
+}

+ 40 - 0
src/pages/StoresSon/Stores1/index.less

@@ -0,0 +1,40 @@
+.Stores1Modal {
+  .ant-modal {
+    width: 1000px !important;
+  }
+
+  .modalMain {
+    padding: 0 20px;
+    border-top: 1px solid #ccc;
+    padding-top: 15px;
+
+    .row {
+      margin-bottom: 20px;
+      display: flex;
+      align-items: center;
+      position: relative;
+
+      .bs {
+        position: absolute;
+        top: 7px;
+        left: -8px;
+        color: #ff4d4f;
+      }
+
+      &>span {
+        font-weight: 700;
+      }
+      .ant-input-textarea {
+        width: 800px;
+      }
+    }
+
+    .rowAll {
+      align-items: flex-start;
+    }
+  }
+
+  .modalBtn {
+    text-align: center;
+  }
+}

+ 149 - 0
src/pages/StoresSon/Stores1/index.module.scss

@@ -0,0 +1,149 @@
+.Stores1 {
+  :global {
+    .objectSonMain {
+      padding: 20px 30px;
+      display: flex;
+      justify-content: space-between;
+
+      .storesL {
+        width: 260px;
+        border: 1px solid #ccc;
+
+        .storesLTit {
+          padding: 15px 0;
+          text-align: center;
+        }
+
+        .storesLBox {
+          height: calc(100% - 62px);
+          overflow-y: auto;
+        }
+
+        .storesLRow {
+          .storesLRow_top {
+            display: flex;
+            align-items: center;
+            height: 40px;
+            color: black;
+
+            .incol {
+              cursor: pointer;
+              padding-left: 15px;
+              font-weight: 700;
+              font-size: 24px;
+              margin-right: 10px;
+            }
+
+            .txt {
+              cursor: pointer;
+              font-size: 18px;
+              width: calc(100% - 110px);
+              overflow: hidden;
+              text-overflow: ellipsis;
+              white-space: nowrap;
+            }
+
+            .inco2 {
+              cursor: pointer;
+              font-size: 16px;
+              margin-left: 10px;
+              width: 60px;
+              display: none;
+            }
+          }
+
+          .storesLRow_show {
+            width: calc(100% - 60px);
+            margin-left: 50px;
+            .storesLRow_showRow {
+              padding: 0;
+              cursor: pointer;
+
+              &>span {
+                font-weight: 700;
+              }
+            }
+
+            .active2 {
+              color: var(--themeColor);
+              pointer-events: none;
+            }
+          }
+
+          .noneData2 {
+            transition: height .3s;
+            overflow: hidden;
+            opacity: 0;
+            height: 0;
+            color: var(--themeColor);
+            text-align: center;
+          }
+        }
+
+        .storesLRowActive {
+          .storesLRow_top {
+            background-color: #ccc;
+
+            .incol {
+              pointer-events: none;
+            }
+
+            .txt {
+              pointer-events: none;
+            }
+            .inco2{
+              display: block;
+            }
+          }
+
+          .storesLRow_show {
+            transition: all .3s;
+
+            .storesLRow_showRow {
+              padding: 5px 0;
+            }
+          }
+
+          .noneData2 {
+            opacity: 1;
+            height: 40px;
+            line-height: 40px;
+          }
+        }
+      }
+
+      .storesR {
+        width: calc(100% - 280px);
+        border: 1px solid #ccc;
+
+        .storesRTitInco {
+          color: black;
+          font-size: 18px;
+          cursor: pointer;
+        }
+
+        .storesRTit {
+          padding: 0 20px;
+          height: 62px;
+          display: flex;
+          align-items: center;
+
+          .storesRTit1 {
+            margin: 0 20px 0 15px;
+          }
+
+        }
+      }
+
+      .noneData {
+        height: 300px;
+        font-size: 20px;
+        color: var(--themeColor);
+        line-height: 300px;
+        text-align: center;
+      }
+
+
+    }
+  }
+}

+ 379 - 0
src/pages/StoresSon/Stores1/index.tsx

@@ -0,0 +1,379 @@
+import BreadTit from "@/components/BreadTit";
+import { Button, Input, message, Modal, Popconfirm, Table } from "antd";
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
+import styles from "./index.module.scss";
+import TextArea from "antd/es/input/TextArea";
+import {
+  DownOutlined,
+  UpOutlined,
+  PlusOutlined,
+  EditOutlined,
+  DeleteOutlined,
+} from "@ant-design/icons";
+import "./index.css";
+import classNames from "classnames";
+import {
+  getStores1DetailAPI,
+  getStores1ListAPI,
+  stores1AddAPI,
+  stores1DelAPI,
+} from "@/store/action/stores1";
+import { useDispatch, useSelector } from "react-redux";
+import { RootState } from "@/store";
+function Stores1() {
+  const dispatch = useDispatch();
+
+  // 封装获取列表的函数
+  const getStores1ListAPIFu = useCallback(() => {
+    dispatch(getStores1ListAPI());
+  }, [dispatch]);
+
+  // 点击删除
+  const delOne = useCallback(
+    async (id: number) => {
+      const res: any = await stores1DelAPI(id);
+      if (res.code === 0) {
+        message.success("删除成功!");
+        getStores1ListAPIFu();
+      }
+    },
+    [getStores1ListAPIFu]
+  );
+
+  // 从仓库中获取总信息
+  const infoList1 = useSelector(
+    (state: RootState) => state.stores1Store.infoList
+  );
+  // 第一级的选中
+  const [acind1, setAcind1] = useState(0);
+  const infoList2 = useMemo(() => {
+    if (infoList1 && infoList1[acind1] && infoList1[acind1].children)
+      return infoList1[acind1].children;
+    else return [];
+  }, [acind1, infoList1]);
+
+  const setAcind1Fu = useCallback((i: number) => {
+    setAcind2(0);
+    setAcind1(i);
+  }, []);
+
+  // 第二级的选中 --表格数据
+  const [acind2, setAcind2] = useState(0);
+  const infoList3 = useMemo(() => {
+    if (infoList2 && infoList2[acind2] && infoList2[acind2].children)
+      return infoList2[acind2].children;
+    else return [];
+  }, [acind2, infoList2]);
+
+  useEffect(() => {
+    getStores1ListAPIFu();
+  }, [getStores1ListAPIFu]);
+
+  // 点击新建 或者编辑出来的页面
+
+  const [val1, setVal1] = useState("");
+  const [val2, setVal2] = useState("");
+  const [val3, setVal3] = useState("");
+
+  const addType = useRef("1");
+  const [open, setOpen] = useState(false);
+
+  const editIdRef = useRef(0);
+  // 点击新增或者编辑
+  const addFu = useCallback(async (type: string, id?: number) => {
+    if (!id) {
+      editIdRef.current = 0;
+      setVal1("");
+      setVal2("");
+      setVal3("");
+    } else {
+      editIdRef.current = id;
+      const res = await getStores1DetailAPI(id);
+      setVal1(res.data.name);
+      setVal2(res.data.num);
+      setVal3(res.data.description);
+    }
+    addType.current = type;
+    setOpen(true);
+  }, []);
+
+  // 点击提交
+  const btnOk = useCallback(async () => {
+    if (val1 === "") return message.warning("不能为空!");
+    if (addType.current !== "1" && val2 === "")
+      return message.warning("不能为空!");
+    const obj = {
+      name: val1,
+      num: val2 ? val2 : "",
+      description: val3 ? val3 : "",
+      level: Number(addType.current),
+    } as any;
+    if (addType.current === "2") obj.parentId = infoList1[acind1].id;
+    else if (addType.current === "3") obj.parentId = infoList2[acind2].id;
+    // 判断是新增还是编辑
+    if (editIdRef.current) obj.id = editIdRef.current;
+    const res: any = await stores1AddAPI(obj);
+    if (res.code === 0) {
+      message.success("操作成功!");
+      getStores1ListAPIFu();
+      setOpen(false);
+    }
+  }, [
+    acind1,
+    acind2,
+    getStores1ListAPIFu,
+    infoList1,
+    infoList2,
+    val1,
+    val2,
+    val3,
+  ]);
+
+  const columns = useMemo(() => {
+    return [
+      {
+        title: "货架名称",
+        dataIndex: "name",
+      },
+      {
+        title: "货架编号",
+        dataIndex: "num",
+      },
+      {
+        title: "备注",
+        render: (item: any) => (item.description ? item.description : "-"),
+      },
+      {
+        title: "操作",
+        render: (item: any) => (
+          <div className="storesRTitInco">
+            <EditOutlined
+              title="编辑货架"
+              onClick={() => addFu("3", item.id)}
+            />
+            &emsp;
+            <Popconfirm
+              title="确定删除吗?"
+              okText="确定"
+              cancelText="取消"
+              onConfirm={() => delOne(item.id)}
+            >
+              <DeleteOutlined title="删除货架" />
+            </Popconfirm>
+          </div>
+        ),
+      },
+    ];
+  }, [addFu, delOne]);
+
+  return (
+    <div className={styles.Stores1}>
+      <div className="breadTit">
+        <BreadTit>
+          <div className="breadTitRow active">库房设置</div>
+        </BreadTit>
+      </div>
+      <div className="objectSonMain">
+        {/* 左边的库区 */}
+        <div className="storesL">
+          <div className="storesLTit">
+            <Button type="primary" onClick={() => addFu("1")}>
+              新建库区
+            </Button>
+            &emsp;
+            <Popconfirm
+              title="确定删除吗?"
+              okText="确定"
+              cancelText="取消"
+              onConfirm={() => delOne(infoList1[acind1].id)}
+            >
+              <Button>删除</Button>
+            </Popconfirm>
+          </div>
+          <div className="storesLBox">
+            {infoList1 && infoList1.length ? (
+              infoList1.map((v: any, i: number) => (
+                <div
+                  className={classNames(
+                    "storesLRow",
+                    i === acind1 ? "storesLRowActive" : ""
+                  )}
+                  key={v.id}
+                >
+                  <div className="storesLRow_top">
+                    <div className="incol" onClick={() => setAcind1Fu(i)}>
+                      <DownOutlined hidden={i === acind1} />
+                      <UpOutlined hidden={i !== acind1} />
+                    </div>
+                    <div
+                      className="txt"
+                      title={v.name}
+                      onClick={() => setAcind1Fu(i)}
+                    >
+                      {v.name}
+                    </div>
+                    <div className="inco2">
+                      <PlusOutlined
+                        title="新增库房"
+                        onClick={() => addFu("2")}
+                      />
+                      &emsp;
+                      <EditOutlined
+                        title="编辑库区"
+                        onClick={() => addFu("1", v.id)}
+                      />
+                    </div>
+                  </div>
+                  {infoList2 && infoList2.length && i === acind1 ? (
+                    <div className="storesLRow_show">
+                      {infoList2.map((v2: any, i2: number) => (
+                        <div
+                          onClick={() => setAcind2(i2)}
+                          className={classNames(
+                            "storesLRow_showRow",
+                            i2 === acind2 ? "active2" : ""
+                          )}
+                          key={v2.id}
+                        >
+                          {v2.name}&nbsp;<span>编号:</span>
+                          {v2.num}
+                        </div>
+                      ))}
+                    </div>
+                  ) : (
+                    <div className="noneData2">暂无数据</div>
+                  )}
+                </div>
+              ))
+            ) : (
+              <div className="noneData">暂无数据</div>
+            )}
+          </div>
+        </div>
+        {/* 右边的表格 */}
+        <div className="storesR">
+          <div className="storesRTit">
+            {infoList2 && infoList2.length ? (
+              <>
+                <h3>{infoList2[acind2].name}</h3>
+                <div className="storesRTit1">
+                  仓库编号:{infoList2[acind2].num}
+                </div>
+                <div className="storesRTitInco">
+                  <PlusOutlined title="新增货架" onClick={() => addFu("3")} />
+                  &emsp;
+                  <EditOutlined
+                    title="编辑库房"
+                    onClick={() => addFu("2", infoList2[acind2].id)}
+                  />
+                  &emsp;
+                  <Popconfirm
+                    title="确定删除吗?"
+                    okText="确定"
+                    cancelText="取消"
+                    onConfirm={() => delOne(infoList2[acind2].id)}
+                  >
+                    <DeleteOutlined title="删除库房" />
+                  </Popconfirm>
+                </div>
+              </>
+            ) : null}
+          </div>
+          {/* 表格主体 */}
+          <Table
+            scroll={{ y: 518 }}
+            dataSource={infoList3}
+            columns={columns}
+            rowKey="id"
+            pagination={false}
+          />
+        </div>
+      </div>
+      {/* 新增或者编辑 */}
+      <Modal
+        wrapClassName="Stores1Modal"
+        destroyOnClose
+        open={open}
+        title={
+          addType.current === "1"
+            ? "库区名称"
+            : addType.current === "2"
+            ? "库房信息"
+            : "货架信息"
+        }
+        onCancel={() => setOpen(false)}
+        footer={
+          [] // 设置footer为空,去掉 取消 确定默认按钮
+        }
+      >
+        <div className="modalMain">
+          <div className="row">
+            <div className="bs">*</div>
+            <span>
+              {addType.current === "1"
+                ? "库区名称:"
+                : addType.current === "2"
+                ? "仓库名称:"
+                : "货架名称:"}
+            </span>
+            <Input
+              maxLength={15}
+              showCount
+              value={val1}
+              onChange={(e) => setVal1(e.target.value.trim())}
+              style={{ width: 300 }}
+              placeholder="请输入"
+            />
+          </div>
+          {addType.current !== "1" ? (
+            <div className="row">
+              <div className="bs">*</div>
+              <span>
+                {addType.current === "2" ? "仓库编号:" : "货架编号:"}
+              </span>
+              <Input
+                maxLength={15}
+                showCount
+                value={val2}
+                onChange={(e) => setVal2(e.target.value.trim())}
+                style={{ width: 300 }}
+                placeholder="请输入"
+              />
+            </div>
+          ) : null}
+          {addType.current === "3" ? (
+            <div className="row rowAll">
+              <span>&emsp;&emsp;备注:</span>
+              <TextArea
+                value={val3}
+                onChange={(e) => setVal3(e.target.value.trim())}
+                rows={3}
+                placeholder="请输入"
+                showCount
+                maxLength={255}
+              />
+            </div>
+          ) : null}
+        </div>
+        <br />
+        <div className="modalBtn">
+          <Button type="primary" onClick={btnOk}>
+            提交
+          </Button>
+          &emsp;
+          <Button onClick={() => setOpen(false)}>取消</Button>
+        </div>
+      </Modal>
+    </div>
+  );
+}
+
+const MemoStores1 = React.memo(Stores1);
+
+export default MemoStores1;

+ 1 - 1
src/pages/StoresSon/初始化组件 copy 2/index.module.scss

@@ -1,4 +1,4 @@
-.AAAAA{
+.Stores2{
   :global{
     
   }

+ 14 - 0
src/pages/StoresSon/Stores2/index.tsx

@@ -0,0 +1,14 @@
+import React from "react";
+import styles from "./index.module.scss";
+ function Stores2() {
+  
+  return (
+    <div className={styles.Stores2}>
+      <h1>Stores2</h1>
+    </div>
+  )
+}
+
+const MemoStores2 = React.memo(Stores2);
+
+export default MemoStores2;

+ 1 - 1
src/pages/StoresSon/初始化组件/index.module.scss

@@ -1,4 +1,4 @@
-.AAAAA{
+.Stores3{
   :global{
     
   }

+ 13 - 0
src/pages/StoresSon/Stores3/index.tsx

@@ -0,0 +1,13 @@
+import React from "react";
+import styles from "./index.module.scss";
+function Stores3() {
+  return (
+    <div className={styles.Stores3}>
+      <h1>Stores3</h1>
+    </div>
+  );
+}
+
+const MemoMemoStores3 = React.memo(Stores3);
+
+export default MemoMemoStores3;

+ 0 - 14
src/pages/StoresSon/初始化组件 copy 2/index.tsx

@@ -1,14 +0,0 @@
-import React from "react";
-import styles from "./index.module.scss";
- function AAAAA() {
-  
-  return (
-    <div className={styles.AAAAA}>
-      <h1>AAAAA</h1>
-    </div>
-  )
-}
-
-const MemoAAAAA = React.memo(AAAAA);
-
-export default MemoAAAAA;

+ 0 - 5
src/pages/StoresSon/初始化组件 copy/index.module.scss

@@ -1,5 +0,0 @@
-.AAAAA{
-  :global{
-    
-  }
-}

+ 0 - 14
src/pages/StoresSon/初始化组件 copy/index.tsx

@@ -1,14 +0,0 @@
-import React from "react";
-import styles from "./index.module.scss";
- function AAAAA() {
-  
-  return (
-    <div className={styles.AAAAA}>
-      <h1>AAAAA</h1>
-    </div>
-  )
-}
-
-const MemoAAAAA = React.memo(AAAAA);
-
-export default MemoAAAAA;

+ 0 - 14
src/pages/StoresSon/初始化组件/index.tsx

@@ -1,14 +0,0 @@
-import React from "react";
-import styles from "./index.module.scss";
- function AAAAA() {
-  
-  return (
-    <div className={styles.AAAAA}>
-      <h1>AAAAA</h1>
-    </div>
-  )
-}
-
-const MemoAAAAA = React.memo(AAAAA);
-
-export default MemoAAAAA;

+ 34 - 0
src/store/action/stores1.ts

@@ -0,0 +1,34 @@
+import http from "@/utils/http";
+import { AppDispatch } from "..";
+
+/**
+ * 新建或编辑 库区  库房  货架
+ */
+export const stores1AddAPI = (data: any) => {
+  return http.post("cms/storage/save", data);
+};
+
+/**
+ * 获取库房列表
+ */
+export const getStores1ListAPI = () => {
+  return async (dispatch: AppDispatch) => {
+    // 获取列表数据
+    const res: any = await http.get("cms/storage/getTree");
+    dispatch({ type: "stores1/getInfoList", payload: res.data });
+  };
+};
+
+/**
+ * 删除
+ */
+export const stores1DelAPI = (id: number) => {
+  return http.get(`cms/storage/remove/${id}`);
+};
+
+/**
+ * 通过id获取详情
+ */
+export const getStores1DetailAPI = (id: number) => {
+  return http.get(`cms/storage/detail/${id}`);
+};

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

@@ -3,6 +3,7 @@ import loginReducer from "./login";
 import object1Reducer from "./object1";
 import object2Reducer from "./object2";
 import object3Reducer from "./object3";
+import stores1Reducer from "./stores1";
 
 // 合并 reducer
 const rootReducer = combineReducers({
@@ -10,6 +11,7 @@ const rootReducer = combineReducers({
   object1Store: object1Reducer,
   object2Store: object2Reducer,
   object3Store: object3Reducer,
+  stores1Store: stores1Reducer,
 });
 
 export default rootReducer;

+ 17 - 0
src/store/reducer/stores1.ts

@@ -0,0 +1,17 @@
+// 初始化状态应用注解
+const initState = {
+  infoList: [] as any,
+};
+
+type ActionType = { type: "stores1/getInfoList"; payload: any };
+// 频道 reducer
+export default function stores1Reducer(state = initState, action: ActionType) {
+  switch (action.type) {
+    // 库房设置数据
+    case "stores1/getInfoList":
+      return { ...state, infoList: action.payload };
+
+    default:
+      return state;
+  }
+}