|
@@ -0,0 +1,456 @@
|
|
|
|
+import React, {
|
|
|
|
+ useCallback,
|
|
|
|
+ useEffect,
|
|
|
|
+ useMemo,
|
|
|
|
+ useRef,
|
|
|
|
+ useState,
|
|
|
|
+} from "react";
|
|
|
|
+import styles from "./index.module.scss";
|
|
|
|
+import {
|
|
|
|
+ A2_APIgetBarrage,
|
|
|
|
+ A2_APIgetBarrageAll,
|
|
|
|
+ A2_APIgetConfigBarrage,
|
|
|
|
+ A2_APIgetGoodsInfo,
|
|
|
|
+ A2_APIgetQuestion,
|
|
|
|
+ A2_APIgoodsaddStar,
|
|
|
|
+} from "@/store/action/A2Main";
|
|
|
|
+import {
|
|
|
|
+ A2BarrageType,
|
|
|
|
+ A2FileType,
|
|
|
|
+ A2GoodsType,
|
|
|
|
+ A2QuestionType,
|
|
|
|
+} from "@/types";
|
|
|
|
+import { baseURL } from "@/utils/http";
|
|
|
|
+import closeImg from "@/assets/img/goods/close.png";
|
|
|
|
+import homeImg from "@/assets/img/goods/toHome.png";
|
|
|
|
+import history from "@/utils/history";
|
|
|
|
+import classNames from "classnames";
|
|
|
|
+import icon1 from "@/assets/img/goods/icon1.png";
|
|
|
|
+import icon2 from "@/assets/img/goods/icon2.png";
|
|
|
|
+import icon3 from "@/assets/img/goods/icon3.png";
|
|
|
|
+import icon4 from "@/assets/img/goods/icon4.png";
|
|
|
|
+import icon5 from "@/assets/img/goods/icon5.png";
|
|
|
|
+import icon1Ac from "@/assets/img/goods/icon1Ac.png";
|
|
|
|
+import icon3Ac from "@/assets/img/goods/icon3Ac.png";
|
|
|
|
+import icon4Ac from "@/assets/img/goods/icon4Ac.png";
|
|
|
|
+import icon5Ac from "@/assets/img/goods/icon5Ac.png";
|
|
|
|
+import { MessageFu } from "@/utils/message";
|
|
|
|
+import { gsap } from "gsap";
|
|
|
|
+import Left2 from "./Left2";
|
|
|
|
+import Left3 from "./Left3";
|
|
|
|
+import Left4 from "./Left4";
|
|
|
|
+import RightFile from "./RightFile";
|
|
|
|
+import Rform from "./Rform";
|
|
|
|
+
|
|
|
|
+type Props = {
|
|
|
|
+ isOpen: boolean;
|
|
|
|
+ id: number;
|
|
|
|
+ closePage?: () => void;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+function GoodsInfo({ isOpen, id, closePage }: Props) {
|
|
|
|
+ // 文物信息
|
|
|
|
+ const [info, setInfo] = useState<A2GoodsType>({} as A2GoodsType);
|
|
|
|
+ // 附件数据
|
|
|
|
+ const [fileList, setFileList] = useState<A2FileType[]>([]);
|
|
|
|
+
|
|
|
|
+ // 音频的url
|
|
|
|
+ const [audio, setAudio] = useState("");
|
|
|
|
+
|
|
|
|
+ // 右侧图标
|
|
|
|
+ const [right1, setRight1] = useState({ show: false, done: false });
|
|
|
|
+ const [right2, setRight2] = useState({ show: false, done: false });
|
|
|
|
+ const [right3, setRight3] = useState({ show: false, done: false });
|
|
|
|
+ const [right4, setRight4] = useState(false);
|
|
|
|
+ const [right5, setRight5] = useState(false);
|
|
|
|
+
|
|
|
|
+ // 打开和关闭音频
|
|
|
|
+ const audioCutFu = useCallback((val: boolean) => {
|
|
|
|
+ const dom: HTMLAudioElement = document.querySelector("#myAudio")!;
|
|
|
|
+ if (val) dom.play();
|
|
|
|
+ else dom.pause();
|
|
|
|
+ setRight1({ show: true, done: val });
|
|
|
|
+ }, []);
|
|
|
|
+
|
|
|
|
+ // 点击点赞
|
|
|
|
+ const likeClickFu = useCallback(async () => {
|
|
|
|
+ if (right4) return;
|
|
|
|
+ await A2_APIgoodsaddStar(id);
|
|
|
|
+ setRight4(true);
|
|
|
|
+ window.setTimeout(() => {
|
|
|
|
+ setRight4(false);
|
|
|
|
+ }, 3000);
|
|
|
|
+ }, [id, right4]);
|
|
|
|
+
|
|
|
|
+ // 点击分享链接
|
|
|
|
+ const fenXClickFu = useCallback(() => {
|
|
|
|
+ if (right5) return;
|
|
|
|
+ setRight5(true);
|
|
|
|
+ window.setTimeout(() => {
|
|
|
|
+ setRight5(false);
|
|
|
|
+ }, 3000);
|
|
|
|
+ let OrderNumber = window.location.origin + "/#/goods?id=" + id;
|
|
|
|
+ let newInput = document.createElement("input");
|
|
|
|
+ newInput.value = OrderNumber;
|
|
|
|
+ document.body.appendChild(newInput);
|
|
|
|
+ newInput.select();
|
|
|
|
+ document.execCommand("Copy");
|
|
|
|
+ newInput.remove();
|
|
|
|
+ MessageFu.success("复制链接成功");
|
|
|
|
+ }, [id, right5]);
|
|
|
|
+
|
|
|
|
+ // 简介-知识-问答-留言
|
|
|
|
+ const [leftAc, setLeftAc] = useState(1);
|
|
|
|
+
|
|
|
|
+ const leftArrTemp = useMemo(() => {
|
|
|
|
+ return [
|
|
|
|
+ { id: 1, name: "简介", done: true },
|
|
|
|
+ { id: 2, name: "知识", done: false },
|
|
|
|
+ { id: 3, name: "问答", done: false },
|
|
|
|
+ { id: 4, name: "留言", done: false },
|
|
|
|
+ ];
|
|
|
|
+ }, []);
|
|
|
|
+
|
|
|
|
+ const [leftArr, setLeftArr] = useState(leftArrTemp.filter((v) => v.done));
|
|
|
|
+
|
|
|
|
+ // 问答数组
|
|
|
|
+ const [question, setQuestion] = useState<A2QuestionType[]>([]);
|
|
|
|
+
|
|
|
|
+ // 文物留言的数组
|
|
|
|
+ const [barrage, setBarrage] = useState<A2BarrageType[]>([]);
|
|
|
|
+
|
|
|
|
+ // 所有弹幕的数组
|
|
|
|
+ const [barrageAll, setBarrageAll] = useState<A2BarrageType[]>([]);
|
|
|
|
+ const barrMoveRef = useRef<HTMLDivElement>(null);
|
|
|
|
+ const [barrInd, setBarrInd] = useState(0);
|
|
|
|
+ const barrIndRef = useRef(0);
|
|
|
|
+ const barrTimeRef = useRef(0);
|
|
|
|
+ const barrMoveRefKill = useRef<any>(null);
|
|
|
|
+
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ if (barrageAll.length) {
|
|
|
|
+ // 开启定时器
|
|
|
|
+ barrTimeRef.current = window.setInterval(() => {
|
|
|
|
+ let num = barrIndRef.current + 1;
|
|
|
|
+ if (num >= barrageAll.length) num = 0;
|
|
|
|
+ setBarrInd(num);
|
|
|
|
+ barrIndRef.current = num;
|
|
|
|
+ }, 17000);
|
|
|
|
+ }
|
|
|
|
+ }, [barrageAll.length]);
|
|
|
|
+
|
|
|
|
+ // 每次弹幕的索引变化的时候
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ window.setTimeout(() => {
|
|
|
|
+ const width = barrMoveRef.current?.offsetWidth || 0;
|
|
|
|
+
|
|
|
|
+ if (barrMoveRef.current) {
|
|
|
|
+ if (barrMoveRef.current) {
|
|
|
|
+ barrMoveRef.current.style.right = -width - 200 + "px";
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const endNum = -window.innerWidth - width - 200;
|
|
|
|
+ barrMoveRefKill.current?.kill();
|
|
|
|
+ // 开始动画
|
|
|
|
+ barrMoveRefKill.current = gsap.fromTo(
|
|
|
|
+ barrMoveRef.current,
|
|
|
|
+ { x: 0 },
|
|
|
|
+ {
|
|
|
|
+ duration: 16,
|
|
|
|
+ ease: "none",
|
|
|
|
+ x: endNum,
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ }, 200);
|
|
|
|
+ }, [barrInd]);
|
|
|
|
+
|
|
|
|
+ // 通过id获取详情
|
|
|
|
+ const getDataFu = useCallback(
|
|
|
|
+ async (id: number) => {
|
|
|
|
+ const res = await A2_APIgetGoodsInfo(id);
|
|
|
|
+ if (res.code === 0) {
|
|
|
|
+ const info: A2GoodsType = res.data.entity;
|
|
|
|
+
|
|
|
|
+ // 留言板 和 弹幕开关 是否显示
|
|
|
|
+ const res_b = await A2_APIgetConfigBarrage();
|
|
|
|
+ if (res_b.code === 0) {
|
|
|
|
+ const value_b = JSON.parse(res_b.data.content);
|
|
|
|
+ if (value_b.value) {
|
|
|
|
+ // 获取所有的弹幕数组
|
|
|
|
+ const resBa_all = await A2_APIgetBarrageAll();
|
|
|
|
+ if (resBa_all.code === 0) {
|
|
|
|
+ setBarrageAll(resBa_all.data);
|
|
|
|
+ }
|
|
|
|
+ //打开了弹幕总开关 并且所有弹幕的数组长度>0
|
|
|
|
+ if (resBa_all.data.length) {
|
|
|
|
+ // 显示弹幕开关
|
|
|
|
+ setRight3({ show: true, done: true });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 文物的弹幕留言开关 和总 弹幕开关都开启了
|
|
|
|
+ if (info.isBarrage) setRight2({ show: true, done: false });
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const file: A2FileType[] = res.data.file;
|
|
|
|
+
|
|
|
|
+ // 附件按照 模型-视频-图片的顺序
|
|
|
|
+ let modelObj = {} as A2FileType;
|
|
|
|
+ let videoObj = {} as A2FileType;
|
|
|
|
+ const imgArr: A2FileType[] = [];
|
|
|
|
+ file.forEach((v) => {
|
|
|
|
+ if (v.type === "model") modelObj = v;
|
|
|
|
+ else if (v.type === "video") videoObj = v;
|
|
|
|
+ else if (v.type === "img") imgArr.push(v);
|
|
|
|
+ });
|
|
|
|
+ let fileListTemp: A2FileType[] = [];
|
|
|
|
+ if (modelObj.id) fileListTemp.push(modelObj);
|
|
|
|
+ if (videoObj.id) fileListTemp.push(videoObj);
|
|
|
|
+
|
|
|
|
+ fileListTemp = [...fileListTemp, ...imgArr];
|
|
|
|
+ setFileList(fileListTemp);
|
|
|
|
+
|
|
|
|
+ // 有上传音频
|
|
|
|
+ const isAudioObj = file.find((v) => v.type === "audio");
|
|
|
|
+ if (isAudioObj) {
|
|
|
|
+ setAudio(isAudioObj.filePath);
|
|
|
|
+ setRight1({ show: true, done: false });
|
|
|
|
+ window.setTimeout(() => {
|
|
|
|
+ const dom: HTMLAudioElement = document.querySelector("#myAudio")!;
|
|
|
|
+ dom.onended = () => {
|
|
|
|
+ // console.log("-------音频播放结束");
|
|
|
|
+
|
|
|
|
+ // 音频播放结束
|
|
|
|
+ setRight1({ show: true, done: false });
|
|
|
|
+ };
|
|
|
|
+ // 音频的状态
|
|
|
|
+ if (!isOpen) {
|
|
|
|
+ dom.play();
|
|
|
|
+
|
|
|
|
+ setRight1({ show: true, done: true });
|
|
|
|
+ }
|
|
|
|
+ }, 100);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ setInfo(info);
|
|
|
|
+
|
|
|
|
+ // 看看是否有相关的问答
|
|
|
|
+ const res2 = await A2_APIgetQuestion(id);
|
|
|
|
+ if (res2.code === 0) {
|
|
|
|
+ // 如有有选择 知识驿站
|
|
|
|
+ if (info.tagType) leftArrTemp[1].done = true;
|
|
|
|
+ // 如果有问答
|
|
|
|
+ if (res2.data.length) leftArrTemp[2].done = true;
|
|
|
|
+ const res3 = await A2_APIgetBarrage(id);
|
|
|
|
+ setQuestion(res2.data);
|
|
|
|
+ if (res3.code === 0) {
|
|
|
|
+ // 如果这条文物有留言
|
|
|
|
+ if (res3.data.length) leftArrTemp[3].done = true;
|
|
|
|
+ setBarrage(res3.data);
|
|
|
|
+ setLeftArr(leftArrTemp.filter((v) => v.done));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ [isOpen, leftArrTemp]
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ getDataFu(id);
|
|
|
|
+ return () => {
|
|
|
|
+ clearInterval(barrTimeRef.current);
|
|
|
|
+ barrMoveRefKill.current?.kill();
|
|
|
|
+ };
|
|
|
|
+ }, [getDataFu, id]);
|
|
|
|
+
|
|
|
|
+ // 点击关闭按钮
|
|
|
|
+ const closeFu = useCallback(() => {
|
|
|
|
+ // 新页面打开回到首页
|
|
|
|
+ if (isOpen) history.push("/");
|
|
|
|
+ else closePage!();
|
|
|
|
+ }, [closePage, isOpen]);
|
|
|
|
+
|
|
|
|
+ return (
|
|
|
|
+ <div className={styles.GoodsInfo}>
|
|
|
|
+ {audio ? <audio src={baseURL + audio} id="myAudio"></audio> : null}
|
|
|
|
+
|
|
|
|
+ {/* 关闭按钮 */}
|
|
|
|
+ <div className={classNames("G_close", isOpen ? "G_closeLL" : "")}>
|
|
|
|
+ <img
|
|
|
|
+ onClick={() => closeFu()}
|
|
|
|
+ src={isOpen ? homeImg : closeImg}
|
|
|
|
+ alt=""
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <div className="G_Main">
|
|
|
|
+ {/* 标题 */}
|
|
|
|
+ <div className="G_title">{info.name ? info.name : "-"}</div>
|
|
|
|
+
|
|
|
|
+ <div className="G_con">
|
|
|
|
+ {/* 左侧容器 */}
|
|
|
|
+ <div className="G_leftMain">
|
|
|
|
+ {/* 简介 */}
|
|
|
|
+ <div className="G_left1" hidden={leftAc !== 1}>
|
|
|
|
+ <div className="G_left1Row">
|
|
|
|
+ <div className="G_left1Row_la">类别:</div>
|
|
|
|
+ <div className="G_left1Row_txt">{info.dictTexture}</div>
|
|
|
|
+ </div>
|
|
|
|
+ <div className="G_left1Row">
|
|
|
|
+ <div className="G_left1Row_la">年代:</div>
|
|
|
|
+ <div className="G_left1Row_txt">{info.dictAge}</div>
|
|
|
|
+ </div>
|
|
|
|
+ <div className="G_left1Row">
|
|
|
|
+ <div className="G_left1Row_la">级别:</div>
|
|
|
|
+ <div className="G_left1Row_txt">{info.dictLevel}</div>
|
|
|
|
+ </div>
|
|
|
|
+ <div className="G_left1Row">
|
|
|
|
+ <div className="G_left1Row_la">简介:</div>
|
|
|
|
+ <div className="G_left1Row_txt">
|
|
|
|
+ {info.description ? info.description : "(空)"}
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ {/* 知识 */}
|
|
|
|
+ {leftAc === 2 ? (
|
|
|
|
+ <Left2 type={info.tagType} />
|
|
|
|
+ ) : leftAc === 3 ? (
|
|
|
|
+ <Left3 list={question} />
|
|
|
|
+ ) : leftAc === 4 ? (
|
|
|
|
+ <Left4 list={barrage} />
|
|
|
|
+ ) : null}
|
|
|
|
+ </div>
|
|
|
|
+ {/* 右侧容器 */}
|
|
|
|
+ <div className="G_rightMain">
|
|
|
|
+ <RightFile list={fileList} />
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ {/* 底部容器 */}
|
|
|
|
+ <div className="G_bottom">
|
|
|
|
+ <div className="G_bottom_left">
|
|
|
|
+ {leftArr.map((v, i) => (
|
|
|
|
+ <div className="G_bottom_left_row" key={v.id}>
|
|
|
|
+ <div
|
|
|
|
+ onClick={() => setLeftAc(v.id)}
|
|
|
|
+ className={classNames(
|
|
|
|
+ "G_bottom_left_row_1",
|
|
|
|
+ leftAc === v.id ? "G_bottom_left_row_1Ac" : ""
|
|
|
|
+ )}
|
|
|
|
+ >
|
|
|
|
+ <span>{v.name}</span>
|
|
|
|
+ </div>
|
|
|
|
+ <div
|
|
|
|
+ className="G_bottom_left_row_2"
|
|
|
|
+ hidden={i === leftArr.length - 1}
|
|
|
|
+ ></div>
|
|
|
|
+ </div>
|
|
|
|
+ ))}
|
|
|
|
+ </div>
|
|
|
|
+ <div className="G_bottom_right">
|
|
|
|
+ <div className="G_bottom_right_main">
|
|
|
|
+ {/* 音频 */}
|
|
|
|
+ <div className="R_row" hidden={!right1.show}>
|
|
|
|
+ <img
|
|
|
|
+ src={icon1Ac}
|
|
|
|
+ alt=""
|
|
|
|
+ title="打开音频"
|
|
|
|
+ hidden={right1.done}
|
|
|
|
+ onClick={() => audioCutFu(true)}
|
|
|
|
+ />
|
|
|
|
+ <img
|
|
|
|
+ onClick={() => audioCutFu(false)}
|
|
|
|
+ src={icon1}
|
|
|
|
+ alt=""
|
|
|
|
+ title="关闭音频"
|
|
|
|
+ hidden={!right1.done}
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+ {/* 弹幕留言 */}
|
|
|
|
+ <div
|
|
|
|
+ className="R_row"
|
|
|
|
+ hidden={!right2.show}
|
|
|
|
+ onClick={() => setRight2({ show: true, done: true })}
|
|
|
|
+ >
|
|
|
|
+ <img src={icon2} alt="" title="打开留言板" />
|
|
|
|
+ </div>
|
|
|
|
+ {/* 弹幕开关 */}
|
|
|
|
+ <div className="R_row" hidden={!right3.show}>
|
|
|
|
+ <img
|
|
|
|
+ src={icon3Ac}
|
|
|
|
+ alt=""
|
|
|
|
+ title="打开弹幕"
|
|
|
|
+ hidden={right3.done}
|
|
|
|
+ onClick={() => setRight3({ show: true, done: true })}
|
|
|
|
+ />
|
|
|
|
+ <img
|
|
|
|
+ src={icon3}
|
|
|
|
+ alt=""
|
|
|
|
+ title="关闭弹幕"
|
|
|
|
+ hidden={!right3.done}
|
|
|
|
+ onClick={() => setRight3({ show: true, done: false })}
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+ {/* 点赞 */}
|
|
|
|
+ <div className="R_row">
|
|
|
|
+ <img
|
|
|
|
+ title="点赞"
|
|
|
|
+ src={right4 ? icon4Ac : icon4}
|
|
|
|
+ alt=""
|
|
|
|
+ onClick={() => likeClickFu()}
|
|
|
|
+ />
|
|
|
|
+ <div className="moveImg" hidden={!right4}>
|
|
|
|
+ <img src={icon4Ac} alt="" />
|
|
|
|
+ +1
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ {/* 分享 */}
|
|
|
|
+ <div className="R_row">
|
|
|
|
+ <img
|
|
|
|
+ title="分享"
|
|
|
|
+ src={right5 ? icon5Ac : icon5}
|
|
|
|
+ alt=""
|
|
|
|
+ onClick={() => fenXClickFu()}
|
|
|
|
+ />
|
|
|
|
+ <img
|
|
|
|
+ className="moveImg"
|
|
|
|
+ src={icon5Ac}
|
|
|
|
+ alt=""
|
|
|
|
+ hidden={!right5}
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ {/* 弹幕的盒子 */}
|
|
|
|
+ {barrageAll.length ? (
|
|
|
|
+ <div className="barrMove" ref={barrMoveRef} hidden={!right3.done}>
|
|
|
|
+ <h3>{barrageAll[barrInd].name}</h3>
|
|
|
|
+ <p>
|
|
|
|
+ {barrageAll[barrInd].authorName}
|
|
|
|
+ {barrageAll[barrInd].updateTime}
|
|
|
|
+ 观 [{barrageAll[barrInd].goodsName}] 有感
|
|
|
|
+ </p>
|
|
|
|
+ </div>
|
|
|
|
+ ) : null}
|
|
|
|
+
|
|
|
|
+ {/* 留言板 */}
|
|
|
|
+ <div
|
|
|
|
+ className={classNames("R_formBox", right2.done ? "R_formBoxAc" : "")}
|
|
|
|
+ >
|
|
|
|
+ {right2.done ? (
|
|
|
|
+ <Rform
|
|
|
|
+ goodsId={id}
|
|
|
|
+ closeFu={() => setRight2({ show: true, done: false })}
|
|
|
|
+ />
|
|
|
|
+ ) : null}
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const MemoGoodsInfo = React.memo(GoodsInfo);
|
|
|
|
+
|
|
|
|
+export default MemoGoodsInfo;
|