shaogen1995 1 éve
szülő
commit
c7d66afb9c

+ 3 - 0
src/assets/styles/base.css

@@ -167,6 +167,9 @@ textarea {
 #upInput2 {
   display: none;
 }
+#upInputAudio {
+  display: none;
+}
 .pageTitle {
   font-size: 18px;
   font-weight: 700;

+ 4 - 1
src/assets/styles/base.less

@@ -237,6 +237,9 @@ textarea {
 #upInput2 {
   display: none;
 }
+#upInputAudio{
+  display: none;
+}
 
 // 页面标题
 .pageTitle {
@@ -280,4 +283,4 @@ textarea {
   -webkit-box-shadow: inset 0 0 5px transparent;
   border-radius: 10px;
   background: transparent;
-}
+}

+ 82 - 0
src/components/ZRichTexts/index.module.scss

@@ -0,0 +1,82 @@
+.ZRichTexts {
+  width: 1000px;
+  height: 100%;
+
+  :global {
+    .txtBox {
+      width: 100%;
+      height: 100%;
+      border: 1px solid #ccc;
+
+      a{
+        color: #fff !important;
+      }
+
+      // 隐藏媒体功能
+      .control-item.media {
+        display: none;
+      }
+
+      .bf-container {
+        height:100%;
+      }
+
+      .bf-content {
+        height: calc(100% - 92px);
+        padding-bottom: 0px;
+      }
+
+
+
+      .bf-controlbar {
+        position: relative;
+
+        .upImgBox {
+          position: absolute;
+          bottom: 13px;
+          right: 15px;
+          cursor: pointer;
+          color: var(--themeColor);
+          // display: none;
+        }
+
+        .upImgBoxNo {
+          display: none;
+        }
+
+      }
+    }
+
+    .noUpThumb {
+      position: relative;
+      overflow: hidden;
+      opacity: 0;
+      transition: top .2s;
+      color: #ff4d4f;
+      top: -10px;
+    }
+
+    .noUpThumbAc {
+      top: 0;
+      opacity: 1;
+    }
+
+    .bf-media .bf-image {
+      float: initial !important;
+      display: block;
+      margin: 10px auto;
+      text-align: center;
+
+      // 不让拖动放大缩小图片(会报错)
+      .bf-csize-icon {
+        display: none !important;
+      }
+
+      img {
+        max-width: 500px;
+        max-height: 300px;
+      }
+    }
+
+  }
+}

+ 202 - 0
src/components/ZRichTexts/index.tsx

@@ -0,0 +1,202 @@
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
+import styles from "./index.module.scss";
+
+// 引入编辑器组件
+
+// 安装---npm install braft-editor --save --force
+// npm install braft-utils --save --force
+import { ContentUtils } from "braft-utils";
+import BraftEditor from "braft-editor";
+// 引入编辑器样式
+import "braft-editor/dist/index.css";
+
+import classNames from "classnames";
+import { MessageFu } from "@/utils/message";
+import { fileDomInitialFu } from "@/utils/domShow";
+import { baseURL } from "@/utils/http";
+
+import { forwardRef, useImperativeHandle } from "react";
+import { API_upFile } from "@/store/action/layout";
+
+type Props = {
+  check: boolean; //表单校验,为fasle表示不校验
+  dirCode: string; //文件的code码
+  isLook: boolean; //是否是查看进来
+  ref: any; //当前自己的ref,给父组件调用
+  myUrl: string; //上传的api地址
+  full?: boolean;
+};
+
+function ZRichTexts({ check, dirCode, isLook, myUrl, full }: Props, ref: any) {
+  // 添加 上传 图片的dom
+  useEffect(() => {
+    setTimeout(() => {
+      const dom = document.querySelector(".bf-controlbar")!;
+      const div = document.createElement("div");
+      div.className = "upImgBox";
+      // div.title = "上传图片";
+      div.innerHTML = "上传图片";
+      div.onclick = async () => {
+        myInput.current?.click();
+      };
+      dom.appendChild(div);
+    }, 20);
+
+    // 监听 富文本 的 class 变化,在全屏的时候会 富文本会添加上 fullscreen 的类
+    // 修复顶部样式冲突问题
+
+    const editorDom = document.querySelector(".bf-container") as HTMLDivElement;
+
+    const observer = new MutationObserver(() => {
+      // console.log("change");
+      const dom = document.querySelector(".layoutRightTop") as HTMLDivElement;
+
+      if (editorDom.className.includes("fullscreen")) dom.style.zIndex = "-1";
+      else dom.style.zIndex = "100";
+    });
+
+    observer.observe(editorDom, {
+      attributes: true,
+    });
+
+    // 销毁监听
+    return () => {
+      observer.disconnect();
+    };
+  }, []);
+
+  useEffect(() => {
+    const controlbarDom = document.querySelectorAll(".txtBox .bf-controlbar ");
+    const contentDom = document.querySelectorAll(".txtBox .bf-content ");
+    if (controlbarDom) {
+      controlbarDom.forEach((v: any) => {
+        v.style.display = isLook ? "none" : "block";
+      });
+      contentDom.forEach((v: any) => {
+        v.style.height = isLook ? "100%" : "";
+      });
+    }
+  }, [isLook]);
+
+  // 编辑器文本
+  const [editorValue, setEditorValue] = useState(
+    // 初始内容
+    BraftEditor.createEditorState("")
+  );
+
+  // 判断 富文本是否为空
+  const isTxtFlag = useMemo(() => {
+    const txt: string = editorValue.toHTML();
+    if (
+      txt.replaceAll("<p>", "").replaceAll("</p>", "").replaceAll(" ", "") ===
+      ""
+    ) {
+      return true;
+    } else return false;
+  }, [editorValue]);
+
+  const myInput = useRef<HTMLInputElement>(null);
+
+  // 上传图片
+  const handeUpPhoto = useCallback(
+    async (e: React.ChangeEvent<HTMLInputElement>) => {
+      if (e.target.files) {
+        // 拿到files信息
+        const filesInfo = e.target.files[0];
+        // 校验格式
+        const type = ["image/jpeg", "image/png"];
+        if (!type.includes(filesInfo.type)) {
+          e.target.value = "";
+          return MessageFu.warning("只支持png、jpg和jpeg格式!");
+        }
+        // 校验大小
+        if (filesInfo.size > 5 * 1024 * 1024) {
+          e.target.value = "";
+          return MessageFu.warning("最大支持5M!");
+        }
+        // 创建FormData对象
+        const fd = new FormData();
+        // 把files添加进FormData对象(‘photo’为后端需要的字段)
+        fd.append("type", "img");
+        fd.append("dirCode", dirCode);
+        fd.append("file", filesInfo);
+
+        e.target.value = "";
+
+        try {
+          const res = await API_upFile(fd, myUrl);
+          if (res.code === 0) {
+            MessageFu.success("上传成功!");
+            // 在光标位置插入图片
+            const newTxt = ContentUtils.insertMedias(editorValue, [
+              {
+                type: "IMAGE",
+                url: baseURL + res.data.filePath,
+              },
+            ]);
+
+            setEditorValue(newTxt);
+          }
+          fileDomInitialFu();
+        } catch (error) {
+          fileDomInitialFu();
+        }
+      }
+    },
+    [dirCode, editorValue, myUrl]
+  );
+
+  // 让父组件调用的 回显 富文本
+  const ritxtShowFu = useCallback((val: string) => {
+    setEditorValue(BraftEditor.createEditorState(val));
+  }, []);
+
+  // 让父组件调用的返回 富文本信息 和 表单校验 isTxtFlag为ture表示未通过校验
+  const fatherBtnOkFu = useCallback(() => {
+    return { val: editorValue.toHTML(), flag: isTxtFlag };
+  }, [editorValue, isTxtFlag]);
+
+  // 可以让父组件调用子组件的方法
+  useImperativeHandle(ref, () => ({
+    ritxtShowFu,
+    fatherBtnOkFu,
+  }));
+
+  return (
+    <div className={styles.ZRichTexts} style={{ width: full ? "100%" : "" }}>
+      <input
+        id="upInput"
+        type="file"
+        accept=".png,.jpg,.jpeg"
+        ref={myInput}
+        onChange={(e) => handeUpPhoto(e)}
+      />
+
+      <div className="txtBox">
+        <BraftEditor
+          readOnly={isLook}
+          placeholder="请输入内容"
+          value={editorValue}
+          onChange={(e) => setEditorValue(e)}
+          imageControls={["remove"]}
+        />
+      </div>
+      <div
+        className={classNames(
+          "noUpThumb",
+          check && isTxtFlag ? "noUpThumbAc" : ""
+        )}
+      >
+        请输入正文!
+      </div>
+    </div>
+  );
+}
+
+export default forwardRef(ZRichTexts);

+ 62 - 0
src/components/ZupAudio/index.module.scss

@@ -0,0 +1,62 @@
+// 上传无障碍音频的样式
+.ZupAudio {
+  margin-left: 20px;
+  width: 180px;
+  height: 32px;
+  // position: relative;
+  // top: -4px;
+  border: 1px solid #ccc;
+  border-radius: 16px;
+
+  :global {
+
+    .ZupAudio1 {
+      cursor: pointer;
+
+      display: flex;
+      justify-content: center;
+
+      .anticon-upload {
+        font-size: 20px;
+      }
+
+      .ZupAudio1_1 {
+        line-height: 15px;
+        color: #aaa5cb;
+        margin-left: 10px;
+
+        &>p {
+          &:nth-of-type(2) {
+            font-size: 10px;
+            // color: red;
+            opacity: .7;
+          }
+        }
+      }
+    }
+
+    .ZupAudio2 {
+      padding: 0 10px;
+      height: 100%;
+      display: flex;
+      align-items: center;
+
+      .anticon {
+        font-size: 18px;
+        cursor: pointer;
+
+      }
+
+      &>div {
+        height: 100%;
+        line-height: 30px;
+        width: calc(100% - 35px);
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+    }
+
+
+  }
+}

+ 133 - 0
src/components/ZupAudio/index.tsx

@@ -0,0 +1,133 @@
+import React, { useCallback, useRef } from "react";
+import styles from "./index.module.scss";
+import { MessageFu } from "@/utils/message";
+import { API_upFile } from "@/store/action/layout";
+import { fileDomInitialFu } from "@/utils/domShow";
+import { UploadOutlined, DeleteOutlined, EyeOutlined } from "@ant-design/icons";
+import store from "@/store";
+import MyPopconfirm from "../MyPopconfirm";
+
+export type ZupAudioType = {
+  fileName: string;
+  filePath: string;
+};
+
+type Props = {
+  fileInfo: ZupAudioType;
+  upDataFu: (info: ZupAudioType,index:number) => void;
+  delFu: (index: number) => void;
+  dirCode: string;
+  myUrl: string;
+  index?: number;
+  size?: number;
+  isLook?: boolean;
+};
+
+function ZupAudio({
+  index = 0,
+  size = 10,
+  isLook = false,
+  fileInfo,
+  upDataFu,
+  delFu,
+  dirCode,
+  myUrl,
+}: Props) {
+  // 上传 无障碍音频的 点击
+  const handeUpAudio = useCallback(
+    async (e: React.ChangeEvent<HTMLInputElement>) => {
+      if (e.target.files) {
+        // 拿到files信息
+        const filesInfo = e.target.files[0];
+        // console.log("-----", filesInfo.type);
+
+        // 校验格式
+        const type = ["audio/mpeg"];
+        if (!type.includes(filesInfo.type)) {
+          e.target.value = "";
+          return MessageFu.warning(`只支持.mp3格式!`);
+        }
+
+        // 校验大小
+        if (filesInfo.size > size * 1024 * 1024) {
+          e.target.value = "";
+          return MessageFu.warning(`最大支持${size}M!`);
+        }
+        // 创建FormData对象
+        const fd = new FormData();
+
+        fd.append("type", "audio");
+        fd.append("dirCode", dirCode);
+        fd.append("file", filesInfo);
+        e.target.value = "";
+
+        try {
+          const res = await API_upFile(fd, myUrl);
+          if (res.code === 0) {
+            MessageFu.success("上传成功!");
+            // console.log(res);
+            upDataFu(res.data,index);
+          }
+          fileDomInitialFu();
+        } catch (error) {
+          fileDomInitialFu();
+        }
+      }
+    },
+    [dirCode, index, myUrl, size, upDataFu]
+  );
+
+  // 上传附近的ref
+  const myInput = useRef<HTMLInputElement>(null);
+
+  return (
+    <div className={styles.ZupAudio} id="upInputAudioBox">
+      {/* 上传无障碍音频 */}
+      <input
+        id="upInputAudio"
+        type="file"
+        accept=".mp3"
+        onChange={(e) => handeUpAudio(e)}
+        ref={myInput}
+      />
+      {fileInfo.filePath ? (
+        <div className="ZupAudio2">
+          <div title={fileInfo.fileName}>{fileInfo.fileName}</div>
+          <EyeOutlined
+            title="预览"
+            onClick={() =>
+              store.dispatch({
+                type: "layout/lookDom",
+                payload: { src: fileInfo.filePath, type: "audio" },
+              })
+            }
+          />
+          &nbsp;
+          <MyPopconfirm
+            txtK="删除"
+            onConfirm={() => delFu(index)}
+            Dom={
+              <DeleteOutlined
+                title="删除"
+                className="ZTbox2X"
+                rev={undefined}
+              />
+            }
+          />
+        </div>
+      ) : (
+        <div className="ZupAudio1" onClick={() => myInput.current?.click()}>
+          <UploadOutlined />
+          <div className="ZupAudio1_1">
+            <p>上传无障碍音频</p>
+            <p>支持{size}MB以下mp3格式</p>
+          </div>
+        </div>
+      )}
+    </div>
+  );
+}
+
+const MemoZupAudio = React.memo(ZupAudio);
+
+export default MemoZupAudio;

+ 0 - 92
src/components/ZupVideos/index.module.scss

@@ -1,92 +0,0 @@
-.ZupVideos {
-  width: 100%;
-
-  :global {
-
-    .zVmain {
-      width: 100%;
-      display: flex;
-      flex-wrap: wrap;
-
-      .file_upIcon {
-        color: #a6a6a6;
-        border-radius: 3px;
-        cursor: pointer;
-        font-size: 30px;
-        width: 100px;
-        height: 100px;
-        border: 1px dashed #797979;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        margin-right: 100px;
-      }
-
-      .zVRow {
-        margin-right: 30px;
-        margin-bottom: 20px;
-
-        .zVRow1 {
-          display: flex;
-
-          .zVRow1V {
-            width: 150px;
-            height: 100px;
-            border: 1px dashed #797979;
-            border-radius: 3px;
-
-            video {
-              width: 100%;
-              height: 100%;
-            }
-          }
-
-          .zVRow1I {
-            margin-left: 4px;
-            display: flex;
-            flex-direction: column;
-            justify-content: space-around;
-            align-items: center;
-          }
-        }
-
-        .zVRow2 {
-          margin-top: 3px;
-          font-size: 14px;
-          text-align: center;
-          width: 170px;
-          overflow: hidden;
-          text-overflow: ellipsis;
-          white-space: nowrap;
-        }
-
-      }
-
-    }
-
-
-
-    .fileBoxRow_r_tit {
-      height: 46px;
-      margin-top: 5px;
-      font-size: 14px;
-      color: rgb(126, 124, 124);
-
-
-    }
-
-    .noUpThumb {
-      position: relative;
-      overflow: hidden;
-      opacity: 0;
-      transition: top .2s;
-      color: #ff4d4f;
-      top: -10px;
-    }
-
-    .noUpThumbAc {
-      top: 0;
-      opacity: 1;
-    }
-  }
-}

+ 0 - 205
src/components/ZupVideos/index.tsx

@@ -1,205 +0,0 @@
-import React, { useCallback, useRef, useState } from "react";
-import styles from "./index.module.scss";
-import { forwardRef, useImperativeHandle } from "react";
-import { FileListType } from "../ZupTypes";
-import { MessageFu } from "@/utils/message";
-import { API_upFile } from "@/store/action/layout";
-import { fileDomInitialFu } from "@/utils/domShow";
-import {
-  PlusOutlined,
-  EyeOutlined,
-  CloseOutlined,
-  DownloadOutlined,
-} from "@ant-design/icons";
-import classNames from "classnames";
-import { baseURL } from "@/utils/http";
-import store from "@/store";
-import MyPopconfirm from "../MyPopconfirm";
-
-type Props = {
-  size: number; //视频大小
-  fileNum: number; //数量限制
-  dirCode: string; //文件的code码
-  myUrl: string; //请求地址
-  fileCheck?: boolean; //是否检验
-  format?: string[]; //上传格式 默认["video/mp4"]
-  formatTxt?: string; //上传提示
-  checkTxt?: string;
-  upTxt?: string;
-  isLook?: boolean; //是不是查看
-  fromData?: any;
-  ref: any; //当前自己的ref,给父组件调用
-};
-
-function ZupVideos(
-  {
-    size,
-    fileNum,
-    dirCode,
-    myUrl,
-    fileCheck = false,
-    format = ["video/mp4"],
-    formatTxt = ".mp4",
-    checkTxt = "请上传视频!",
-    upTxt = "",
-    isLook = false,
-    fromData,
-  }: Props,
-  ref: any
-) {
-  const [fileList, setFileList] = useState<FileListType[]>([]);
-
-  // 上传
-  const handeUpPhoto = useCallback(
-    async (e: React.ChangeEvent<HTMLInputElement>) => {
-      if (e.target.files) {
-        // 拿到files信息
-        const filesInfo = e.target.files[0];
-        // console.log("-----", filesInfo.type);
-
-        // 校验格式
-        if (!format.includes(filesInfo.type)) {
-          e.target.value = "";
-          return MessageFu.warning(`只支持${formatTxt}格式!`);
-        }
-
-        // 校验大小
-        if (filesInfo.size > size * 1024 * 1024) {
-          e.target.value = "";
-          return MessageFu.warning(`最大支持${size}M!`);
-        }
-        // 创建FormData对象
-        const fd = new FormData();
-
-        fd.append("type", "video");
-        fd.append("isDb", "true");
-        fd.append("dirCode", dirCode);
-        fd.append("file", filesInfo);
-
-        if (fromData) {
-          for (const k in fromData) {
-            if (fromData[k]) fd.append(k, fromData[k]);
-          }
-        }
-
-        e.target.value = "";
-
-        try {
-          const res = await API_upFile(fd, myUrl);
-          if (res.code === 0) {
-            MessageFu.success("上传成功!");
-            setFileList([...fileList, res.data]);
-            // console.log(res);
-          }
-          fileDomInitialFu();
-        } catch (error) {
-          fileDomInitialFu();
-        }
-      }
-    },
-    [dirCode, fileList, format, formatTxt, fromData, myUrl, size]
-  );
-
-  // 让父组件调用的 回显 附件 地址
-  const setFileComFileFu = useCallback((valList: FileListType[]) => {
-    setFileList(valList);
-  }, []);
-
-  // 让父组件调用的返回 附件 名字和路径
-  const fileComFileResFu = useCallback(() => {
-    return fileList;
-  }, [fileList]);
-
-  // 可以让父组件调用子组件的方法
-  useImperativeHandle(ref, () => ({
-    setFileComFileFu,
-    fileComFileResFu,
-  }));
-
-  const myInput = useRef<HTMLInputElement>(null);
-
-  // 点击预览
-  const lookFileFu = useCallback((file: string) => {
-    store.dispatch({
-      type: "layout/lookDom",
-      payload: { src: file, type: "video" },
-    });
-  }, []);
-
-  return (
-    <div className={styles.ZupVideos}>
-      <input
-        id="upInput"
-        type="file"
-        accept={formatTxt}
-        ref={myInput}
-        onChange={(e) => handeUpPhoto(e)}
-      />
-
-      <div hidden={!(isLook && fileList.length <= 0)}>(空)</div>
-
-      <div className="zVmain">
-        <div
-          hidden={fileList.length >= fileNum || isLook}
-          className="file_upIcon"
-          onClick={() => myInput.current?.click()}
-        >
-          <PlusOutlined />
-        </div>
-
-        {fileList.map((v) => (
-          <div className="zVRow" key={v.id}>
-            <div className="zVRow1">
-              <div className="zVRow1V" title={v.fileName}>
-                <video src={baseURL + v.filePath}></video>
-              </div>
-              <div className="zVRow1I">
-                {/* 视频预览 */}
-                <EyeOutlined onClick={() => lookFileFu(v.filePath)} />
-                {/* 视频下载 */}
-                <a
-                  href={baseURL + v.filePath}
-                  download
-                  target="_blank"
-                  rel="noreferrer"
-                >
-                  <DownloadOutlined />
-                </a>
-                {/* 视频删除 */}
-
-                {isLook ? null : (
-                  <MyPopconfirm
-                    txtK="删除"
-                    onConfirm={() =>
-                      setFileList(fileList.filter((c) => c.id !== v.id))
-                    }
-                    Dom={<CloseOutlined />}
-                  />
-                )}
-              </div>
-            </div>
-            <div className="zVRow2" title={v.fileName}>
-              {v.fileName}
-            </div>
-          </div>
-        ))}
-      </div>
-
-      <div className="fileBoxRow_r_tit" hidden={isLook}>
-        格式要求:仅支持{formatTxt.replaceAll(".", "")}格式,最大支持{size}M
-        {upTxt}
-        <br />
-        <div
-          className={classNames(
-            "noUpThumb",
-            fileList.length <= 0 && fileCheck ? "noUpThumbAc" : ""
-          )}
-        >
-          {checkTxt}
-        </div>
-      </div>
-    </div>
-  );
-}
-
-export default forwardRef(ZupVideos);

+ 69 - 0
src/pages/A1event/A1add/index.module.scss

@@ -0,0 +1,69 @@
+.A1add {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 12;
+  background-color: #fff;
+  border-radius: 10px;
+  padding: 24px;
+
+  :global {
+    .A1eMain {
+      width: 100%;
+      height: 100%;
+      overflow-y: auto;
+
+      .A1Frow {
+        position: absolute;
+        top: 24px;
+        left: 624px;
+        width: 200px;
+      }
+
+      .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);
+          }
+        }
+        // 正文
+        .formRightZW{
+          top: -3px;
+          position: relative;
+          width: 100%;
+          display: flex;
+          align-items: center;
+          justify-content: space-between;
+        }
+
+        .A1Ebtn {
+          position: absolute;
+          z-index: 10;
+          left: 1200px;
+          top: 50%;
+          transform: translateY(-50%);
+        }
+      }
+    }
+  }
+}

+ 308 - 0
src/pages/A1event/A1add/index.tsx

@@ -0,0 +1,308 @@
+import React, { useCallback, useEffect, useRef, useState } from "react";
+import styles from "./index.module.scss";
+import { A1EditInfoType } from "../data";
+import { Button, Checkbox, DatePicker, Form, FormInstance, Input } from "antd";
+import { A1_APIgetInfo, A1_APIsave } from "@/store/action/A1event";
+import dayjs from "dayjs";
+import { MessageFu } from "@/utils/message";
+import MyPopconfirm from "@/components/MyPopconfirm";
+import ZupAudio, { ZupAudioType } from "@/components/ZupAudio";
+import ZupOne from "@/components/ZupOne";
+
+type Props = {
+  editInfo: A1EditInfoType;
+  closeFu: () => void;
+  editTableFu: () => void;
+  addTableFu: () => void;
+};
+
+function A1add({ editInfo, closeFu, editTableFu, addTableFu }: Props) {
+  const [dirCode, setDirCode] = useState("");
+
+  // 表单的ref
+  const FormBoxRef = useRef<FormInstance>(null);
+
+  // 封面图的ref
+  const ZupThumbRef = useRef<any>(null);
+
+  // 富文本的ref
+  const ZRichTextRef = useRef<any>(null);
+
+  // 标题的音频
+  const [nameAudio, setNameAudio] = useState({
+    fileName: "",
+    filePath: "",
+  });
+
+  const getInfoFu = useCallback(async (id: number) => {
+    const res = await A1_APIgetInfo(id);
+    if (res.code === 0) {
+      const data = res.data;
+
+      setDirCode(data.dirCode);
+
+      // 设置富文本
+      ZRichTextRef.current?.ritxtShowFu(data.rtf);
+
+      FormBoxRef.current?.setFieldsValue({
+        ...data,
+        myTime: dayjs(data.datePublish),
+      });
+
+      // 设置封面图
+      ZupThumbRef.current?.setFileComFileFu({
+        fileName: "",
+        filePath: data.thumb,
+      });
+    }
+  }, []);
+
+  useEffect(() => {
+    if (editInfo.id > 0) {
+      getInfoFu(editInfo.id);
+    } else {
+      setDirCode(Date.now() + "");
+      FormBoxRef.current?.setFieldsValue({
+        myTime: dayjs(Date.now()),
+      });
+    }
+  }, [editInfo.id, getInfoFu]);
+
+  // 附件 是否 已经点击过确定
+  const [fileCheck, setFileCheck] = useState(false);
+
+  // 是否按章节发布
+  const [isSection, setIsSection] = useState(false);
+
+  type SectionArrType = {
+    id: number;
+    name: string;
+    txt: string;
+    fileInfo: ZupAudioType;
+  };
+
+  const [sectionArr, setSectionArr] = useState<SectionArrType[]>([
+    {
+      id: Date.now(),
+      name: "",
+      txt: "",
+      fileInfo: { fileName: "", filePath: "" },
+    },
+  ]);
+
+  // 点击新增章节
+  const addSectionFu = useCallback(() => {
+    if (sectionArr.length >= 20) return MessageFu.warning("最多存在20个章节");
+    setSectionArr([
+      {
+        id: Date.now(),
+        name: "",
+        txt: "",
+        fileInfo: { fileName: "", filePath: "" },
+      },
+      ...sectionArr,
+    ]);
+  }, [sectionArr]);
+
+  // 章节音频上传成功
+  const upSectionFu = useCallback(
+    (info: ZupAudioType, index: number) => {
+      const arr = [...sectionArr];
+      arr[index].fileInfo = info;
+      setSectionArr(arr);
+    },
+    [sectionArr]
+  );
+
+  // 章节音频删除
+  const delSectionFu = useCallback(
+    (index: number) => {
+      const arr = [...sectionArr];
+      arr[index].fileInfo = {} as ZupAudioType;
+      setSectionArr(arr);
+    },
+    [sectionArr]
+  );
+
+  // 整个章节的删除
+  const delSectionAllFu = useCallback(
+    (id: number) => {
+      setSectionArr(sectionArr.filter((v) => v.id !== id));
+    },
+    [sectionArr]
+  );
+
+  // 整个章节的位移
+  const moveSectionFu = useCallback(
+    (index: number, num: number) => {
+      const arr = [...sectionArr];
+      const temp = arr[index];
+      arr[index] = arr[index + 1];
+      arr[index + 1] = temp;
+      setSectionArr(arr);
+    },
+    [sectionArr]
+  );
+
+  // 没有通过校验
+  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");
+
+      const rtf = ZRichTextRef.current?.fatherBtnOkFu();
+
+      const obj = {
+        ...values,
+        id: editInfo.id > 0 ? editInfo.id : null,
+        datePublish,
+        thumb: coverUrl1.filePath,
+        rtf: rtf.val || "",
+      };
+
+      if (obj) {
+        console.log(123, obj);
+        return;
+      }
+
+      const res = await A1_APIsave(obj);
+
+      if (res.code === 0) {
+        MessageFu.success(`${editInfo.txt}成功!`);
+        editInfo.id > 0 ? editTableFu() : addTableFu();
+        closeFu();
+      }
+    },
+    [addTableFu, closeFu, editInfo.id, editInfo.txt, editTableFu]
+  );
+
+  return (
+    <div className={styles.A1add}>
+      <div className="A1eMain">
+        <Form
+          ref={FormBoxRef}
+          name="basic"
+          labelCol={{ span: 3 }}
+          onFinish={onFinish}
+          onFinishFailed={onFinishFailed}
+          autoComplete="off"
+          scrollToFirstError
+        >
+          <Form.Item
+            label="标题"
+            name="name"
+            rules={[{ required: true, message: "请输入标题!" }]}
+            getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
+          >
+            <Input
+              style={{ width: "500px" }}
+              maxLength={50}
+              showCount
+              placeholder="请输入内容"
+            />
+          </Form.Item>
+
+          {/* 标题的无障碍音频 */}
+          <div className="A1Frow">
+            <ZupAudio
+              fileInfo={nameAudio}
+              upDataFu={(info) => setNameAudio(info)}
+              delFu={() => setNameAudio({} as ZupAudioType)}
+              dirCode={dirCode}
+              myUrl="cms/event/upload"
+              isLook={editInfo.txt === "查看"}
+            />
+          </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/event/upload"
+                format={["image/jpeg", "image/png"]}
+                formatTxt="png、jpg和jpeg"
+                checkTxt="请上传封面图!"
+                upTxt="最多1张"
+                myType="thumb"
+              />
+            </div>
+          </div>
+
+          {/* 正文 */}
+          <div className="formRow">
+            <div className="formLeft">
+              <span>* </span>
+              正文:
+            </div>
+            <div className="formRight">
+              <div className="formRightZW">
+                <Checkbox
+                  checked={isSection}
+                  onChange={(e) => setIsSection(e.target.checked)}
+                >
+                  按章节发布
+                </Checkbox>
+
+                {isSection ? (
+                  <Button type="primary" onClick={addSectionFu}>
+                    新增章节
+                  </Button>
+                ) : (
+                  <ZupAudio
+                    fileInfo={sectionArr[0].fileInfo}
+                    upDataFu={(info) => upSectionFu(info, 0)}
+                    delFu={() => delSectionFu(0)}
+                    dirCode={dirCode}
+                    myUrl="cms/event/upload"
+                    isLook={editInfo.txt === "查看"}
+                  />
+                )}
+              </div>
+            </div>
+          </div>
+
+          <Form.Item
+            label="发布日期"
+            name="myTime"
+            rules={[{ required: true, message: "请选择发布日期!" }]}
+          >
+            <DatePicker />
+          </Form.Item>
+
+          {/* 确定和取消按钮 */}
+          <Form.Item className="A1Ebtn">
+            <Button type="primary" htmlType="submit">
+              提交
+            </Button>
+            <br />
+            <br />
+            <MyPopconfirm txtK="取消" onConfirm={closeFu} />
+          </Form.Item>
+        </Form>
+      </div>
+    </div>
+  );
+}
+
+const MemoA1add = React.memo(A1add);
+
+export default MemoA1add;

+ 17 - 0
src/pages/A1event/data.ts

@@ -0,0 +1,17 @@
+export type A1FromDataType= {
+  pageNum: number;
+  pageSize: number;
+  searchKey: string;
+  display: ''|0|1;
+}
+
+export const A1Selct=[
+  { value: '', label: '全部' },
+  { value: 0, label: '不发布' },
+  { value: 1, label: '发布' },
+]
+
+export type A1EditInfoType ={
+  id:number
+  txt:'新增'|'编辑'|'查看'|''
+}

+ 26 - 3
src/pages/A1event/index.module.scss

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

+ 178 - 5
src/pages/A1event/index.tsx

@@ -1,12 +1,185 @@
-import React from "react";
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
 import styles from "./index.module.scss";
- function A1event() {
-  
+import { useDispatch, useSelector } from "react-redux";
+import { A1_APIdel, A1_APIgetList } from "@/store/action/A1event";
+import { A1EditInfoType, A1FromDataType, A1Selct } from "./data";
+import { RootState } from "@/store";
+import { MessageFu } from "@/utils/message";
+import { A1tableType } from "@/types";
+import { Button, Input, Select } from "antd";
+import MyPopconfirm from "@/components/MyPopconfirm";
+import MyTable from "@/components/MyTable";
+import { A1tableC } from "@/utils/tableData";
+import A1add from "./A1add";
+function A1event() {
+  const dispatch = useDispatch();
+
+  const [fromData, setFromData] = useState<A1FromDataType>({
+    pageNum: 1,
+    pageSize: 10,
+    searchKey: "",
+    display: "",
+  });
+
+  const getListFu = useCallback(() => {
+    dispatch(A1_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: "",
+      display: "",
+    });
+  }, []);
+
+  const tableInfo = useSelector((state: RootState) => state.A1event.tableInfo);
+
+  const delTableFu = useCallback(
+    async (id: number) => {
+      const res = await A1_APIdel(id);
+      if (res.code === 0) {
+        MessageFu.success("删除成功!");
+        getListFu();
+      }
+    },
+    [getListFu]
+  );
+
+  const tableLastBtn = useMemo(() => {
+    return [
+      {
+        title: "操作",
+        render: (item: A1tableType) => (
+          <>
+            <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 (
     <div className={styles.A1event}>
-       <div className="pageTitle">事件管理</div>
+      <div className="pageTitle">
+        事件管理{editInfo.id ? ` - ${editInfo.txt}` : ""}
+      </div>
+
+      {/* 顶部筛选 */}
+      <div className="A1top">
+        <div className="A1topLeft">
+          <div>
+            <span>标题:</span>
+            <Input
+              key={inputKey}
+              maxLength={10}
+              showCount
+              style={{ width: 300 }}
+              placeholder="请输入关键字,不超过50字"
+              allowClear
+              onChange={(e) => fromKeyChangeFu(e, "searchKey")}
+            />
+          </div>
+          <div>
+            <span>状态:</span>
+            <Select
+              placeholder="请选择"
+              style={{ width: 200 }}
+              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="A1tableBox">
+        <MyTable
+          yHeight={625}
+          list={tableInfo.list}
+          columnsTemp={A1tableC}
+          lastBtn={tableLastBtn}
+          pageNum={fromData.pageNum}
+          pageSize={fromData.pageSize}
+          total={tableInfo.total}
+          onChange={(pageNum, pageSize) =>
+            setFromData({ ...fromData, pageNum, pageSize })
+          }
+        />
+      </div>
+
+      {/* 新增 编辑 查看 */}
+      {editInfo.id ? (
+        <A1add
+          editInfo={editInfo}
+          closeFu={() => setEditInfo({ id: 0, txt: "" })}
+          editTableFu={() => getListFu()}
+          addTableFu={() => resetSelectFu()}
+        />
+      ) : null}
     </div>
-  )
+  );
 }
 
 const MemoA1event = React.memo(A1event);

+ 40 - 0
src/store/action/A1event.ts

@@ -0,0 +1,40 @@
+import http from "@/utils/http";
+import { AppDispatch } from "..";
+
+/**
+ *事件管理-列表
+ */
+
+export const A1_APIgetList = (data: any): any => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post("cms/event/pageList", data);
+    if (res.code === 0) {
+      const obj = {
+        list: res.data.records,
+        total: res.data.total,
+      };
+      dispatch({ type: "A1/getList", payload: obj });
+    }
+  };
+};
+
+/**
+ * 事件管理-删除
+ */
+export const A1_APIdel = (id: number) => {
+  return http.get(`cms/event/removes/${id}`);
+};
+
+/**
+ * 事件管理-获取详情
+ */
+export const A1_APIgetInfo = (id: number) => {
+  return http.get(`cms/event/detail/${id}`);
+};
+
+/**
+ * 事件管理-新增、编辑
+ */
+export const A1_APIsave = (data: any) => {
+  return http.post("cms/event/save", data);
+};

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

@@ -0,0 +1,28 @@
+import { A1tableType } from "@/types";
+
+// 初始化状态
+const initState = {
+  // 列表数据
+  tableInfo: {
+    list: [] as A1tableType[],
+    total: 0,
+  },
+};
+
+// 定义 action 类型
+type Props = {
+  type: "A1/getList";
+  payload: { list: A1tableType[]; total: number };
+};
+
+// reducer
+export default function Reducer(state = initState, action: Props) {
+  switch (action.type) {
+    // 获取列表数据
+    case "A1/getList":
+      return { ...state, tableInfo: action.payload };
+
+    default:
+      return state;
+  }
+}

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

@@ -3,12 +3,14 @@ import { combineReducers } from "redux";
 
 // 导入 登录 模块的 reducer
 import A0Layout from "./layout";
+import A1event from "./A1event";
 import Z1user from "./Z1user";
 import Z2log from "./Z2log";
 
 // 合并 reducer
 const rootReducer = combineReducers({
   A0Layout,
+  A1event,
   Z1user,
   Z2log,
 });

+ 17 - 0
src/types/api/A1event.d.ts

@@ -0,0 +1,17 @@
+export type A1tableType={
+	createTime: string;
+	// creatorId?: any;
+	creatorName: string;
+	// dateEnd?: any;
+	// datePublish?: any;
+	// dateStart?: any;
+	display: number;
+	fileName: string;
+	filePath: string;
+	id: number;
+	name: string;
+	rft: string;
+	sort: number;
+	thumb: string;
+	updateTime: string;
+}

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

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

+ 7 - 87
src/utils/tableData.ts

@@ -14,96 +14,16 @@
 //     ["text", "创建日期",'description', 50,A],
 //   ];
 // };
-
-export const A2tableC = [
-  ["txt", "标题", "name"],
-  ["img", "封面", "thumb"],
-  ["txt", "发布日期", "publishDate"],
-  ["txt", "所属栏目", "dictName"],
-  ["text", "摘要", "description", 50],
-];
-
-export const A3tableC = [
-  ["txt", "标题", "name"],
-  ["img", "封面", "thumb"],
-  ["txt", "发布日期", "publishDate"],
-  ["text", "链接", "link", 50, "A"],
-];
-
-export const A4tableC = [
-  ["txt", "标题", "name"],
-  ["img", "封面", "thumb"],
-  ["txt", "发布日期", "publishDate"],
-  ["txt", "所属栏目", "dictName"],
-  ["txt", "质地", "texture"],
-  ["txt", "年代", "age"],
-  ["text", "简介", "description", 50],
-];
-
-export const A5tableC = [
-  ["txt", "标题", "name"],
-  ["img", "封面", "thumb"],
-  ["txt", "发布日期", "publishDate"],
-  ["txt", "展览类型", "type"],
-  ["text", "摘要", "description", 50],
-];
-
-export const A6tableC = [
+export const A1tableC = [
   ["txt", "标题", "name"],
-  ["img", "封面", "thumb"],
-  ["txt", "发布日期", "publishDate"],
-  ["txt", "所属栏目", "dictName"],
-  ["txtChange", "需要预约", "isNeed", { 1: "是", 0: "否" }],
+  ["img", '封面', "thumb"],
+  ["txt", "活动日期", "realName"], //待完善
+  ["txt", "最近编辑日期", "updateTime"],
+  ["txt", "编辑人", "creatorName"],
+  ["txt", "排序值", "sort"],
+  ["txtChange", "状态", "display", { 0: "不发布", 1: "发布" }],
 ];
 
-export const A7tableC = [
-  ["txt", "标题", "name"],
-  ["img", "封面", "thumb"],
-  ["txt", "发布日期", "publishDate"],
-];
-
-export const B1tableC = [
-  ["txt", "申请时间", "createTime"],
-  ["txtChange", "验证状态", "status", { 0: "未验证", 1: "已验证" }],
-  ["txt", "姓名", "name"],
-  ["txt", "联系电话", "phone"],
-  ["txt", "人数", "pcs"],
-  ["txt", "预约日期", "bookDate"],
-  ["txt", "预约时段", "time"],
-];
-
-export const B2tableC = [
-  ["txt", "申请时间", "createTime"],
-  ["txt", "姓名", "name"],
-  ["txt", "活动名称", "title"],
-  ["txt", "联系电话", "phone"],
-  ["txt", "身份证", "identity"],
-  ["text", "预约说明", "description", 50],
-];
-
-export const B3tableC = [
-  ["txt", "申请时间", "createTime"],
-  ["txt", "姓名", "name"],
-  ["txt", "联系电话", "phone"],
-  ["txt", "身份证", "identity"],
-  ["text", "预约说明", "description", 50],
-];
-
-export const C1tableC = [
-  ["txt", "时段", "time"],
-  ["txt", "周一", "monday"],
-  ["txt", "周二", "tuesday"],
-  ["txt", "周三", "wednesday"],
-  ["txt", "周四", "thursday"],
-  ["txt", "周五", "friday"],
-  ["txt", "周六", "saturday"],
-  ["txt", "周日", "sunday"],
-];
-
-export const Z0tableC = [
-  ["txt", "栏目名称", "name"],
-  ["text", "说明", "rtf", 50],
-];
 
 export const Z1tableC = [
   ["txt", "用户名", "userName"],