shaogen1995 пре 1 година
родитељ
комит
d3e2932e19
2 измењених фајлова са 190 додато и 208 уклоњено
  1. 185 208
      src/components/ZRichTexts/index.tsx
  2. 5 0
      src/pages/A1event/A1add/index.tsx

+ 185 - 208
src/components/ZRichTexts/index.tsx

@@ -1,323 +1,308 @@
-import React, { useCallback, useMemo, useRef, useState } from "react";
-import styles from "./index.module.scss";
+import React, { useCallback, 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 { 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";
-import ZupAudio, { ZupAudioType } from "../ZupAudio";
-import { Button, Checkbox, Input } from "antd";
-import {
-  ArrowDownOutlined,
-  DeleteOutlined,
-  ArrowUpOutlined,
-} from "@ant-design/icons";
-import MyPopconfirm from "../MyPopconfirm";
+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'
+import ZupAudio, { ZupAudioType } from '../ZupAudio'
+import { Button, Checkbox, Input } from 'antd'
+import { ArrowDownOutlined, DeleteOutlined, ArrowUpOutlined } from '@ant-design/icons'
+import MyPopconfirm from '../MyPopconfirm'
 
 export type SectionArrType = {
-  id: number;
-  name: string;
-  txt: any;
-  fileInfo: ZupAudioType;
-};
+  id: number
+  name: string
+  txt: any
+  fileInfo: ZupAudioType
+}
 
 type Props = {
-  check: boolean; //表单校验,为fasle表示不校验
-  dirCode: string; //文件的code码
-  isLook: boolean; //是否是查看进来
-  ref: any; //当前自己的ref,给父组件调用
-  myUrl: string; //上传的api地址
-  isOne?: boolean; //只显示单个富文本
-  upAudioBtnNone?: boolean; //是否能上传无障碍音频
-};
+  check: boolean //表单校验,为fasle表示不校验
+  dirCode: string //文件的code码
+  isLook: boolean //是否是查看进来
+  ref: any //当前自己的ref,给父组件调用
+  myUrl: string //上传的api地址
+  isOne?: boolean //只显示单个富文本
+  upAudioBtnNone?: boolean //是否能上传无障碍音频
+}
 
 function ZRichTexts(
-  {
-    check,
-    dirCode,
-    isLook,
-    myUrl,
-    isOne = false,
-    upAudioBtnNone = false,
-  }: Props,
+  { check, dirCode, isLook, myUrl, isOne = false, upAudioBtnNone = false }: Props,
   ref: any
 ) {
   const [sectionArr, setSectionArr] = useState<SectionArrType[]>([
     {
       id: Date.now(),
-      name: "",
-      txt: BraftEditor.createEditorState(""),
-      fileInfo: { fileName: "", filePath: "" },
-    },
-  ]);
+      name: '',
+      txt: BraftEditor.createEditorState(''),
+      fileInfo: { fileName: '', filePath: '' }
+    }
+  ])
 
   // 是否按章节发布
-  const [isSection, setIsSection] = useState(false);
+  const [isSection, setIsSection] = useState(false)
 
   // 当前上传 图片 视频的索引
-  const nowIndexRef = useRef(0);
+  const nowIndexRef = useRef(0)
 
   // 判断 富文本是否为空
   const isTxtFlag = useMemo(() => {
-    let flag = false;
+    let flag = false
 
     // 不是按章节发布,检查第一个富文本
     if (!isSection) {
-      const txt = sectionArr[0].txt.toHTML();
+      const txt = sectionArr[0].txt.toHTML()
       if (
-        txt.replaceAll("<p>", "").replaceAll("</p>", "").replaceAll(" ", "") ===
-        ""
+        txt
+          .replaceAll(
+            '<p size="0" _root="undefined" __ownerID="undefined" __hash="undefined" __altered="false"></p>',
+            ''
+          )
+          .replaceAll('<p>', '')
+          .replaceAll('</p>', '')
+          .replaceAll(' ', '') === ''
       )
-        flag = true;
+        flag = true
     } else {
       // 按章节发布  检查 所有的 标题 和富文本
       sectionArr.forEach((v, i) => {
-        if (!v.name) flag = true;
-        const txt: string = v.txt.toHTML();
+        if (!v.name) flag = true
+        const txt: string = v.txt.toHTML()
         if (
           txt
-            .replaceAll("<p>", "")
-            .replaceAll("</p>", "")
-            .replaceAll(" ", "") === ""
+            .replaceAll(
+              '<p size="0" _root="undefined" __ownerID="undefined" __hash="undefined" __altered="false"></p>',
+              ''
+            )
+            .replaceAll('<p>', '')
+            .replaceAll('</p>', '')
+            .replaceAll(' ', '') === ''
         )
-          flag = true;
-      });
+          flag = true
+      })
     }
 
-    return flag;
-  }, [isSection, sectionArr]);
+    return flag
+  }, [isSection, sectionArr])
 
-  const myInput = useRef<HTMLInputElement>(null);
+  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 filesInfo = e.target.files[0]
 
-        let type = ["image/jpeg", "image/png", "video/mp4"];
-        let size = 5;
-        let txt = "图片只支持png、jpg和jpeg格式!";
-        let txt2 = "图片最大支持5M!";
+        let type = ['image/jpeg', 'image/png', 'video/mp4']
+        let size = 5
+        let txt = '图片只支持png、jpg和jpeg格式!'
+        let txt2 = '图片最大支持5M!'
 
-        const isVideoFlag =
-          filesInfo.name.endsWith(".mp4") || filesInfo.name.endsWith(".MP4");
+        const isVideoFlag = filesInfo.name.endsWith('.mp4') || filesInfo.name.endsWith('.MP4')
 
         if (isVideoFlag) {
           // 上传视频
-          size = 500;
-          txt = "视频只支持mp4格式!";
-          txt2 = "视频最大支持500M!";
+          size = 500
+          txt = '视频只支持mp4格式!'
+          txt2 = '视频最大支持500M!'
         }
 
         // 校验格式
         if (!type.includes(filesInfo.type)) {
-          e.target.value = "";
-          return MessageFu.warning(txt);
+          e.target.value = ''
+          return MessageFu.warning(txt)
         }
 
         // 校验大小
         if (filesInfo.size > size * 1024 * 1024) {
-          e.target.value = "";
-          return MessageFu.warning(txt2);
+          e.target.value = ''
+          return MessageFu.warning(txt2)
         }
 
         // 创建FormData对象
-        const fd = new FormData();
+        const fd = new FormData()
         // 把files添加进FormData对象(‘photo’为后端需要的字段)
-        fd.append("type", isVideoFlag ? "video" : "img");
-        fd.append("dirCode", dirCode);
-        fd.append("file", filesInfo);
+        fd.append('type', isVideoFlag ? 'video' : 'img')
+        fd.append('dirCode', dirCode)
+        fd.append('file', filesInfo)
 
-        e.target.value = "";
+        e.target.value = ''
 
         try {
-          const res = await API_upFile(fd, myUrl);
+          const res = await API_upFile(fd, myUrl)
           if (res.code === 0) {
-            MessageFu.success("上传成功!");
+            MessageFu.success('上传成功!')
             // 在光标位置插入图片
-            const newTxt = ContentUtils.insertMedias(
-              sectionArr[nowIndexRef.current].txt,
-              [
-                {
-                  type: isVideoFlag ? "VIDEO" : "IMAGE",
-                  url: baseURL + res.data.filePath,
-                },
-              ]
-            );
-            const arr = [...sectionArr];
-            arr[nowIndexRef.current].txt = newTxt;
-            setSectionArr(arr);
+            const newTxt = ContentUtils.insertMedias(sectionArr[nowIndexRef.current].txt, [
+              {
+                type: isVideoFlag ? 'VIDEO' : 'IMAGE',
+                url: baseURL + res.data.filePath
+              }
+            ])
+            const arr = [...sectionArr]
+            arr[nowIndexRef.current].txt = newTxt
+            setSectionArr(arr)
           }
-          fileDomInitialFu();
+          fileDomInitialFu()
         } catch (error) {
-          fileDomInitialFu();
+          fileDomInitialFu()
         }
       }
     },
     [dirCode, myUrl, sectionArr]
-  );
+  )
 
   // 让父组件调用的 回显 富文本
   const ritxtShowFu = useCallback((val: any) => {
     if (val) {
-      setIsSection(val.isSection || false);
+      setIsSection(val.isSection || false)
       if (val.txtArr) {
         const arr = val.txtArr.map((v: any) => ({
           ...v,
-          txt: BraftEditor.createEditorState(v.txt),
-        }));
-        setSectionArr(arr);
+          txt: BraftEditor.createEditorState(v.txt)
+        }))
+        setSectionArr(arr)
       }
     }
-  }, []);
+  }, [])
 
   // 让父组件调用的返回 富文本信息 和 表单校验 isTxtFlag为ture表示未通过校验
   const fatherBtnOkFu = useCallback(() => {
-    const arr: any[] = [];
+    const arr: any[] = []
 
     sectionArr.forEach((v, i) => {
       arr.push({
         ...v,
-        txt: v.txt.toHTML(),
-      });
-    });
+        txt: v.txt.toHTML()
+      })
+    })
 
     const obj = {
       isSection: isSection, //是否按章节发布
-      txtArr: arr,
-    };
+      txtArr: arr
+    }
 
-    return { val: obj, flag: isTxtFlag };
-  }, [isSection, isTxtFlag, sectionArr]);
+    return { val: obj, flag: isTxtFlag }
+  }, [isSection, isTxtFlag, sectionArr])
 
   // 可以让父组件调用子组件的方法
   useImperativeHandle(ref, () => ({
     ritxtShowFu,
-    fatherBtnOkFu,
-  }));
+    fatherBtnOkFu
+  }))
 
   // 点击新增章节
   const addSectionFu = useCallback(() => {
-    if (sectionArr.length >= 20) return MessageFu.warning("最多存在20个章节");
+    if (sectionArr.length >= 20) return MessageFu.warning('最多存在20个章节')
     setSectionArr([
       ...sectionArr,
       {
         id: Date.now(),
-        name: "",
-        txt: BraftEditor.createEditorState(""),
-        fileInfo: { fileName: "", filePath: "" },
-      },
-    ]);
-  }, [sectionArr]);
+        name: '',
+        txt: BraftEditor.createEditorState(''),
+        fileInfo: { fileName: '', filePath: '' }
+      }
+    ])
+  }, [sectionArr])
 
   // 章节音频上传成功
   const upSectionFu = useCallback(
     (info: ZupAudioType, index: number) => {
-      const arr = [...sectionArr];
-      arr[index].fileInfo = info;
-      setSectionArr(arr);
+      const arr = [...sectionArr]
+      arr[index].fileInfo = info
+      setSectionArr(arr)
     },
     [sectionArr]
-  );
+  )
 
   // 章节音频删除
   const delSectionFu = useCallback(
     (index: number) => {
       // console.log("ppppppppp", index);
 
-      const arr = [...sectionArr];
-      arr[index].fileInfo = { fileName: "", filePath: "" };
-      setSectionArr(arr);
+      const arr = [...sectionArr]
+      arr[index].fileInfo = { fileName: '', filePath: '' }
+      setSectionArr(arr)
     },
     [sectionArr]
-  );
+  )
 
   // 整个章节的删除
   const delSectionAllFu = useCallback(
     (id: number) => {
-      setSectionArr(sectionArr.filter((v) => v.id !== id));
+      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 + num];
-      arr[index + num] = temp;
-      setSectionArr(arr);
+      const arr = [...sectionArr]
+      const temp = arr[index]
+      arr[index] = arr[index + num]
+      arr[index + num] = temp
+      setSectionArr(arr)
     },
     [sectionArr]
-  );
+  )
 
   // 单个富文本是否输入完整
   const isOneTxtFlag = useCallback(
     (name: string, txt: any) => {
-      let flag = false;
-      if (!name && isSection) flag = true;
-      const txtRes: string = txt.toHTML();
-      if (
-        txtRes
-          .replaceAll("<p>", "")
-          .replaceAll("</p>", "")
-          .replaceAll(" ", "") === ""
-      )
-        flag = true;
-      return flag;
+      let flag = false
+      if (!name && isSection) flag = true
+      const txtRes: string = txt.toHTML()
+      if (txtRes.replaceAll('<p>', '').replaceAll('</p>', '').replaceAll(' ', '') === '')
+        flag = true
+      return flag
     },
     [isSection]
-  );
+  )
 
   return (
     <div className={styles.ZRichTexts}>
       <input
-        id="upInput"
-        type="file"
-        accept=".png,.jpg,.jpeg,.mp4"
+        id='upInput'
+        type='file'
+        accept='.png,.jpg,.jpeg,.mp4'
         ref={myInput}
-        onChange={(e) => handeUpPhoto(e)}
+        onChange={e => handeUpPhoto(e)}
       />
 
-      <div
-        className={classNames("formRightZW", isLook ? "formRightZWLook" : "")}
-      >
+      <div className={classNames('formRightZW', isLook ? 'formRightZWLook' : '')}>
         {isOne ? (
           <div></div>
         ) : (
-          <Checkbox
-            checked={isSection}
-            onChange={(e) => setIsSection(e.target.checked)}
-          >
+          <Checkbox checked={isSection} onChange={e => setIsSection(e.target.checked)}>
             按章节发布
           </Checkbox>
         )}
 
         {isSection ? (
-          <Button hidden={isLook} type="primary" onClick={addSectionFu}>
+          <Button hidden={isLook} type='primary' onClick={addSectionFu}>
             新增章节
           </Button>
         ) : (
-          <div className="formRightZWRR">
+          <div className='formRightZWRR'>
             {upAudioBtnNone ? null : (
               <ZupAudio
                 fileInfo={sectionArr[0].fileInfo}
-                upDataFu={(info) => upSectionFu(info, 0)}
+                upDataFu={info => upSectionFu(info, 0)}
                 delFu={() => delSectionFu(0)}
                 dirCode={dirCode}
                 myUrl={myUrl}
@@ -328,8 +313,8 @@ function ZRichTexts(
             <div hidden={isLook} style={{ marginLeft: 20 }}>
               <Button
                 onClick={() => {
-                  nowIndexRef.current = 0;
-                  myInput.current?.click();
+                  nowIndexRef.current = 0
+                  myInput.current?.click()
                 }}
               >
                 上传图片/视频
@@ -339,51 +324,51 @@ function ZRichTexts(
         )}
       </div>
 
-      <div className={classNames("txtBox", isLook ? "txtBoxLook" : "")}>
+      <div className={classNames('txtBox', isLook ? 'txtBoxLook' : '')}>
         {sectionArr.map((item, index) => (
           <div
             className={classNames(
-              "zztxtRow",
-              isOneTxtFlag(item.name, item.txt) && check ? "zztxtRowErr" : ""
+              'zztxtRow',
+              isOneTxtFlag(item.name, item.txt) && check ? 'zztxtRowErr' : ''
             )}
             key={item.id}
             hidden={!isSection && index > 0}
           >
             {/* 顶部 */}
-            <div className="zztxtRow1" hidden={!isSection && index === 0}>
-              <div className="zztxtRow1_1">
-                <div className="zztxtRow1_1_1">章节 {index + 1}</div>
-                <div className="zztxtRow1_1_2">
+            <div className='zztxtRow1' hidden={!isSection && index === 0}>
+              <div className='zztxtRow1_1'>
+                <div className='zztxtRow1_1_1'>章节 {index + 1}</div>
+                <div className='zztxtRow1_1_2'>
                   标题:
                   <Input
                     readOnly={isLook}
                     value={item.name}
-                    placeholder="请输入内容"
+                    placeholder='请输入内容'
                     maxLength={100}
                     showCount
                     style={{ width: 400 }}
-                    onChange={(e) => {
-                      const arr = [...sectionArr];
-                      arr[index].name = e.target.value.replace(/\s+/g, "");
-                      setSectionArr(arr);
+                    onChange={e => {
+                      const arr = [...sectionArr]
+                      arr[index].name = e.target.value.replace(/\s+/g, '')
+                      setSectionArr(arr)
                     }}
                   />
                   &emsp;
                   <Button
                     hidden={isLook}
                     onClick={() => {
-                      nowIndexRef.current = index;
-                      myInput.current?.click();
+                      nowIndexRef.current = index
+                      myInput.current?.click()
                     }}
                   >
                     上传图片/视频
                   </Button>
                 </div>
               </div>
-              <div className="zztxtRow1_2">
+              <div className='zztxtRow1_2'>
                 <ZupAudio
                   fileInfo={item.fileInfo}
-                  upDataFu={(info) => upSectionFu(info, index)}
+                  upDataFu={info => upSectionFu(info, index)}
                   delFu={() => delSectionFu(index)}
                   dirCode={dirCode}
                   myUrl={myUrl}
@@ -392,31 +377,28 @@ function ZRichTexts(
                 &emsp;
                 <div
                   hidden={isLook}
-                  className={classNames(
-                    "zztxtRow1_2Icon",
-                    index === 0 ? "zztxtRow1_2IconNo" : ""
-                  )}
+                  className={classNames('zztxtRow1_2Icon', index === 0 ? 'zztxtRow1_2IconNo' : '')}
                   onClick={() => moveSectionFu(index, -1)}
                 >
-                  <ArrowUpOutlined title="上移" />
+                  <ArrowUpOutlined title='上移' />
                 </div>
                 &emsp;
                 <div
                   hidden={isLook}
                   className={classNames(
-                    "zztxtRow1_2Icon",
-                    index === sectionArr.length - 1 ? "zztxtRow1_2IconNo" : ""
+                    'zztxtRow1_2Icon',
+                    index === sectionArr.length - 1 ? 'zztxtRow1_2IconNo' : ''
                   )}
                   onClick={() => moveSectionFu(index, 1)}
                 >
-                  <ArrowDownOutlined title="下移" />
+                  <ArrowDownOutlined title='下移' />
                 </div>
                 &emsp;
-                {isLook ? null : (
+                {isLook || sectionArr.length <= 1 ? null : (
                   <MyPopconfirm
-                    txtK="删除"
+                    txtK='删除'
                     onConfirm={() => delSectionAllFu(item.id)}
-                    Dom={<DeleteOutlined title="删除" className="ZTbox2X" />}
+                    Dom={<DeleteOutlined title='删除' className='ZTbox2X' />}
                   />
                 )}
               </div>
@@ -424,28 +406,23 @@ function ZRichTexts(
             {/* 主体 */}
             <BraftEditor
               readOnly={isLook}
-              placeholder="请输入内容"
+              placeholder='请输入内容'
               value={item.txt}
-              onChange={(e) => {
-                const arr = [...sectionArr];
-                arr[index].txt = e;
-                setSectionArr(arr);
+              onChange={e => {
+                const arr = [...sectionArr]
+                arr[index].txt = e
+                setSectionArr(arr)
               }}
-              imageControls={["remove"]}
+              imageControls={['remove']}
             />
           </div>
         ))}
       </div>
-      <div
-        className={classNames(
-          "noUpThumb",
-          check && isTxtFlag ? "noUpThumbAc" : ""
-        )}
-      >
-        {`请完整输入${isSection ? "标题/" : ""}正文!`}
+      <div className={classNames('noUpThumb', check && isTxtFlag ? 'noUpThumbAc' : '')}>
+        {`请完整输入${isSection ? '标题/' : ''}正文!`}
       </div>
     </div>
-  );
+  )
 }
 
-export default forwardRef(ZRichTexts);
+export default forwardRef(ZRichTexts)

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

@@ -145,6 +145,11 @@ function A1add({ editInfo, closeFu, editTableFu, addTableFu }: Props) {
       // 富文本校验不通过
       const rtf = ZRichTextRef.current?.fatherBtnOkFu() || { flag: true }
 
+      // if (1 + 1 === 2) {
+      //   console.log('------', rtf)
+      //   return
+      // }
+
       if (rtf.flag) return MessageFu.warning('请输入完整正文!')
 
       // 富文本标题集合