Bläddra i källkod

展览管理ok

shaogen1995 1 år sedan
förälder
incheckning
209745ba1e

+ 45 - 1
src/components/ZupTypes/index.module.scss

@@ -96,6 +96,30 @@
             position: relative;
             position: relative;
             margin-bottom: 20px;
             margin-bottom: 20px;
             cursor: move;
             cursor: move;
+            position: relative;
+
+            // 修改图片名字
+            .ZTbox1ImgRowName {
+              font-size: 12px;
+              line-height: 22px;
+              position: absolute;
+              left: 0;
+              bottom: 25px;
+              width: 100%;
+              cursor: pointer;
+              height: 24px;
+              padding: 0 3px;
+              background-color: rgba(0, 0, 0, 0.8);
+              color: #fff;
+              text-align: center;
+              overflow: hidden;
+              text-overflow: ellipsis;
+              white-space: nowrap;
+
+              &:hover {
+                color: var(--themeColor);
+              }
+            }
 
 
             .ZTbox1ImgRowIcon {
             .ZTbox1ImgRowIcon {
               width: 100%;
               width: 100%;
@@ -140,9 +164,29 @@
       color: #ff4d4f;
       color: #ff4d4f;
       top: -10px;
       top: -10px;
     }
     }
-    .ZcheckTxtAc{
+
+    .ZcheckTxtAc {
       top: 2px;
       top: 2px;
       opacity: 1;
       opacity: 1;
     }
     }
   }
   }
+}
+
+
+// 查看情况
+.ZupTypesLook {
+  :global {}
+}
+
+// 修改图片名字的弹窗
+.ZupTypesMo {
+  :global {
+    .ant-modal-close {
+      display: none;
+    }
+    .ZupTypesMoBtn {
+      margin-top: 24px;
+      text-align: center;
+    }
+  }
 }
 }

+ 151 - 22
src/components/ZupTypes/index.tsx

@@ -6,7 +6,7 @@ import React, {
   useState,
   useState,
 } from "react";
 } from "react";
 import styles from "./index.module.scss";
 import styles from "./index.module.scss";
-import { Button, Checkbox } from "antd";
+import { Button, Checkbox, Input, Modal } from "antd";
 import { forwardRef, useImperativeHandle } from "react";
 import { forwardRef, useImperativeHandle } from "react";
 import { baseURL } from "@/utils/http";
 import { baseURL } from "@/utils/http";
 import {
 import {
@@ -24,12 +24,14 @@ import store from "@/store";
 import ImageLazy from "../ImageLazy";
 import ImageLazy from "../ImageLazy";
 import classNames from "classnames";
 import classNames from "classnames";
 import MyPopconfirm from "../MyPopconfirm";
 import MyPopconfirm from "../MyPopconfirm";
+import { A2_APIchangeImgName } from "@/store/action/A2exhibition";
 
 
 export type FileListType = {
 export type FileListType = {
   fileName: string;
   fileName: string;
   filePath: string;
   filePath: string;
   id: number;
   id: number;
   type: "model" | "img" | "audio" | "video";
   type: "model" | "img" | "audio" | "video";
+  imgName: string;
 };
 };
 
 
 type Props = {
 type Props = {
@@ -45,6 +47,8 @@ type Props = {
   audioSize?: number; //音频大小限制
   audioSize?: number; //音频大小限制
   videoSize?: number; //视频大小限制
   videoSize?: number; //视频大小限制
   videoTit?: string; //视频上传的提示语
   videoTit?: string; //视频上传的提示语
+  isTypeShow?: boolean; //默认就选中(只有一个类型的时候)
+  isUpName?: boolean; //是否能修改图片名字
 };
 };
 
 
 function ZupTypes(
 function ZupTypes(
@@ -60,9 +64,14 @@ function ZupTypes(
     audioSize = 10,
     audioSize = 10,
     videoSize = 500,
     videoSize = 500,
     videoTit = "",
     videoTit = "",
+    isTypeShow = false,
+    isUpName = false,
   }: Props,
   }: Props,
   ref: any
   ref: any
 ) {
 ) {
+  // 筛选
+  const [typeCheck, setTypeCheck] = useState<string[]>([]);
+
   // 筛选数组
   // 筛选数组
   const typeCheckArr = useMemo(() => {
   const typeCheckArr = useMemo(() => {
     const arr = [
     const arr = [
@@ -71,11 +80,15 @@ function ZupTypes(
       { label: "音频", value: "audio" },
       { label: "音频", value: "audio" },
       { label: "视频", value: "video" },
       { label: "视频", value: "video" },
     ];
     ];
-    return arr.filter((v) => selecFlag.includes(v.label));
-  }, [selecFlag]);
 
 
-  // 筛选
-  const [typeCheck, setTypeCheck] = useState<string[]>([]);
+    const arrRes = arr.filter((v) => selecFlag.includes(v.label));
+    if (arrRes.length <= 1 && isTypeShow) {
+      setTypeCheck([arrRes[0].value]);
+      // 默认就选中(只有一个类型的时候)
+    }
+
+    return arrRes;
+  }, [isTypeShow, selecFlag]);
 
 
   // 上传附件的信息
   // 上传附件的信息
   const [fileList, setFileList] = useState({
   const [fileList, setFileList] = useState({
@@ -119,8 +132,8 @@ function ZupTypes(
         // 拿到files信息
         // 拿到files信息
         const filesInfo = e.target.files[0];
         const filesInfo = e.target.files[0];
 
 
-        let anType = ["image/jpeg", "image/png", "image/gif"];
-        let anTit1 = "只支持png、jpg、gif和jpeg格式!";
+        let anType = ["image/jpeg", "image/png"];
+        let anTit1 = "只支持png、jpg格式!";
         let anTit2 = `最大支持${imgSize}M!`;
         let anTit2 = `最大支持${imgSize}M!`;
         let anSize = imgSize * 1024 * 1024;
         let anSize = imgSize * 1024 * 1024;
 
 
@@ -165,6 +178,12 @@ function ZupTypes(
         fd.append("type", fileOneType);
         fd.append("type", fileOneType);
         fd.append("dirCode", dirCode);
         fd.append("dirCode", dirCode);
         fd.append("isDb", "true");
         fd.append("isDb", "true");
+
+        //初始图片 fileName为:未命名
+        if (isUpName) {
+          fd.append("isDefaultName", "false");
+        }
+
         fd.append("file", filesInfo);
         fd.append("file", filesInfo);
 
 
         e.target.value = "";
         e.target.value = "";
@@ -175,7 +194,10 @@ function ZupTypes(
           if (res.code === 0) {
           if (res.code === 0) {
             MessageFu.success("上传成功!");
             MessageFu.success("上传成功!");
             if (fileOneType === "img")
             if (fileOneType === "img")
-              setFileList({ ...fileList, img: [res.data, ...fileList.img] });
+              setFileList({
+                ...fileList,
+                img: [{ ...res.data, imgName: "未命名" }, ...fileList.img],
+              });
             else setFileList({ ...fileList, [fileOneType]: res.data });
             else setFileList({ ...fileList, [fileOneType]: res.data });
           }
           }
           fileDomInitialFu();
           fileDomInitialFu();
@@ -190,6 +212,7 @@ function ZupTypes(
       fileList,
       fileList,
       fileOneType,
       fileOneType,
       imgSize,
       imgSize,
+      isUpName,
       modelSize,
       modelSize,
       myUrl,
       myUrl,
       videoSize,
       videoSize,
@@ -312,8 +335,9 @@ function ZupTypes(
       };
       };
 
 
       data.forEach((v) => {
       data.forEach((v) => {
-        if (v.type === "img") obj.img.push(v);
-        else obj[v.type!] = v;
+        if (v.type === "img") {
+          obj.img.push({ ...v, imgName: v.fileName });
+        } else obj[v.type!] = v;
       });
       });
       setFileList(obj);
       setFileList(obj);
     }
     }
@@ -353,14 +377,60 @@ function ZupTypes(
     fileComFileResFu,
     fileComFileResFu,
   }));
   }));
 
 
+  // 修改图片名称
+  const [isNameChange, setIsNameChange] = useState({
+    id: 0,
+    oldName: "",
+    newName: "",
+  });
+
+  // 关闭弹窗
+  const isNameChangeXFu = useCallback(() => {
+    setIsNameChange({ id: 0, oldName: "", newName: "" });
+  }, []);
+
+  // 点击图片名字-出来弹窗
+  const isNameChangeFu = useCallback(
+    (item: FileListType) => {
+      if (isLook) return;
+      setIsNameChange({ id: item.id, oldName: item.imgName, newName: "" });
+    },
+    [isLook]
+  );
+
+  // 修改完这点击 确定修改
+  const isNameChangeOkFu = useCallback(async () => {
+    if (!isNameChange.newName) return MessageFu.warning("图片名不能为空!");
+
+    const res = await A2_APIchangeImgName({
+      id: isNameChange.id,
+      fileName: isNameChange.newName,
+    });
+
+    if (res.code === 0) {
+      MessageFu.success("修改图片名成功!");
+      setFileList({
+        ...fileList,
+        img: fileList.img.map((v) => ({
+          ...v,
+          imgName: v.id === isNameChange.id ? isNameChange.newName : v.imgName,
+        })),
+      });
+      isNameChangeXFu();
+    }
+  }, [fileList, isNameChange.id, isNameChange.newName, isNameChangeXFu]);
+  //
+
   return (
   return (
-    <div className={styles.ZupTypes}>
+    <div
+      className={classNames(styles.ZupTypes, isLook ? styles.ZupTypesLook : "")}
+    >
       <input
       <input
         id="upInput"
         id="upInput"
         type="file"
         type="file"
         accept={
         accept={
           fileOneType === "img"
           fileOneType === "img"
-            ? ".gif,.png,.jpg,.jpeg"
+            ? ".png,.jpg,.jpeg"
             : fileOneType === "audio"
             : fileOneType === "audio"
             ? ".mp3"
             ? ".mp3"
             : fileOneType === "model"
             : fileOneType === "model"
@@ -370,12 +440,13 @@ function ZupTypes(
         ref={myInput}
         ref={myInput}
         onChange={(e) => handeUpPhoto2(e)}
         onChange={(e) => handeUpPhoto2(e)}
       />
       />
-
-      <Checkbox.Group
-        options={typeCheckArr}
-        value={typeCheck}
-        onChange={(e) => setTypeCheck(e as string[])}
-      />
+      <div hidden={isTypeShow}>
+        <Checkbox.Group
+          options={typeCheckArr}
+          value={typeCheck}
+          onChange={(e) => setTypeCheck(e as string[])}
+        />
+      </div>
 
 
       {/* -----------模型 */}
       {/* -----------模型 */}
       {resOneDivDom("model")}
       {resOneDivDom("model")}
@@ -383,11 +454,14 @@ function ZupTypes(
       {/* -----------图片 */}
       {/* -----------图片 */}
       <div className="ZTboxImgMain" hidden={!typeCheck.includes("img")}>
       <div className="ZTboxImgMain" hidden={!typeCheck.includes("img")}>
         <div className="ZTboxImgBox">
         <div className="ZTboxImgBox">
-          <div className="ZTbox1">
+          <div className="ZTbox1" hidden={isTypeShow}>
             <span> </span> 图片:
             <span> </span> 图片:
           </div>
           </div>
 
 
-          <div className="ZTbox1Img">
+          <div
+            className="ZTbox1Img"
+            style={{ width: isTypeShow ? "100%" : "" }}
+          >
             <div
             <div
               hidden={!!fileList.img.length && fileList.img.length >= imgLength}
               hidden={!!fileList.img.length && fileList.img.length >= imgLength}
               className="ZTbox1ImgIcon"
               className="ZTbox1ImgIcon"
@@ -413,6 +487,18 @@ function ZupTypes(
                     src={v.filePath}
                     src={v.filePath}
                   />
                   />
                 ) : null}
                 ) : null}
+
+                {/* 修改图片名字 */}
+                {isUpName ? (
+                  <div
+                    title={v.imgName}
+                    className="ZTbox1ImgRowName"
+                    onClick={() => isNameChangeFu(v)}
+                  >
+                    {v.imgName}
+                  </div>
+                ) : null}
+
                 <div className="ZTbox1ImgRowIcon">
                 <div className="ZTbox1ImgRowIcon">
                   <EyeOutlined
                   <EyeOutlined
                     onClick={() =>
                     onClick={() =>
@@ -455,7 +541,7 @@ function ZupTypes(
               <br />
               <br />
             </>
             </>
           ) : null}
           ) : null}
-          支持png、jpg、gif和jpeg的图片格式;最大支持5M;最多支持{imgLength}张。
+          支持png、jpg的图片格式;最大支持5M;最多支持{imgLength}张。
         </div>
         </div>
       </div>
       </div>
 
 
@@ -472,8 +558,51 @@ function ZupTypes(
           fileCheck && fileCheckFu ? "ZcheckTxtAc" : ""
           fileCheck && fileCheckFu ? "ZcheckTxtAc" : ""
         )}
         )}
       >
       >
-        请最少勾选一个文件类型,并且上传对应的附件!
+        请最少上传一个展品!
       </div>
       </div>
+
+      {/* 点击修改名字出来的弹窗 */}
+      {isNameChange.id ? (
+        <Modal
+          wrapClassName={styles.ZupTypesMo}
+          open={true}
+          title="修改展品图片名称"
+          footer={
+            [] // 设置footer为空,去掉 取消 确定默认按钮
+          }
+        >
+          <br />
+          <div className="ZupTypesMoRow">
+            <strong>当前名:</strong>
+            {isNameChange.oldName}
+          </div>
+          <div className="ZupTypesMoRow">
+            <br />
+            <strong>修改为:</strong>
+            <Input
+              style={{ width: 400 }}
+              placeholder="请输入图片名"
+              maxLength={50}
+              showCount
+              value={isNameChange.newName}
+              onChange={(e) => {
+                setIsNameChange({
+                  ...isNameChange,
+                  newName: e.target.value.replace(/\s+/g, ""),
+                });
+              }}
+            />
+          </div>
+
+          <div className="ZupTypesMoBtn">
+            <Button onClick={isNameChangeXFu}>取消</Button>
+            &emsp;
+            <Button type="primary" onClick={isNameChangeOkFu}>
+              修改
+            </Button>
+          </div>
+        </Modal>
+      ) : null}
     </div>
     </div>
   );
   );
 }
 }

+ 1 - 1
src/pages/A1event/index.tsx

@@ -119,7 +119,7 @@ function A1event() {
             <span>标题:</span>
             <span>标题:</span>
             <Input
             <Input
               key={inputKey}
               key={inputKey}
-              maxLength={10}
+              maxLength={50}
               showCount
               showCount
               style={{ width: 300 }}
               style={{ width: 300 }}
               placeholder="请输入关键字,不超过50字"
               placeholder="请输入关键字,不超过50字"

+ 123 - 0
src/pages/A2exhibition/A2add/index.module.scss

@@ -0,0 +1,123 @@
+.A2add {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 12;
+  background-color: #fff;
+  border-radius: 10px;
+  padding: 24px;
+
+  :global {
+    .A2eMain {
+      width: 100%;
+      height: 100%;
+      overflow-y: auto;
+
+
+      .A2fromRow {
+        position: relative;
+        width: 800px;
+        height: 56px;
+
+        // &>div {
+        //   width: 100%;
+        // }
+
+        .A2_1Frow {
+          position: absolute;
+          top: 0px;
+          left: 600px;
+          width: 200px;
+        }
+
+        .A2_4Frow {
+          position: absolute;
+          left: 400px;
+          top: 4px;
+        }
+
+        .A2_6Frow {
+          position: absolute;
+          left: 200px;
+          top: 5px;
+          color: #999;
+          font-size: 12px;
+        }
+
+      }
+
+      .ant-form {
+        width: 800px;
+
+        // .ant-input-affix-wrapper{
+        //   width: 800px;
+        // }
+        .formRow {
+          display: flex;
+
+          .formLeft {
+            position: relative;
+            top: 3px;
+            width: 100px;
+            text-align: right;
+
+            &>span {
+              color: #ff4d4f;
+            }
+          }
+
+          .formRight {
+            width: calc(100% - 100px);
+          }
+
+
+          .formRight5Tit {
+            position: relative;
+            top: -10px;
+            transition: top .2s;
+            margin: 5px 0;
+            color: #ff4d4f;
+            opacity: 0;
+            pointer-events: none;
+          }
+
+          .formRight5TitErr {
+            opacity: 1;
+            top: 0;
+          }
+        }
+
+
+        .A2Ebtn {
+          position: absolute;
+          z-index: 10;
+          left: 1200px;
+          top: 50%;
+          transform: translateY(-50%);
+        }
+      }
+    }
+
+
+    // 从查看进入
+    .A2eMainLook {
+      .ant-picker {
+        pointer-events: none;
+      }
+
+      .ant-checkbox-wrapper {
+        pointer-events: none;
+      }
+
+      .ant-input-number {
+        pointer-events: none;
+      }
+
+      .ant-select {
+        pointer-events: none;
+      }
+    }
+  }
+}

+ 575 - 0
src/pages/A2exhibition/A2add/index.tsx

@@ -0,0 +1,575 @@
+import React, { useCallback, useEffect, useRef, useState } from "react";
+import styles from "./index.module.scss";
+import {
+  Button,
+  DatePicker,
+  Form,
+  FormInstance,
+  Input,
+  InputNumber,
+  Radio,
+  Select,
+} from "antd";
+import { A1EditInfoType } from "@/pages/A1event/data";
+import { A2_APIgetInfo, A2_APIsave } from "@/store/action/A2exhibition";
+import dayjs from "dayjs";
+import { MessageFu } from "@/utils/message";
+import classNames from "classnames";
+import ZupAudio, { ZupAudioType } from "@/components/ZupAudio";
+import ZupOne from "@/components/ZupOne";
+import MyPopconfirm from "@/components/MyPopconfirm";
+import ZRichTexts from "@/components/ZRichTexts";
+import TextArea from "antd/es/input/TextArea";
+import ZupTypes from "@/components/ZupTypes";
+
+const { RangePicker } = DatePicker;
+
+type Props = {
+  editInfo: A1EditInfoType;
+  closeFu: () => void;
+  editTableFu: () => void;
+  addTableFu: () => void;
+};
+
+function A2add({ editInfo, closeFu, editTableFu, addTableFu }: Props) {
+  const [dirCode, setDirCode] = useState("");
+
+  // 表单的ref
+  const FormBoxRef = useRef<FormInstance>(null);
+
+  // 封面图的ref
+  const ZupThumbRef = useRef<any>(null);
+
+  // PC海报图的ref
+  const ZupPcImgRef = useRef<any>(null);
+
+  // 富文本的ref
+  const ZRichTextRef = useRef<any>(null);
+
+  // 展品的ref
+  const ZupFilesRef1 = useRef<any>(null);
+
+  // 展馆的ref
+  const ZupFilesRef2 = useRef<any>(null);
+
+  // 标题的音频
+  const [nameAudio, setNameAudio] = useState({
+    fileName: "",
+    filePath: "",
+  });
+
+  // 编辑/查看 进入页面 获取信息
+  const getInfoFu = useCallback(async (id: number) => {
+    const res = await A2_APIgetInfo(id);
+    if (res.code === 0) {
+      const data = res.data;
+
+      setDirCode(data.dirCode);
+
+      // 展示展品
+      ZupFilesRef1.current?.setFileComFileFu({
+        type: "img",
+        fileList: data.exhibitsFile || [],
+      });
+
+      // 展示展馆
+      ZupFilesRef2.current?.setFileComFileFu({
+        type: "img",
+        fileList: data.exhibitionFile || [],
+      });
+
+      // 设置 临时展览 / 常设展览
+      setTimeType(data.type);
+
+      // 设置 常设展览描述
+      setTimeVal(data.typeRemark);
+
+      // 设置 临时展览 时间
+      if (data.dateStart && data.dateEnd) {
+        setTimeArr([dayjs(data.dateStart), dayjs(data.dateEnd)]);
+      }
+
+      // 设置地址
+      setAddrType({
+        key: data.addrType,
+        txt: data.address,
+      });
+
+      // 设置标题的 音频
+      if (data.fileName && data.filePath) {
+        setNameAudio({
+          fileName: data.fileName,
+          filePath: data.filePath,
+        });
+      }
+      // 设置富文本
+      ZRichTextRef.current?.ritxtShowFu(JSON.parse(data.rtf));
+
+      const obj = {
+        ...data,
+        myTime: dayjs(data.datePublish),
+      };
+
+      FormBoxRef.current?.setFieldsValue(obj);
+
+      // 设置封面图
+      ZupThumbRef.current?.setFileComFileFu({
+        fileName: "",
+        filePath: data.thumb,
+      });
+
+      // 设置Pc海报
+      ZupPcImgRef.current?.setFileComFileFu({
+        fileName: "",
+        filePath: data.thumbPc,
+      });
+    }
+  }, []);
+
+  // 临时展览 常设展览的切换
+  const [timeType, setTimeType] = useState("long");
+  const [timeVal, setTimeVal] = useState("");
+  // 格式为dayjs的格式,需要转换
+  const [timeArr, setTimeArr] = useState<any>(null);
+
+  // 地址
+  const [addrType, setAddrType] = useState({
+    key: "inland",
+    txt: "",
+  });
+
+  const addrTypeChangeFu = useCallback(
+    (key: "key" | "txt", val: string) => {
+      setAddrType({ ...addrType, [key]: val });
+    },
+    [addrType]
+  );
+
+  // 附件 是否 已经点击过确定
+  const [fileCheck, setFileCheck] = useState(false);
+
+  // 没有通过校验
+  const onFinishFailed = useCallback(() => {
+    setFileCheck(true);
+  }, []);
+
+  //  通过校验点击确定
+  const onFinish = useCallback(
+    async (values: any) => {
+      setFileCheck(true);
+
+      const coverUrl1 = ZupThumbRef.current?.fileComFileResFu();
+      // 没有传 封面图
+      if (!coverUrl1.filePath) return MessageFu.warning("请上传封面图!");
+
+      // 发布日期
+      const datePublish = dayjs(values.myTime).format("YYYY-MM-DD");
+
+      // 临时展览的时候要判断
+      if (timeType === "temp") {
+        if (!timeArr || !timeArr[0])
+          return MessageFu.warning("请选择临时展览时间!");
+      }
+      // 地址校验
+      if (!addrType.txt) return MessageFu.warning("请输入地址!");
+
+      let dateStart = "";
+      let dateEnd = "";
+      if (timeArr && timeArr[0] && timeArr[1]) {
+        dateStart = dayjs(timeArr[0]).format("YYYY-MM-DD");
+        dateEnd = dayjs(timeArr[1]).format("YYYY-MM-DD");
+      }
+
+      // 富文本校验不通过
+      const rtf = ZRichTextRef.current?.fatherBtnOkFu() || { flag: true };
+
+      if (rtf.flag) return MessageFu.warning("请输入完整正文!");
+
+      // 展品的校验
+      const { sonFileIds: exhibitsFileIds } =
+        ZupFilesRef1.current?.fileComFileResFu() || [];
+
+      if (exhibitsFileIds.length <= 0) {
+        return MessageFu.warning("请最少上传一个展品!");
+      }
+
+      // 展馆的校验
+      const { sonFileIds: exhibitionFileIds } =
+        ZupFilesRef2.current?.fileComFileResFu() || [];
+
+      if (exhibitionFileIds.length <= 0) {
+        return MessageFu.warning("请最少上传一个展馆!");
+      }
+
+      // pc海报
+      const coverUrl2 = ZupPcImgRef.current?.fileComFileResFu();
+
+      const obj = {
+        ...values,
+        id: editInfo.id > 0 ? editInfo.id : null,
+        datePublish,
+        thumb: coverUrl1.filePath,
+        thumbPc: coverUrl2.filePath,
+        rtf: JSON.stringify(rtf.val || ""),
+        fileName: nameAudio.fileName,
+        filePath: nameAudio.filePath,
+        type: timeType,
+        dateStart,
+        dateEnd,
+        addrType: addrType.key,
+        address: addrType.txt,
+        exhibitsFileIds: exhibitsFileIds.join(","),
+        exhibitionFileIds: exhibitionFileIds.join(","),
+        dirCode,
+        typeRemark: timeVal,
+      };
+
+      // if (obj) {
+      //   console.log(123, obj);
+      //   return;
+      // }
+
+      const res = await A2_APIsave(obj);
+
+      if (res.code === 0) {
+        MessageFu.success(`${editInfo.txt}成功!`);
+        editInfo.id > 0 ? editTableFu() : addTableFu();
+        closeFu();
+      }
+    },
+    [
+      timeVal,
+      dirCode,
+      addTableFu,
+      addrType.key,
+      addrType.txt,
+      closeFu,
+      editInfo.id,
+      editInfo.txt,
+      editTableFu,
+      nameAudio.fileName,
+      nameAudio.filePath,
+      timeArr,
+      timeType,
+    ]
+  );
+
+  useEffect(() => {
+    if (editInfo.id > 0) {
+      getInfoFu(editInfo.id);
+    } else {
+      setDirCode(Date.now() + "");
+      FormBoxRef.current?.setFieldsValue({
+        myTime: dayjs(Date.now()),
+        sort: 999,
+        display: 1,
+      });
+    }
+  }, [editInfo.id, getInfoFu]);
+
+  return (
+    <div className={styles.A2add}>
+      <div
+        className={classNames(
+          "A2eMain",
+          editInfo.txt === "查看" ? "A2eMainLook" : ""
+        )}
+      >
+        <Form
+          ref={FormBoxRef}
+          name="basic"
+          labelCol={{ span: 3 }}
+          onFinish={onFinish}
+          onFinishFailed={onFinishFailed}
+          autoComplete="off"
+          scrollToFirstError
+        >
+          <div className="A2fromRow">
+            <Form.Item
+              label="标题"
+              name="name"
+              rules={[{ required: true, message: "请输入标题!" }]}
+              getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
+            >
+              <Input
+                readOnly={editInfo.txt === "查看"}
+                style={{ width: "500px" }}
+                maxLength={50}
+                showCount
+                placeholder="请输入内容"
+              />
+            </Form.Item>
+            {/* 标题的无障碍音频 */}
+            <div className="A2_1Frow">
+              <ZupAudio
+                fileInfo={nameAudio}
+                upDataFu={(info) => setNameAudio(info)}
+                delFu={() => setNameAudio({} as ZupAudioType)}
+                dirCode={dirCode}
+                myUrl="cms/exhibition/upload"
+                isLook={editInfo.txt === "查看"}
+              />
+            </div>
+          </div>
+
+          {/* 封面 */}
+          <div className="formRow">
+            <div className="formLeft">
+              <span>* </span>
+              封面:
+            </div>
+            <div className="formRight">
+              <ZupOne
+                ref={ZupThumbRef}
+                isLook={editInfo.txt === "查看"}
+                fileCheck={fileCheck}
+                size={5}
+                dirCode={dirCode}
+                myUrl="cms/exhibition/upload"
+                format={["image/jpeg", "image/png"]}
+                formatTxt="png、jpg和jpeg"
+                checkTxt="请上传封面图!"
+                upTxt="最多1张"
+                myType="thumb"
+              />
+            </div>
+          </div>
+
+          {/* PC海报 */}
+          <div className="formRow">
+            <div className="formLeft">
+              <span> </span>
+              PC海报:
+            </div>
+            <div className="formRight">
+              <ZupOne
+                ref={ZupPcImgRef}
+                isLook={editInfo.txt === "查看"}
+                fileCheck={false}
+                size={5}
+                dirCode={dirCode}
+                myUrl="cms/exhibition/upload"
+                format={["image/jpeg", "image/png"]}
+                formatTxt="png、jpg和jpeg"
+                checkTxt="请上传封面图!"
+                upTxt="最多1张"
+                myType="thumb"
+              />
+            </div>
+          </div>
+
+          <Form.Item label="摘要" name="digest">
+            <TextArea placeholder="请输入内容" maxLength={200} showCount />
+          </Form.Item>
+
+          {/* 时间 */}
+          <div className="formRow">
+            <div className="formLeft">
+              <span>* </span>
+              时间:
+            </div>
+            <div className="formRight">
+              <div>
+                <Select
+                  value={timeType}
+                  onChange={(e) => setTimeType(e)}
+                  style={{ width: 150 }}
+                  options={[
+                    { value: "long", label: "常设展览" },
+                    { value: "temp", label: "临时展览" },
+                  ]}
+                />
+                &emsp;
+                {timeType === "long" ? (
+                  <Input
+                    style={{ width: 536 }}
+                    maxLength={50}
+                    showCount
+                    value={timeVal}
+                    onChange={(e) => setTimeVal(e.target.value)}
+                    placeholder="在此填入时间备注(选填),如9:00 - 17:00 (closed on Mondays)"
+                  />
+                ) : (
+                  <RangePicker
+                    value={timeArr && timeArr[0] ? timeArr : null}
+                    onChange={(val) => setTimeArr(val)}
+                  />
+                )}
+              </div>
+              <div
+                className={classNames(
+                  "formRight5Tit",
+                  fileCheck && timeType === "temp" && (!timeArr || !timeArr[0])
+                    ? "formRight5TitErr"
+                    : ""
+                )}
+              >
+                请选择时间!
+              </div>
+            </div>
+          </div>
+
+          {/* 地址 */}
+          <div className="formRow">
+            <div className="formLeft">
+              <span>* </span>
+              地址:
+            </div>
+            <div className="formRight">
+              <div>
+                {[
+                  { name: "国内", key: "inland" },
+                  { name: "国外", key: "foreign" },
+                ].map((item) => (
+                  <Radio
+                    key={item.name}
+                    checked={addrType.key === item.key}
+                    onClick={() => addrTypeChangeFu("key", item.key)}
+                  >
+                    {item.name}
+                  </Radio>
+                ))}
+                &emsp;
+                <Input
+                  style={{ width: 536, marginLeft: 14 }}
+                  maxLength={50}
+                  showCount
+                  value={addrType.txt}
+                  onChange={(e) => addrTypeChangeFu("txt", e.target.value)}
+                  placeholder="请输入内容"
+                />
+              </div>
+              <div
+                className={classNames(
+                  "formRight5Tit",
+                  fileCheck && !addrType.txt ? "formRight5TitErr" : ""
+                )}
+              >
+                请输入地址!
+              </div>
+            </div>
+          </div>
+
+          {/* 概况 */}
+          <div className="formRow">
+            <div className="formLeft">
+              <span>* </span>
+              概况:
+            </div>
+            <div className="formRight">
+              <ZRichTexts
+                check={fileCheck}
+                dirCode={dirCode}
+                isLook={editInfo.txt === "查看"}
+                ref={ZRichTextRef}
+                myUrl="cms/exhibition/upload"
+              />
+            </div>
+          </div>
+
+          {/* 展品 */}
+          <div className="formRow">
+            <div className="formLeft">
+              <span>* </span>
+              展品:
+            </div>
+            <div className="formRight">
+              <ZupTypes
+                ref={ZupFilesRef1}
+                selecFlag="图片"
+                fileCheck={fileCheck}
+                dirCode={dirCode}
+                myUrl="cms/exhibition/upload"
+                isLook={editInfo.txt === "查看"}
+                imgLength={30}
+                isTypeShow={true}
+                isUpName={true}
+              />
+            </div>
+          </div>
+
+          {/* 展馆 */}
+          <div className="formRow">
+            <div className="formLeft">
+              <span>* </span>
+              展馆:
+            </div>
+            <div className="formRight">
+              <ZupTypes
+                ref={ZupFilesRef2}
+                selecFlag="图片"
+                fileCheck={fileCheck}
+                dirCode={dirCode}
+                myUrl="cms/exhibition/upload"
+                isLook={editInfo.txt === "查看"}
+                imgLength={30}
+                isTypeShow={true}
+              />
+            </div>
+          </div>
+
+          <Form.Item
+            label="发布日期"
+            name="myTime"
+            rules={[{ required: true, message: "请选择发布日期!" }]}
+          >
+            <DatePicker />
+          </Form.Item>
+
+          <div className="A2fromRow">
+            <Form.Item
+              label="排序值"
+              name="sort"
+              rules={[{ required: true, message: "请输入排序值!" }]}
+            >
+              <InputNumber
+                min={1}
+                max={999}
+                precision={0}
+                placeholder="请输入"
+              />
+            </Form.Item>
+            <div className="A2_6Frow">
+              请输入1~999的数字。数字越小,排序越靠前。数字相同时,更新发布的内容排在前面
+            </div>
+          </div>
+
+          <Form.Item
+            label="状态"
+            name="display"
+            rules={[{ required: true, message: "请选择状态!" }]}
+          >
+            <Select
+              placeholder="请选择状态"
+              style={{ width: 200 }}
+              options={[
+                { value: 1, label: "发布" },
+                { value: 0, label: "不发布" },
+              ]}
+            />
+          </Form.Item>
+
+          {/* 确定和取消按钮 */}
+          <Form.Item className="A2Ebtn">
+            {editInfo.txt === "查看" ? (
+              <Button onClick={closeFu}>返回</Button>
+            ) : (
+              <>
+                <Button type="primary" htmlType="submit">
+                  提交
+                </Button>
+                <br />
+                <br />
+                <MyPopconfirm txtK="取消" onConfirm={closeFu} />
+              </>
+            )}
+          </Form.Item>
+        </Form>
+      </div>
+    </div>
+  );
+}
+
+const MemoA2add = React.memo(A2add);
+
+export default MemoA2add;

+ 20 - 0
src/pages/A2exhibition/data.ts

@@ -0,0 +1,20 @@
+export type A2FromDataType = {
+  pageNum: number;
+  pageSize: number;
+  searchKey: string;
+  type: "" | "temp" | "long";
+  display: "" | 0 | 1;
+  addrType: "" | "inland" | "foreign";
+};
+
+export const A2Selct_1 = [
+  { value: "", label: "全部" },
+  { value: "inland", label: "国内" },
+  { value: "foreign", label: "国外" },
+];
+
+export const A2Selct_2 = [
+  { value: "", label: "全部" },
+  { value: "temp", label: "临时展览" },
+  { value: "long", label: "常设展览" },
+];

+ 25 - 2
src/pages/A2exhibition/index.module.scss

@@ -1,5 +1,28 @@
 .A2exhibition{
 .A2exhibition{
-  :global{
-    
+  position: relative;
+
+  :global {
+    .A2top {
+      padding: 15px 24px;
+      border-radius: 10px;
+      background-color: #fff;
+      display: flex;
+      justify-content: space-between;
+
+      .A2topLeft {
+        display: flex;
+        &>div {
+          margin-right: 24px;
+        }
+      }
+    }
+
+    .A2tableBox {
+      border-radius: 10px;
+      overflow: hidden;
+      margin-top: 15px;
+      height: calc(100% - 77px);
+      background-color: #fff;
+    }
   }
   }
 }
 }

+ 210 - 5
src/pages/A2exhibition/index.tsx

@@ -1,12 +1,217 @@
-import React from "react";
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
 import styles from "./index.module.scss";
 import styles from "./index.module.scss";
- function A2exhibition() {
-  
+import { useDispatch, useSelector } from "react-redux";
+import { A2FromDataType, A2Selct_1, A2Selct_2 } from "./data";
+import { A2_APIdel, A2_APIgetList } from "@/store/action/A2exhibition";
+import { A2tableType } from "@/types";
+import { RootState } from "@/store";
+import { MessageFu } from "@/utils/message";
+import { Button, Input, Select } from "antd";
+import MyPopconfirm from "@/components/MyPopconfirm";
+import { A1EditInfoType, A1Selct } from "../A1event/data";
+import MyTable from "@/components/MyTable";
+import { A2tableC } from "@/utils/tableData";
+import A2add from "./A2add";
+function A2exhibition() {
+  const dispatch = useDispatch();
+
+  const [fromData, setFromData] = useState<A2FromDataType>({
+    pageNum: 1,
+    pageSize: 10,
+    searchKey: "",
+    type: "",
+    display: "",
+    addrType: "",
+  });
+  const getListFu = useCallback(() => {
+    dispatch(A2_APIgetList(fromData));
+  }, [dispatch, fromData]);
+
+  useEffect(() => {
+    getListFu();
+  }, [getListFu]);
+
+  const [inputKey, setInputKey] = useState(1);
+
+  // 标题的输入
+  const timeRef = useRef(-1);
+  const fromKeyChangeFu = useCallback(
+    (e: React.ChangeEvent<HTMLInputElement>, key: "searchKey") => {
+      clearTimeout(timeRef.current);
+      timeRef.current = window.setTimeout(() => {
+        setFromData({ ...fromData, [key]: e.target.value, pageNum: 1 });
+      }, 500);
+    },
+    [fromData]
+  );
+
+  // 点击重置
+  const resetSelectFu = useCallback(() => {
+    setInputKey(Date.now());
+    setFromData({
+      pageNum: 1,
+      pageSize: 10,
+      searchKey: "",
+      type: "",
+      display: "",
+      addrType: "",
+    });
+  }, []);
+
+  const tableInfo = useSelector(
+    (state: RootState) => state.A2exhibition.tableInfo
+  );
+
+  const delTableFu = useCallback(
+    async (id: number) => {
+      const res = await A2_APIdel(id);
+      if (res.code === 0) {
+        MessageFu.success("删除成功!");
+        getListFu();
+      }
+    },
+    [getListFu]
+  );
+
+  const tableLastBtn = useMemo(() => {
+    return [
+      {
+        title: "操作",
+        render: (item: A2tableType) => (
+          <>
+            <Button
+              size="small"
+              type="text"
+              onClick={() => setEditInfo({ id: item.id, txt: "查看" })}
+            >
+              查看
+            </Button>
+            <Button
+              size="small"
+              type="text"
+              onClick={() => setEditInfo({ id: item.id, txt: "编辑" })}
+            >
+              编辑
+            </Button>
+            <MyPopconfirm txtK="删除" onConfirm={() => delTableFu(item.id)} />
+          </>
+        ),
+      },
+    ];
+  }, [delTableFu]);
+
+  //查看、新增、编辑
+  const [editInfo, setEditInfo] = useState<A1EditInfoType>({
+    id: 0,
+    txt: "",
+  });
   return (
   return (
     <div className={styles.A2exhibition}>
     <div className={styles.A2exhibition}>
-       <div className="pageTitle">展览管理</div>
+      <div className="pageTitle">
+        展览管理{editInfo.id ? ` - ${editInfo.txt}` : ""}
+      </div>
+
+      {/* 顶部筛选 */}
+      <div className="A2top">
+        <div className="A2topLeft">
+          <div>
+            <span>标题:</span>
+            <Input
+              key={inputKey}
+              maxLength={50}
+              showCount
+              style={{ width: 300 }}
+              placeholder="请输入关键字,不超过50字"
+              allowClear
+              onChange={(e) => fromKeyChangeFu(e, "searchKey")}
+            />
+          </div>
+
+          <div>
+            <span>展览地址:</span>
+            <Select
+              placeholder="请选择"
+              style={{ width: 100 }}
+              value={fromData.addrType}
+              onChange={(e) =>
+                setFromData({ ...fromData, pageNum: 1, addrType: e })
+              }
+              options={A2Selct_1}
+            />
+          </div>
+
+          <div>
+            <span>展览时间:</span>
+            <Select
+              placeholder="请选择"
+              style={{ width: 100 }}
+              value={fromData.type}
+              onChange={(e) =>
+                setFromData({ ...fromData, pageNum: 1, type: e })
+              }
+              options={A2Selct_2}
+            />
+          </div>
+
+          <div>
+            <span>状态:</span>
+            <Select
+              placeholder="请选择"
+              style={{ width: 100 }}
+              value={fromData.display}
+              onChange={(e) =>
+                setFromData({ ...fromData, pageNum: 1, display: e })
+              }
+              options={A1Selct}
+            />
+          </div>
+        </div>
+
+        <div>
+          <Button
+            type="primary"
+            onClick={() => setEditInfo({ id: -1, txt: "新增" })}
+          >
+            新增
+          </Button>
+          &emsp;
+          <Button onClick={resetSelectFu}>重置</Button>
+        </div>
+      </div>
+
+      {/* 表格主体 */}
+      <div className="A2tableBox">
+        <MyTable
+          yHeight={625}
+          list={tableInfo.list}
+          columnsTemp={A2tableC}
+          lastBtn={tableLastBtn}
+          pageNum={fromData.pageNum}
+          pageSize={fromData.pageSize}
+          total={tableInfo.total}
+          onChange={(pageNum, pageSize) =>
+            setFromData({ ...fromData, pageNum, pageSize })
+          }
+        />
+      </div>
+
+      {/* 新增 编辑 查看 */}
+      {editInfo.id ? (
+        <A2add
+          editInfo={editInfo}
+          closeFu={() => setEditInfo({ id: 0, txt: "" })}
+          editTableFu={() => getListFu()}
+          addTableFu={() => resetSelectFu()}
+        />
+      ) : null}
     </div>
     </div>
-  )
+  );
 }
 }
 
 
 const MemoA2exhibition = React.memo(A2exhibition);
 const MemoA2exhibition = React.memo(A2exhibition);

+ 54 - 0
src/store/action/A2exhibition.ts

@@ -0,0 +1,54 @@
+import http from "@/utils/http";
+import { AppDispatch } from "..";
+
+/**
+ *展览管理-列表
+ */
+
+export const A2_APIgetList = (data: any): any => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post("cms/exhibition/pageList", data);
+    if (res.code === 0) {
+      const obj = {
+        // 待完善
+        list: res.data.records.map((v: any) => ({
+          ...v,
+          activityTime:
+            v.type === "long"
+              ? ""
+              : v.dateStart + " 至 " + (v.dateEnd ? v.dateEnd : "长期有效"),
+        })),
+        total: res.data.total,
+      };
+      dispatch({ type: "A2/getList", payload: obj });
+    }
+  };
+};
+
+/**
+ * 展览管理-删除
+ */
+export const A2_APIdel = (id: number) => {
+  return http.get(`cms/exhibition/removes/${id}`);
+};
+
+/**
+ * 展览管理-获取详情
+ */
+export const A2_APIgetInfo = (id: number) => {
+  return http.get(`cms/exhibition/detail/${id}`);
+};
+
+/**
+ * 展览管理-新增、编辑
+ */
+export const A2_APIsave = (data: any) => {
+  return http.post("cms/exhibition/save", data);
+};
+
+/**
+ * 展览管理-修改 展品 图片的名字
+ */
+export const A2_APIchangeImgName = (data: any) => {
+  return http.post("cms/exhibition/file/update", data);
+};

+ 28 - 0
src/store/reducer/A2exhibition.ts

@@ -0,0 +1,28 @@
+import { A2tableType } from "@/types";
+
+// 初始化状态
+const initState = {
+  // 列表数据
+  tableInfo: {
+    list: [] as A2tableType[],
+    total: 0,
+  },
+};
+
+// 定义 action 类型
+type Props = {
+  type: "A2/getList";
+  payload: { list: A2tableType[]; total: number };
+};
+
+// reducer
+export default function Reducer(state = initState, action: Props) {
+  switch (action.type) {
+    // 获取列表数据
+    case "A2/getList":
+      return { ...state, tableInfo: 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 A1event from "./A1event";
 import A1event from "./A1event";
+import A2exhibition from "./A2exhibition";
 import Z1user from "./Z1user";
 import Z1user from "./Z1user";
 import Z2log from "./Z2log";
 import Z2log from "./Z2log";
 
 
@@ -11,6 +12,7 @@ import Z2log from "./Z2log";
 const rootReducer = combineReducers({
 const rootReducer = combineReducers({
   A0Layout,
   A0Layout,
   A1event,
   A1event,
+  A2exhibition,
   Z1user,
   Z1user,
   Z2log,
   Z2log,
 });
 });

+ 27 - 0
src/types/api/A2exhibition.d.ts

@@ -0,0 +1,27 @@
+export type A2tableType = {
+  addrType: string;
+  address: string;
+  createTime: string;
+  // creatorId?: any;
+  creatorName: string;
+  // dateEnd?: any;
+  datePublish?: any;
+  // dateStart?: any;
+  digest: string;
+  display: number;
+  // exhibitionFile?: any;
+  exhibitionFileIds: string;
+  // exhibitsFile?: any;
+  exhibitsFileIds: string;
+  fileName: string;
+  filePath: string;
+  id: number;
+  name: string;
+  rtf: string;
+  sort: number;
+  thumb: string;
+  thumbPc: string;
+  type: string;
+  typeRemark: string;
+  updateTime: string;
+};

+ 1 - 0
src/types/index.d.ts

@@ -1,4 +1,5 @@
 export * from './api/layot'
 export * from './api/layot'
 export * from './api/A1event'
 export * from './api/A1event'
+export * from './api/A2exhibition'
 export * from './api/Z1user'
 export * from './api/Z1user'
 export * from './api/Z2log'
 export * from './api/Z2log'

+ 12 - 0
src/utils/tableData.ts

@@ -24,6 +24,18 @@ export const A1tableC = [
   ["txtChange", "状态", "display", { 0: "不发布", 1: "发布" }],
   ["txtChange", "状态", "display", { 0: "不发布", 1: "发布" }],
 ];
 ];
 
 
+export const A2tableC = [
+  ["txt", "标题", "name"],
+  ["img", "封面", "thumb"],
+  ["txtChange", "展览地址", "addrType", { inland: "国内", foreign: "国外" }],
+  ["txtChange", "展览时间", "type", { temp: "临时展览", long: "常设展览" }],
+  ["txt", "活动日期", "activityTime"],
+  ["txt", "最近编辑日期", "updateTime"],
+  ["txt", "编辑人", "creatorName"],
+  ["txt", "排序值", "sort"],
+  ["txtChange", "状态", "display", { 0: "不发布", 1: "发布" }],
+];
+
 export const Z1tableC = [
 export const Z1tableC = [
   ["txt", "用户名", "userName"],
   ["txt", "用户名", "userName"],
   ["txtChange", "角色", "isAdmin", { 1: "管理员", 0: "普通成员" }],
   ["txtChange", "角色", "isAdmin", { 1: "管理员", 0: "普通成员" }],