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

+ 201 - 0
houtai/src/pages/A2News/NewsAdd/index.module.scss

@@ -0,0 +1,201 @@
+.NewsAdd {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: #fff;
+  border-radius: 10px;
+  z-index: 20;
+
+  :global {
+    .formBox {
+      width: 900px;
+      margin-top: 15px;
+      height: calc(100% - 75px);
+      padding-right: 100px;
+      overflow-y: auto;
+
+
+      // 多张附件图片上传
+
+
+      .myformBox {
+        display: flex;
+        margin-bottom: 10px;
+        margin-top: 40px;
+
+        .ant-btn-default {
+          width: 100px;
+        }
+
+        .label {
+          width: 100px;
+          text-align: right;
+
+          &>span {
+            position: relative;
+            top: 2px;
+            color: #ff4d4f;
+          }
+        }
+
+        .fileBoxRow_r {
+          position: relative;
+
+          .fileBoxRow_up {
+            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;
+
+
+          }
+
+          .fileBoxRow_r_img {
+            width: 100px;
+            height: 100px;
+            position: relative;
+
+            .clearCover {
+              cursor: pointer;
+              z-index: 10;
+              position: absolute;
+              width: 50px;
+              height: 50px;
+              top: 50%;
+              transform: translateY(-50%);
+              right: -50px;
+              display: flex;
+              justify-content: center;
+              align-items: center;
+              font-size: 24px;
+            }
+          }
+
+          .fileBoxRow_r_tit {
+            height: 46px;
+            margin-top: 5px;
+            font-size: 14px;
+            color: rgb(126, 124, 124);
+
+
+          }
+
+          .upImgBox {
+            display: flex;
+            flex-wrap: wrap;
+            max-width: 700px;
+
+            &>div {
+              margin: 0 15px 15px 0;
+            }
+
+            .fileBoxRow_r_img {
+              position: relative;
+
+              .clearCover {
+                right: -10px;
+                top: -10px;
+                transform: translate(0, 0);
+                background-color: rgba(0, 0, 0, .8);
+                width: 20px;
+                height: 20px;
+                border-radius: 50%;
+                font-size: 16px;
+                color: #fff;
+              }
+            }
+          }
+
+        }
+
+      }
+
+      // 视频和单个图片上传
+      .myformBox2 {
+        align-items: center;
+        height: 32px;
+
+        .label {
+          height: 32px;
+          line-height: 32px;
+        }
+
+        .fileTit {
+          margin-left: 20px;
+          font-size: 14px;
+          color: rgb(126, 124, 124);
+        }
+
+        .fileInfo {
+          height: 32px;
+          line-height: 32px;
+          display: flex;
+          font-size: 16px;
+
+          .clearCover {
+            margin-left: 20px;
+            cursor: pointer;
+            font-size: 18px;
+          }
+
+        }
+
+
+      }
+
+      .myformBox3{
+        margin-bottom: -20px;
+      }
+
+    }
+
+    .noUpThumb {
+      position: relative;
+      overflow: hidden;
+      opacity: 0;
+      transition: top .2s;
+      color: #ff4d4f;
+      top: -10px;
+    }
+
+    .noUpThumb2 {
+      position: relative;
+      padding-left: 100px;
+      margin-bottom: 12px;
+    }
+
+    .noUpThumbAc {
+      top: 0;
+      opacity: 1;
+    }
+
+    .formBox::-webkit-scrollbar {
+      /*滚动条整体样式*/
+      width: 5px;
+      /*高宽分别对应横竖滚动条的尺寸*/
+      height: 1px;
+    }
+
+    .formBox::-webkit-scrollbar-thumb {
+      /*滚动条里面小方块*/
+      border-radius: 10px;
+      -webkit-box-shadow: inset 0 0 5px transparent;
+      background: var(--themeColor);
+    }
+
+    .formBox::-webkit-scrollbar-track {
+      /*滚动条里面轨道*/
+      -webkit-box-shadow: inset 0 0 5px transparent;
+      border-radius: 10px;
+      background: transparent;
+    }
+  }
+}

+ 479 - 0
houtai/src/pages/A2News/NewsAdd/index.tsx

@@ -0,0 +1,479 @@
+import { newsUploadAPI } from "@/store/action/A2News";
+import { domShowFu, progressDomFu } from "@/utils/domShow";
+import { MessageFu } from "@/utils/message";
+import { Button, DatePicker, Form, Input, Popconfirm, Select } from "antd";
+import TextArea from "antd/es/input/TextArea";
+import dayjs from "dayjs";
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
+import styles from "./index.module.scss";
+import {
+  PlusOutlined,
+  CloseOutlined,
+  PlayCircleOutlined,
+  CloseCircleOutlined,
+  UploadOutlined,
+} from "@ant-design/icons";
+import ImageLazy from "@/components/ImageLazy";
+import classNames from "classnames";
+import store from "@/store";
+
+type Props = {
+  id: number;
+  tableType: string;
+  closePageFu: () => void;
+  editTableFu: () => void;
+  addTableFu: () => void;
+};
+
+type ImgListType = {
+  fileName: string;
+  filePath: string;
+  id: number;
+};
+
+function NewsAdd({
+  id,
+  closePageFu,
+  editTableFu,
+  addTableFu,
+  tableType,
+}: Props) {
+  // 设置表单初始数据(区分编辑和新增)
+  const FormBoxRef = useRef<any>({});
+
+  // 通过id获取详情,回显数据
+  const getInfoFu = useCallback((id: number) => {
+    // setDirCode(res.data.entity.dirCode);
+  }, []);
+
+  useEffect(() => {
+    if (id > 0) getInfoFu(id);
+    else {
+      setDirCode(Date.now() + "");
+      FormBoxRef.current.setFieldsValue({
+        display: 1,
+        // 默认新闻日期为当天
+        myTime:
+          tableType === "news"
+            ? dayjs(dayjs(new Date()).format("YYYY-MM-DD"), "YYYY-MM-DD")
+            : "",
+      });
+    }
+  }, [getInfoFu, id, tableType]);
+
+  const myInput = useRef<HTMLInputElement>(null);
+
+  // 文件的dirCode码
+  const [dirCode, setDirCode] = useState("");
+
+  // 多张图片附件
+  const [imgList, setImgList] = useState<ImgListType[]>([]);
+
+  // 单个视频或者图片上传
+  const [fileOne, setFileOne] = useState<ImgListType>({
+    fileName: "",
+    filePath: "",
+    id: 0,
+  });
+
+  // 上传附件的处理函数
+  const handeUpPhoto = useCallback(
+    async (e: React.ChangeEvent<HTMLInputElement>) => {
+      if (e.target.files) {
+        // 拿到files信息
+        const filesInfo = e.target.files[0];
+
+        let anType = ["image/jpeg", "image/png"];
+        let anTit1 = "只支持png、jpg和jpeg格式!";
+        let anTit2 = "最大支持20M!";
+        let anSize = 20 * 1024 * 1024;
+
+        if (tableType === "video") {
+          anType = ["video/mp4"];
+          anTit1 = "只支持mp4格式!";
+          anTit2 = "最大支持500M!";
+          anSize = 500 * 1024 * 1024;
+        }
+
+        // 校验格式
+        if (!anType.includes(filesInfo.type)) {
+          e.target.value = "";
+          return MessageFu.warning(anTit1);
+        }
+
+        // 校验大小
+        if (filesInfo.size > anSize) {
+          e.target.value = "";
+          return MessageFu.warning(anTit2);
+        }
+        // 创建FormData对象
+        const fd = new FormData();
+        // 把files添加进FormData对象(‘photo’为后端需要的字段)
+        fd.append("type", tableType === "video" ? "video" : "img");
+        fd.append("dirCode", dirCode);
+        fd.append("file", filesInfo);
+
+        e.target.value = "";
+
+        const res: any = await newsUploadAPI(fd);
+
+        if (res.code === 0) {
+          MessageFu.success("上传成功!");
+          if (tableType === "news") setImgList([...imgList, res.data]);
+          else setFileOne(res.data);
+        }
+        domShowFu("#UpAsyncLoding", false);
+        progressDomFu("0%");
+      }
+    },
+    [dirCode, imgList, tableType]
+  );
+
+  // 附件图片的拖动
+  const [dragImg, setDragImg] = useState<any>(null);
+
+  const handleDragOver = useCallback(
+    (e: React.DragEvent<HTMLDivElement>, item: ImgListType) => {
+      e.dataTransfer.dropEffect = "move";
+    },
+    []
+  );
+
+  const handleDragEnter = useCallback(
+    (e: React.DragEvent<HTMLDivElement>, item: ImgListType) => {
+      e.dataTransfer.effectAllowed = "move";
+      if (item === dragImg) return;
+      const newItems = [...imgList]; //拷贝一份数据进行交换操作。
+      const src = newItems.indexOf(dragImg); //获取数组下标
+      const dst = newItems.indexOf(item);
+      newItems.splice(dst, 0, ...newItems.splice(src, 1)); //交换位置
+      setImgList(newItems);
+    },
+    [dragImg, imgList]
+  );
+
+  // 删除某一张图片
+  const delImgListFu = useCallback(
+    (id: number) => {
+      const newItems = imgList.filter((v) => v.id !== id);
+      setImgList(newItems);
+    },
+    [imgList]
+  );
+
+  const [typeOk, setTypeOk] = useState(false);
+
+  // 附件信息的校验
+  const fileCheckFu = useMemo(() => {
+    let flag = false;
+    if (tableType === "news" && imgList.length === 0) flag = true;
+    if (tableType !== "news" && !fileOne.filePath) flag = true;
+    return flag;
+  }, [fileOne.filePath, imgList.length, tableType]);
+
+  // 没有通过校验
+  const onFinishFailed = useCallback(() => {
+    setTypeOk(true);
+    // return MessageFu.warning("有表单不符号规则!");
+  }, []);
+
+  // 通过校验点击确定
+  const onFinish = useCallback(
+    (values: any) => {
+      setTypeOk(true);
+
+      if (fileCheckFu) return;
+
+      const obj = {
+        ...values,
+        id: id > 0 ? id : null,
+        dirCode,
+        myTime: values.myTime ? dayjs(values.myTime).format("YYYY-MM-DD") : "",
+        fileIds:
+          tableType === "news"
+            ? imgList.map((v) => v.id).join(",")
+            : fileOne.id,
+      };
+      console.log(obj);
+      if (id > 0) editTableFu();
+      else addTableFu();
+      closePageFu();
+    },
+    [
+      addTableFu,
+      closePageFu,
+      dirCode,
+      editTableFu,
+      fileCheckFu,
+      fileOne.id,
+      id,
+      imgList,
+      tableType,
+    ]
+  );
+
+  return (
+    <div className={styles.NewsAdd}>
+      <div className="pageTitle">{id > 0 ? "编辑资讯" : "新增资讯"}</div>
+      <div className="formBox">
+        <Form
+          ref={FormBoxRef}
+          name="basic"
+          labelCol={{ span: 3 }}
+          onFinish={onFinish}
+          onFinishFailed={onFinishFailed}
+          autoComplete="off"
+        >
+          <Form.Item
+            label="标题"
+            name="name"
+            rules={[{ required: true, message: "请输入标题!" }]}
+            getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
+          >
+            <Input maxLength={20} showCount placeholder="请输入内容" />
+          </Form.Item>
+
+          <input
+            id="upInput2"
+            type="file"
+            accept={tableType === "video" ? ".mp4" : ".png,.jpg,.jpeg"}
+            ref={myInput}
+            onChange={(e) => handeUpPhoto(e)}
+          />
+
+          {tableType === "news" ? (
+            <>
+              <Form.Item
+                label="新闻日期"
+                name="myTime"
+                rules={[{ required: true, message: "请选择新闻日期!" }]}
+              >
+                <DatePicker />
+              </Form.Item>
+              <Form.Item
+                label="正文"
+                name="myTxt"
+                rules={[{ required: true, message: "请输入正文!" }]}
+                // getValueFromEvent={(e) => e.target.value.trim()}
+              >
+                <TextArea
+                  rows={8}
+                  placeholder="请输入内容"
+                  showCount
+                  maxLength={1000}
+                />
+              </Form.Item>
+
+              {/* 上传附件图片 */}
+              <div className="myformBox">
+                <div className="label">
+                  <span>*</span> 图片:
+                </div>
+                <>
+                  <div className="fileBoxRow_r">
+                    <div className="upImgBox">
+                      <div
+                        hidden={imgList.length >= 9}
+                        className="fileBoxRow_up"
+                        onClick={() => myInput.current?.click()}
+                      >
+                        <PlusOutlined />
+                      </div>
+                      {imgList.map((v) => (
+                        <div
+                          className="fileBoxRow_r_img"
+                          key={v.id}
+                          draggable="true"
+                          onDragStart={() => setDragImg(v)}
+                          onDragOver={(e) => handleDragOver(e, v)}
+                          onDragEnter={(e) => handleDragEnter(e, v)}
+                          onDragEnd={() => setDragImg(null)}
+                        >
+                          {v.filePath ? (
+                            <ImageLazy
+                              noLook={dragImg ? true : false}
+                              width={100}
+                              height={100}
+                              src={v.filePath}
+                            />
+                          ) : null}
+
+                          <Popconfirm
+                            title="删除后无法恢复,是否删除?"
+                            okText="删除"
+                            cancelText="取消"
+                            onConfirm={() => delImgListFu(v.id)}
+                          >
+                            <div className="clearCover">
+                              <CloseOutlined />
+                            </div>
+                          </Popconfirm>
+                        </div>
+                      ))}
+                    </div>
+                    <div className="fileTit">
+                      {imgList.length >= 2 ? (
+                        <>
+                          按住鼠标可拖动图片调整顺序。
+                          <br />
+                        </>
+                      ) : null}
+                      支持png、jpg和jpeg的图片格式;最大支持20M;最多支持9张。
+                    </div>
+                  </div>
+                </>
+              </div>
+            </>
+          ) : tableType === "video" ? (
+            // 上传视频
+            <>
+              {/* -----------视频上传 */}
+              <div className="myformBox myformBox2">
+                <div className="label">
+                  <span>*</span> 视频:
+                </div>
+                {fileOne.id ? (
+                  <div className="fileInfo">
+                    <div className="upSuccTxt">{fileOne.fileName}</div>
+                    <div
+                      className="clearCover"
+                      hidden={!fileOne.filePath}
+                      onClick={() =>
+                        store.dispatch({
+                          type: "layout/lookVideo",
+                          payload: fileOne.filePath!,
+                        })
+                      }
+                    >
+                      <PlayCircleOutlined />
+                    </div>
+
+                    <Popconfirm
+                      title="删除后无法恢复,是否删除?"
+                      okText="删除"
+                      cancelText="取消"
+                      onConfirm={() =>
+                        setFileOne({ fileName: "", filePath: "", id: 0 })
+                      }
+                    >
+                      <div className="clearCover">
+                        <CloseCircleOutlined />
+                      </div>
+                    </Popconfirm>
+                  </div>
+                ) : (
+                  <>
+                    <Button
+                      onClick={() => myInput.current?.click()}
+                      icon={<UploadOutlined />}
+                    >
+                      上传
+                    </Button>
+
+                    <div className="fileTit">
+                      仅支持MP4格式的视频文件,大小不得超过500MB。
+                    </div>
+                  </>
+                )}
+              </div>
+            </>
+          ) : (
+            <>
+              {/* 上传单张图片 */}
+              <div className="myformBox myformBox3">
+                <div className="label">
+                  <span>*</span> 图片:
+                </div>
+                <div className="fileBoxRow_r">
+                  <div
+                    hidden={!!fileOne.filePath}
+                    className="fileBoxRow_up"
+                    onClick={() => myInput.current?.click()}
+                  >
+                    <PlusOutlined />
+                  </div>
+                  <div className="fileBoxRow_r_img" hidden={!fileOne.filePath}>
+                    {fileOne.filePath ? (
+                      <ImageLazy
+                        width={100}
+                        height={100}
+                        src={fileOne.filePath}
+                      />
+                    ) : null}
+
+                    <Popconfirm
+                      title="删除后无法恢复,是否删除?"
+                      okText="删除"
+                      cancelText="取消"
+                      onConfirm={() =>
+                        setFileOne({ fileName: "", filePath: "", id: 0 })
+                      }
+                    >
+                      <div className="clearCover">
+                        <CloseCircleOutlined />
+                      </div>
+                    </Popconfirm>
+                  </div>
+                  <div className="fileBoxRow_r_tit">
+                    支持png、jpg和jpeg的图片格式;最大支持20M。
+                  </div>
+                </div>
+              </div>
+            </>
+          )}
+
+          <div
+            className={classNames(
+              "noUpThumb noUpThumb2",
+              fileCheckFu && typeOk ? "noUpThumbAc" : ""
+            )}
+          >
+            请上传附件!
+          </div>
+
+          <Form.Item
+            label="展示状态"
+            name="display"
+            rules={[{ required: true, message: "请选择展示状态!" }]}
+          >
+            <Select
+              placeholder="请选择"
+              style={{ width: 400 }}
+              options={[
+                { value: 1, label: "展示" },
+                { value: 0, label: "不展示" },
+              ]}
+            />
+          </Form.Item>
+
+          {/* 确定和取消按钮 */}
+          <br />
+          <Form.Item wrapperCol={{ offset: 10, span: 16 }}>
+            <Button type="primary" htmlType="submit">
+              提交
+            </Button>
+            &emsp;
+            <Popconfirm
+              title="放弃编辑后,信息将不会保存!"
+              okText="放弃"
+              cancelText="取消"
+              onConfirm={closePageFu}
+            >
+              <Button>取消</Button>
+            </Popconfirm>
+          </Form.Item>
+        </Form>
+      </div>
+    </div>
+  );
+}
+
+const MemoNewsAdd = React.memo(NewsAdd);
+
+export default MemoNewsAdd;

+ 8 - 3
houtai/src/pages/A2News/NewsTable/index.tsx

@@ -14,9 +14,10 @@ import { HTML5Backend } from "react-dnd-html5-backend";
 
 type Porps = {
   tableType: string;
+  editInfoFu: (id: number) => void;
 };
 
-function NewsTable({ tableType }: Porps) {
+function NewsTable({ tableType, editInfoFu }: Porps) {
   // 有关表格数据
   const results = useSelector(
     (state: RootState) => state.newsReducer.tableInfo
@@ -87,7 +88,11 @@ function NewsTable({ tableType }: Porps) {
         title: "操作",
         render: (item: NewsTableType) => (
           <>
-            <Button size="small" type="text">
+            <Button
+              size="small"
+              type="text"
+              onClick={() => editInfoFu(item.id)}
+            >
               编辑
             </Button>
             <Button size="small" type="text" danger>
@@ -97,7 +102,7 @@ function NewsTable({ tableType }: Porps) {
         ),
       },
     ];
-  }, [results.length, tableType]);
+  }, [editInfoFu, results.length, tableType]);
 
   // 表格拖动排序-----------------
   interface DraggableBodyRowProps

+ 1 - 0
houtai/src/pages/A2News/index.module.scss

@@ -1,4 +1,5 @@
 .News {
+  position: relative;
   :global {
     .newTop {
       background-color: #fff;

+ 37 - 4
houtai/src/pages/A2News/index.tsx

@@ -1,3 +1,5 @@
+import { RootState } from "@/store";
+import { MessageFu } from "@/utils/message";
 import { Button, Input, Select } from "antd";
 import React, {
   useCallback,
@@ -6,7 +8,9 @@ import React, {
   useRef,
   useState,
 } from "react";
+import { useSelector } from "react-redux";
 import styles from "./index.module.scss";
+import NewsAdd from "./NewsAdd";
 import NewsTable from "./NewsTable";
 function News() {
   // 顶部筛选的数据
@@ -67,6 +71,21 @@ function News() {
   // 新增或者编辑的id
   const [editId, setEditId] = useState(0);
 
+  // 有关表格数据
+  const results = useSelector(
+    (state: RootState) => state.newsReducer.tableInfo
+  );
+
+  // 点击新增或者编辑
+  const addInfoFu = useCallback(
+    (id: number) => {
+      if (id === -1 && results.length >= 50)
+        return MessageFu.warning("最多可录入50条信息!");
+      setEditId(id);
+    },
+    [results.length]
+  );
+
   return (
     <div className={styles.News}>
       <div className="newTop">
@@ -113,13 +132,27 @@ function News() {
           <div className="row">
             <Button onClick={resetSelectFu}>重置</Button>
             &emsp;&emsp;&emsp;&emsp;
-            <Button type="primary">新增</Button>
+            <Button type="primary" onClick={() => addInfoFu(-1)}>
+              新增
+            </Button>
           </div>
         </div>
       </div>
-
-      {/* 表格主体 */}
-      <NewsTable tableType={tableSelect.type} />
+      {/* 新增和编辑 和 表格主体 (拖动有冲突,所以只能同时渲染一个)*/}
+      {editId ? (
+        <NewsAdd
+          id={editId}
+          tableType={tableSelect.type}
+          closePageFu={() => setEditId(0)}
+          editTableFu={() => console.log("编辑了数据")}
+          addTableFu={resetSelectFu}
+        />
+      ) : (
+        <NewsTable
+          tableType={tableSelect.type}
+          editInfoFu={(id) => addInfoFu(id)}
+        />
+      )}
     </div>
   );
 }

+ 24 - 11
houtai/src/store/action/A2News.ts

@@ -1,15 +1,28 @@
+import { domShowFu, progressDomFu } from "@/utils/domShow";
 import http from "@/utils/http";
-import { AppDispatch } from "..";
+import axios from "axios";
+import store, { AppDispatch } from "..";
 
+const CancelToken = axios.CancelToken;
 /**
- * 获取列表数据
+ * 上传封面图和附件
  */
-export const getGoodsListAPI = (data: any) => {
-  return async (dispatch: AppDispatch) => {
-    // const res = await http.post("cms/goods/pageList", data);
-    // dispatch({
-    //   type: "goods/getList",
-    //   payload: { list: res.data.records, total: res.data.total },
-    // });
-  };
-};
+export const newsUploadAPI = (data: any) => {
+  domShowFu("#UpAsyncLoding", true);
+
+  return http.post("cms/goods/upload", data, {
+    timeout: 50000,
+    // 显示进度条
+    onUploadProgress: (e: any) => {
+      const complete = (e.loaded / e.total) * 100 || 0;
+      progressDomFu(complete + "%");
+    },
+    // 取消上传
+    cancelToken: new CancelToken(function executor(c) {
+      store.dispatch({
+        type: "layout/closeUpFile",
+        payload: { fu: c, state: true },
+      });
+    }),
+  });
+};

+ 6 - 6
houtai/src/utils/http.ts

@@ -7,10 +7,10 @@ import { domShowFu, progressDomFu } from "./domShow";
 // 请求基地址
 export const baseURL =
   // 线下的图片地址需要加上/api/
-  // process.env.NODE_ENV === "development"
-  //   ? "http://192.168.20.55:8041/api/"
-  //   : "";
-process.env.NODE_ENV === "development" ? "https://xuzhouwall.4dage.com" : "";
+  process.env.NODE_ENV === "development"
+    ? "http://192.168.20.55:8041/api/"
+    : "";
+// process.env.NODE_ENV === "development" ? "https://xuzhouwall.4dage.com" : "";
 
 // 处理  类型“AxiosResponse<any, any>”上不存在属性“code”
 declare module "axios" {
@@ -23,10 +23,10 @@ declare module "axios" {
 // 创建 axios 实例
 const http = axios.create({
   // --------线下的地址不用加/api/
-  // baseURL: baseURL,
+  baseURL: baseURL,
 
   // --------打包或线上环境接口需要加上api/
-  baseURL: baseURL + "/api/",
+  // baseURL: baseURL + "/api/",
   timeout: 5000,
 });