123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543 |
- /* eslint-disable jsx-a11y/iframe-has-title */
- import React, {
- useCallback,
- useEffect,
- useMemo,
- useRef,
- useState,
- } from "react";
- import styles from "./index.module.scss";
- import toBackImg from "@/assets/img/goods/toBack.png";
- import { envUrl } from "@/utils/env";
- import {
- A2BarrageType,
- A2FileObjType,
- A2FileType,
- A2GoodsType,
- A2QuestionType,
- } from "@/types";
- import {
- A2_APIgetBarrage,
- A2_APIgetBarrageAll,
- A2_APIgetConfigBarrage,
- A2_APIgetGoodsInfo,
- A2_APIgetQuestion,
- A2_APIgoodsaddStar,
- } from "@/store/action/A2Main";
- import { MessageFu } from "@/utils/message";
- import classNames from "classnames";
- import { baseURL } from "@/utils/http";
- import ImageLazy from "@/components/ImageLazy";
- import R_leftImg from "@/assets/img/goods/R_left.png";
- import R_rightImg from "@/assets/img/goods/R_right.png";
- import { gsap } from "gsap";
- import Tab4Msg from "../Tab4Msg";
- import Tab4S3 from "../Tab4S3";
- type Props = {
- isOpen: boolean;
- id: number;
- closePage?: () => void;
- };
- function Tab4Info({ isOpen, id, closePage }: Props) {
- // 文物信息
- const [info, setInfo] = useState<A2GoodsType>({} as A2GoodsType);
- // 附件数据(除开音频)
- const [fileList, setFileList] = useState<A2FileObjType>({
- model: [],
- video: [],
- img: [],
- });
- // ---------------右侧图标
- // 音频
- const [right1, setRight1] = useState({ show: false, url: "" });
- const audioUrlRef = useRef("");
- // 留言板(默认显示),传递 到二级页面 看看是否开启了 留言到后端的 功能
- const [right2, setRight2] = useState(false);
- //问答
- const [right3, setRight3] = useState(false);
- // 知识
- const [right4, setRight4] = useState(false);
- // 弹幕
- const [right5, setRight5] = useState({ show: false, done: false });
- // 点赞
- const [right6, setRight6] = useState(false);
- // 分享
- const [right7, setRight7] = useState(false);
- // 点击点赞
- const likeClickFu = useCallback(async () => {
- if (right6) return;
- setRight6(true);
- try {
- await A2_APIgoodsaddStar(id);
- } catch (error) {
- console.log(error);
- }
- window.setTimeout(() => {
- setRight6(false);
- }, 3000);
- }, [id, right6]);
- // 点击分享链接
- const fenXClickFu = useCallback(() => {
- if (right7) return;
- setRight7(true);
- window.setTimeout(() => {
- setRight7(false);
- }, 3000);
- let OrderNumber = window.location.origin + "/pc/#/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, right7]);
- // 留言-知识-问答 弹窗的选中状态(打开)
- const [rightPageAc, setRightPageAc] = useState<0 | 2 | 3 | 4>(0);
- // 问答数组
- 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 barrMoveRefKill = useRef<any>(null);
- // 每次弹幕的索引变化的时候
- useEffect(() => {
- window.setTimeout(() => {
- const width = barrMoveRef.current?.offsetWidth || 0;
- if (barrMoveRef.current) {
- barrMoveRef.current.style.right = -width - 200 + "px";
- const endNum = -window.innerWidth - width - 200;
- barrMoveRefKill.current?.kill();
- // 开始动画
- // 总弹幕数量只有 1 的情况
- if (barrageAll.length === 1) {
- barrMoveRefKill.current = gsap.to(barrMoveRef.current, {
- duration: 16,
- ease: "none",
- x: endNum,
- repeat: -1,
- });
- } else if (barrageAll.length > 1) {
- // 有超过 1 的情况
- barrMoveRefKill.current = gsap.fromTo(
- barrMoveRef.current,
- { x: 0 },
- {
- duration: 16,
- ease: "none",
- x: endNum,
- onComplete: () => {
- let num = barrInd + 1;
- if (num >= barrageAll.length) num = 0;
- setBarrInd(num);
- },
- }
- );
- }
- }
- }, 200);
- }, [barrInd, barrageAll.length]);
- // 通过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) {
- // 显示弹幕开关
- setRight5({ show: true, done: true });
- }
- // 文物的弹幕留言开关 和总 弹幕开关都开启了(可以在二级页面发送接口留言)
- if (info.isBarrage) setRight2(true);
- }
- }
- const file: A2FileType[] = res.data.file;
- // 整理附件数据
- const fileObj: A2FileObjType = {
- model: [],
- video: [],
- img: [],
- };
- file.forEach((v) => {
- if (v.type === "model") fileObj.model.push(v);
- else if (v.type === "video") fileObj.video.push(v);
- else if (v.type === "img") fileObj.img.push(v);
- });
- setFileList(fileObj);
- // 有上传音频
- const isAudioObj = file.find((v) => v.type === "audio");
- if (isAudioObj) {
- setRight1({ show: !isOpen, url: isAudioObj.filePath });
- audioUrlRef.current = isAudioObj.filePath;
- }
- setInfo(info);
- // 看看是否有相关的问答
- const res2 = await A2_APIgetQuestion(id);
- if (res2.code === 0) {
- // 如有有选择 知识驿站
- if (info.tagType) setRight4(true);
- // 如果有问答
- if (res2.data.length) setRight3(true);
- const res3 = await A2_APIgetBarrage(id);
- setQuestion(res2.data);
- if (res3.code === 0) {
- // 如果这条文物有留言
- // if (res3.data.length) setRight2;
- setBarrage(res3.data);
- }
- }
- }
- },
- [isOpen]
- );
- // 有关音频
- useEffect(() => {
- if (right1.url) {
- // 如果是从 文物 详情 进来---直接播放音频
- window.setTimeout(() => {
- const dom: HTMLAudioElement | null = document.querySelector("#myAudio");
- if (dom) {
- dom.onended = () => {
- // console.log("-------音频播放结束");
- setRight1({ show: false, url: audioUrlRef.current });
- };
- // 音频的状态
- if (!isOpen) dom.play();
- }
- }, 100);
- }
- }, [isOpen, right1.url]);
- // 打开和关闭音频
- const audioCutFu = useCallback((val: boolean) => {
- const dom: HTMLAudioElement | null = document.querySelector("#myAudio");
- if (dom) {
- if (!val) dom.play();
- else dom.pause();
- setRight1({ show: !val, url: audioUrlRef.current });
- }
- }, []);
- useEffect(() => {
- getDataFu(id);
- return () => {
- barrMoveRefKill.current?.kill();
- };
- }, [getDataFu, id]);
- // 文件类型 type
- const [type, setType] = useState<"model" | "video" | "img">("model");
- // 每次变化type的时候把 索引变成0
- useEffect(() => {
- setShowInd(0);
- }, [type]);
- // 切换不同文件(模型/视频/图片的数组)
- const typeArr = useMemo(() => {
- const arr: {
- name: "模型" | "视频" | "图片";
- type: "model" | "video" | "img";
- }[] = [];
- if (fileList.model.length) arr.push({ name: "模型", type: "model" });
- if (fileList.video.length) arr.push({ name: "视频", type: "video" });
- if (fileList.img.length) arr.push({ name: "图片", type: "img" });
- return arr;
- }, [fileList]);
- // 当前默认展示什么模块(优先级按照 模型-视频-图片)
- useEffect(() => {
- if (fileList.model.length) setType("model");
- else if (fileList.video.length) setType("video");
- else setType("img");
- }, [fileList]);
- // 在页面展示的数组
- const list = useMemo(() => {
- return fileList[type];
- }, [fileList, type]);
- // 当前显示的 索引
- const [showInd, setShowInd] = useState(0);
- const cutIndFu = useCallback(
- (num: number) => {
- setShowInd(showInd + num);
- },
- [showInd]
- );
- return (
- <div
- className={styles.Tab4Info}
- style={{ backgroundImage: `url(${envUrl}/goods/bac.jpg)` }}
- >
- {/* 音频控件 */}
- {right1.url ? (
- <audio hidden src={baseURL + right1.url} controls id="myAudio"></audio>
- ) : null}
- {/* 返回按钮 */}
- <div className="t4ItoBack" onClick={closePage}>
- <img src={toBackImg} alt="" />
- </div>
- {/* 顶部名称 */}
- <div className="topName">{info.name}</div>
- {/* 顶部tab */}
- <div className="R_typeCutBox" hidden={typeArr.length <= 1}>
- {typeArr.map((v) => (
- <div
- onClick={() => setType(v.type)}
- className={classNames(
- "R_typeCutRow",
- type === v.type ? "R_typeCutRowAc" : ""
- )}
- key={v.type}
- >
- {v.name}
- {fileList[v.type].length > 1 ? fileList[v.type].length : null}
- </div>
- ))}
- </div>
- {/* 主体模型 */}
- {fileList.model && fileList.model[0] && fileList.model[0].id ? (
- <div className="t4IifrBox" hidden={type !== "model"}>
- <iframe
- src={`model.html?m=${fileList.model[0].filePath}`}
- frameBorder="0"
- ></iframe>
- </div>
- ) : null}
- {/* 主体 其他附件 */}
- <div className="t4IFileBox">
- {list.map((v, i) => (
- <div
- className={classNames("R1_row", i === showInd ? "R1_rowAc" : "")}
- key={v.id}
- >
- {v.type === "video" && i === showInd ? (
- <video src={baseURL + v.filePath} controls></video>
- ) : v.type === "img" ? (
- <ImageLazy src={v.filePath} width="100%" height="100%" />
- ) : null}
- </div>
- ))}
- {/* 索引 */}
- {list.length > 1 ? (
- <div className="showIndBox">
- {showInd + 1} / {list.length}
- </div>
- ) : null}
- </div>
- {/* 左右按钮 */}
- <div
- hidden={list.length <= 1}
- onClick={() => cutIndFu(-1)}
- className={classNames("R_left", showInd === 0 ? "R_arrowNo" : "")}
- >
- <img src={R_leftImg} alt="" />
- </div>
- <div
- hidden={list.length <= 1}
- onClick={() => cutIndFu(1)}
- className={classNames(
- "R_right",
- showInd >= list.length - 1 ? "R_arrowNo" : ""
- )}
- >
- <img src={R_rightImg} alt="" />
- </div>
- {/* 底部文字介绍集合 */}
- <div className="t4ITxts myscroll">
- {info.dictTexture ? (
- <>
- <span>类别:</span>
- {info.dictTexture} 
- </>
- ) : null}
- {info.dictAge ? (
- <>
- <span>年代:</span>
- {info.dictAge} 
- </>
- ) : null}
- {info.dictLevel ? (
- <>
- <span>级别:</span>
- {info.dictLevel} 
- </>
- ) : null}
- {info.description ? (
- <>
- <span>简介:</span>
- {info.description} 
- </>
- ) : null}
- </div>
- {/* 右侧所有按钮图标 */}
- <div className="rightIconBox">
- {/* 音频 */}
- {right1.url ? (
- <div
- className="rightIconRow"
- onClick={() => audioCutFu(right1.show)}
- title={right1.show ? "关闭音频" : "打开音频"}
- >
- <img
- src={`${envUrl}/goods/icon1${right1.show ? "Ac" : ""}.png`}
- alt=""
- />
- </div>
- ) : null}
- {/* 留言板 */}
- <div
- hidden={barrage.length<=0}
- className="rightIconRow"
- onClick={() => setRightPageAc(2)}
- title="留言板"
- >
- <img src={`${envUrl}/goods/icon2.png`} alt="" />
- </div>
- {/* 问答 */}
- {right3 ? (
- <div
- className="rightIconRow"
- onClick={() => setRightPageAc(3)}
- title="问答"
- >
- <img src={`${envUrl}/goods/icon3.png`} alt="" />
- </div>
- ) : null}
- {/* 知识 */}
- {right4 ? (
- <div
- className="rightIconRow"
- onClick={() => setRightPageAc(4)}
- title="知识"
- >
- <img src={`${envUrl}/goods/icon4.png`} alt="" />
- </div>
- ) : null}
- {/* 弹幕 */}
- {right5.done ? (
- <div
- className="rightIconRow"
- title={right5.show ? "关闭弹幕" : "开启弹幕"}
- onClick={() => setRight5({ show: !right5.show, done: true })}
- >
- <img
- src={`${envUrl}/goods/icon5${right5.show ? "Ac" : ""}.png`}
- alt=""
- />
- </div>
- ) : null}
- {/* 点赞 */}
- <div
- className="rightIconRow"
- onClick={() => likeClickFu()}
- title="点赞"
- >
- <img src={`${envUrl}/goods/icon6${right6 ? "Ac" : ""}.png`} alt="" />
- <div className="moveImg" hidden={!right6}>
- +1
- </div>
- </div>
- {/* 分享 */}
- <div
- className="rightIconRow"
- onClick={() => fenXClickFu()}
- title="分享"
- >
- <img src={`${envUrl}/goods/icon7${right7 ? "Ac" : ""}.png`} alt="" />
- </div>
- </div>
- {/* 弹幕的盒子 */}
- {barrageAll.length ? (
- <div className="barrMove" ref={barrMoveRef} hidden={!right5.show}>
- <h3>{barrageAll[barrInd].name}</h3>
- <p>
- {barrageAll[barrInd].authorName}
- {barrageAll[barrInd].createTime}
- 观 [{barrageAll[barrInd].goodsName}] 有感
- </p>
- </div>
- ) : null}
- {/* 留言板 - 知识 - 问答 */}
- {rightPageAc === 2 ? (
- <Tab4Msg
- btnOkFlag={right2}
- barrageList={barrage}
- goodsId={id}
- closeFu={() => setRightPageAc(0)}
- />
- ) : rightPageAc === 3 ? (
- <Tab4S3 closeFu={() => setRightPageAc(0)} questionList={question}/>
- ) : null}
- </div>
- );
- }
- const MemoTab4Info = React.memo(Tab4Info);
- export default MemoTab4Info;
|