Commit bda229309dd1a6e8575f97c24dfa1f3cbece4b80

Authored by 史婷婷
1 parent f40a6f53

feat: 生产线详情-预览功能:pdt(单个与批量)+回退自定义方法

@@ -15,8 +15,8 @@ @@ -15,8 +15,8 @@
15 "axios": "^1.7.9", 15 "axios": "^1.7.9",
16 "react": "^18.3.1", 16 "react": "^18.3.1",
17 "react-dom": "^18.3.1", 17 "react-dom": "^18.3.1",
18 - "react-pdf": "^9.2.1",  
19 - "react-router-dom": "^7.1.1" 18 + "react-router-dom": "^7.1.1",
  19 + "lodash": "^4.17.11"
20 }, 20 },
21 "devDependencies": { 21 "devDependencies": {
22 "@eslint/js": "^9.17.0", 22 "@eslint/js": "^9.17.0",
@@ -33,6 +33,7 @@ @@ -33,6 +33,7 @@
33 "postcss-px-to-viewport": "^1.1.1", 33 "postcss-px-to-viewport": "^1.1.1",
34 "typescript": "~5.6.2", 34 "typescript": "~5.6.2",
35 "typescript-eslint": "^8.18.2", 35 "typescript-eslint": "^8.18.2",
36 - "vite": "^5.3.4" 36 + "vite": "^5.3.4",
  37 + "@types/lodash": "^4.17.7"
37 } 38 }
38 } 39 }
@@ -12,8 +12,8 @@ interface NavBarProps { @@ -12,8 +12,8 @@ interface NavBarProps {
12 backContent?: any; 12 backContent?: any;
13 hiddenHead?: boolean; 13 hiddenHead?: boolean;
14 customBack?: { 14 customBack?: {
15 - icon: any;  
16 - onClick: () => void; 15 + icon?: any;
  16 + onClick?: () => void;
17 }; 17 };
18 } 18 }
19 19
  1 +.pdfPreview {
  2 + width: 100%;
  3 + height: 100%;
  4 +}
  5 +
  1 +import { useEffect, useState } from 'react';
  2 +import './index.less';
  3 +
  4 +interface pdfPreviewProps {
  5 + url: string
  6 +}
  7 +
  8 +const pdfPreview = (props: pdfPreviewProps) => {
  9 + const [filePath, setFilePath] = useState<string>();
  10 +
  11 + useEffect(()=>{
  12 + if (props.url) {
  13 + setFilePath(props.url);
  14 + }
  15 + },[props.url])
  16 +
  17 +
  18 + return (
  19 + <div className={'pdfPreview'}>
  20 + {/* pdf属性 page 跳转到指定页码,navpanes 控制左侧的缩略图预览导航是否默认打开。0-关闭,1-打开*/}
  21 + {/* navpanes=0&scrollbars=0&toolbar=0&statusbar=0 去除缩略图和工具栏 */}
  22 + {/* frameborder=0 和view=FitH,top 为全屏展示 */}
  23 + <iframe
  24 + title="pdf-preview"
  25 + style={{ width: '100%', height: '100%' }}
  26 + frameborder="0"
  27 + src={`${filePath}#page=1&navpanes=0&scrollbars=0&toolbar=0&statusbar=0&view=FitH,top`}
  28 + // src={`${filePath}`}
  29 + />
  30 + </div>
  31 + );
  32 +};
  33 +
  34 +export default pdfPreview;
src/components/video-play.tsx renamed from src/components/videoPlay.tsx
@@ -25,7 +25,6 @@ a:hover { @@ -25,7 +25,6 @@ a:hover {
25 body { 25 body {
26 margin: 0; 26 margin: 0;
27 min-height: 100vh; 27 min-height: 100vh;
28 - background: pink;  
29 } 28 }
30 29
31 h1 { 30 h1 {
1 import React, {useEffect, useState} from 'react' 1 import React, {useEffect, useState} from 'react'
2 import './style.less' 2 import './style.less'
3 import NavBar from '@/components/nav-bar' 3 import NavBar from '@/components/nav-bar'
4 -import VideoPlay from '@/components/videoPlay' 4 +import VideoPlay from '@/components/video-play'
  5 +import PdfPreview from '@/components/pdf-preview'
5 import {useSearchParams} from "react-router-dom"; 6 import {useSearchParams} from "react-router-dom";
6 -import { Document, Page, pdfjs } from "react-pdf";  
7 -import 'react-pdf/dist/esm/Page/AnnotationLayer.css'  
8 -import 'react-pdf/dist/esm/Page/TextLayer.css';  
9 import {getCarouselSettings} from "@/api/apiConfig"; 7 import {getCarouselSettings} from "@/api/apiConfig";
10 -pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`; 8 +import _ from 'lodash';
  9 +import { useNavigate } from 'react-router-dom';
11 10
12 11
13 const ProductionDetail: React.FC = () => { 12 const ProductionDetail: React.FC = () => {
  13 + let navigate = useNavigate();
14 const [title, setTitle] = useState<string>(''); 14 const [title, setTitle] = useState<string>('');
15 const [filePathItem, setFilePathItem] = useState(); 15 const [filePathItem, setFilePathItem] = useState();
16 // 自动预览 定时器 16 // 自动预览 定时器
@@ -23,8 +23,6 @@ const ProductionDetail: React.FC = () => { @@ -23,8 +23,6 @@ const ProductionDetail: React.FC = () => {
23 23
24 const sxPreViewList = localStorage.getItem('sxPreViewListStorage') ? JSON.parse(localStorage.getItem('sxPreViewListStorage')) : []; 24 const sxPreViewList = localStorage.getItem('sxPreViewListStorage') ? JSON.parse(localStorage.getItem('sxPreViewListStorage')) : [];
25 25
26 - console.log('sxPreViewList', sxPreViewList)  
27 -  
28 useEffect(() => { 26 useEffect(() => {
29 if (sxPreViewList?.length) { 27 if (sxPreViewList?.length) {
30 const _isLoop = sxPreViewList?.length > 1; 28 const _isLoop = sxPreViewList?.length > 1;
@@ -68,6 +66,9 @@ const ProductionDetail: React.FC = () => { @@ -68,6 +66,9 @@ const ProductionDetail: React.FC = () => {
68 66
69 useEffect(() => { 67 useEffect(() => {
70 console.log('filePathItem', filePathItem) 68 console.log('filePathItem', filePathItem)
  69 + if (!_.isEmpty(filePathItem)) {
  70 + setTitle(filePathItem?.name)
  71 + }
71 }, [filePathItem]) 72 }, [filePathItem])
72 73
73 74
@@ -75,7 +76,11 @@ const ProductionDetail: React.FC = () => { @@ -75,7 +76,11 @@ const ProductionDetail: React.FC = () => {
75 return ( 76 return (
76 <div className={'sxjx-content-main sxjx-layout-main-unfoot'}> 77 <div className={'sxjx-content-main sxjx-layout-main-unfoot'}>
77 <div className={'production-detail'}> 78 <div className={'production-detail'}>
78 - <NavBar showBack={true} title={title}/> 79 + <NavBar showBack={true} title={title} customBack={{onClick: () => {
  80 + const _url = localStorage.getItem('sxListPath');
  81 + navigate(_url, { replace: true });
  82 + }}}
  83 + />
79 { 84 {
80 filePathItem?.type === 'mp4' ? <div className={'production-detail-video-box'}> 85 filePathItem?.type === 'mp4' ? <div className={'production-detail-video-box'}>
81 <VideoPlay 86 <VideoPlay
@@ -83,8 +88,7 @@ const ProductionDetail: React.FC = () => { @@ -83,8 +88,7 @@ const ProductionDetail: React.FC = () => {
83 url={filePathItem?.url || ''} 88 url={filePathItem?.url || ''}
84 className={'production-detail-video'} 89 className={'production-detail-video'}
85 /> 90 />
86 - </div> : <>  
87 - </> 91 + </div> : filePathItem?.type === 'pdf' ? <PdfPreview url={filePathItem?.url}/> : ''
88 } 92 }
89 </div> 93 </div>
90 </div> 94 </div>
@@ -8,8 +8,7 @@ import _preview from './preview.png'; @@ -8,8 +8,7 @@ import _preview from './preview.png';
8 import {useSearchParams} from "react-router-dom"; 8 import {useSearchParams} from "react-router-dom";
9 import {getFilePreview, getProductBook} from "@/api/apiConfig"; 9 import {getFilePreview, getProductBook} from "@/api/apiConfig";
10 import {SpinLoading, Checkbox, Toast} from 'antd-mobile' 10 import {SpinLoading, Checkbox, Toast} from 'antd-mobile'
11 -import { useNavigate } from "react-router-dom";  
12 -import {a} from "vite/dist/node/types.d-aGj9QkWt"; 11 +import { useNavigate, useLocation } from "react-router-dom";
13 12
14 interface ListType { 13 interface ListType {
15 id: string; 14 id: string;
@@ -26,21 +25,18 @@ const ProductionList: React.FC = () => { @@ -26,21 +25,18 @@ const ProductionList: React.FC = () => {
26 const [show, setShow] = useState<boolean>(false); 25 const [show, setShow] = useState<boolean>(false);
27 const [showBatch, setShowBatch] = useState<boolean>(false); 26 const [showBatch, setShowBatch] = useState<boolean>(false);
28 const navigate = useNavigate(); 27 const navigate = useNavigate();
  28 + const location = useLocation();
  29 + console.log('location', location?.pathname, location?.search)
29 const [checkItems, setCheckItems] = useState<CheckboxValue[]>([]) 30 const [checkItems, setCheckItems] = useState<CheckboxValue[]>([])
30 const [checkValues, setCheckValues] = useState<CheckboxValue[]>([]) 31 const [checkValues, setCheckValues] = useState<CheckboxValue[]>([])
31 - // const [sxPreViewList, setSxPreViewList] = useState<ListType[]>([])  
32 32
33 33
34 // 因是hook,必须写在组件的顶部执行,useSearchParams() 返回的是数组 34 // 因是hook,必须写在组件的顶部执行,useSearchParams() 返回的是数组
35 const [params] = useSearchParams(); 35 const [params] = useSearchParams();
36 - console.log('ProductionList===params', params)  
37 // 通过 get 方法获取目标参数 36 // 通过 get 方法获取目标参数
38 const name = params.get("name") || ""; 37 const name = params.get("name") || "";
39 const id = params.get("id") || ""; 38 const id = params.get("id") || "";
40 39
41 - useEffect(() => {  
42 - localStorage.setItem('sxPreViewListStorage', '');  
43 - }, [])  
44 40
45 useEffect(() => { 41 useEffect(() => {
46 if (name) { 42 if (name) {
@@ -55,7 +51,7 @@ const ProductionList: React.FC = () => { @@ -55,7 +51,7 @@ const ProductionList: React.FC = () => {
55 setShow(true); 51 setShow(true);
56 let _checkItems = []; 52 let _checkItems = [];
57 const _list = res?.product_book?.map((item: any) => { 53 const _list = res?.product_book?.map((item: any) => {
58 - _checkItems.push(item?.guide_book_file_info_?.[0]?.fileId); 54 + _checkItems.push(item?.id);
59 const _arr = item?.guide_book_file_info_?.[0]?.name?.split('.') || []; 55 const _arr = item?.guide_book_file_info_?.[0]?.name?.split('.') || [];
60 return { 56 return {
61 id: item?.id || '', 57 id: item?.id || '',
@@ -83,7 +79,6 @@ const ProductionList: React.FC = () => { @@ -83,7 +79,6 @@ const ProductionList: React.FC = () => {
83 ) 79 )
84 80
85 const checkboxChange = (value: CheckboxValue[]) => { 81 const checkboxChange = (value: CheckboxValue[]) => {
86 - console.log('checkboxChange-value', value)  
87 setCheckValues(value) 82 setCheckValues(value)
88 } 83 }
89 84
@@ -96,10 +91,8 @@ const ProductionList: React.FC = () => { @@ -96,10 +91,8 @@ const ProductionList: React.FC = () => {
96 91
97 92
98 const toDetail = async (ids: CheckboxValue[]) => { 93 const toDetail = async (ids: CheckboxValue[]) => {
99 - console.log('toDetail-ids', ids)  
100 if (ids?.length) { 94 if (ids?.length) {
101 let _arr = list?.filter((item: ListType) => ids?.includes(item?.id || '')) || []; 95 let _arr = list?.filter((item: ListType) => ids?.includes(item?.id || '')) || [];
102 - console.log('_arr', _arr)  
103 // 创建一个promise数组,每个promise都是对API的一次调用 96 // 创建一个promise数组,每个promise都是对API的一次调用
104 const promises = _arr?.map((item: ListType) => fetchData(item)); 97 const promises = _arr?.map((item: ListType) => fetchData(item));
105 // 使用Promise.all来并行地解决这些promise 98 // 使用Promise.all来并行地解决这些promise
@@ -111,16 +104,17 @@ const ProductionList: React.FC = () => { @@ -111,16 +104,17 @@ const ProductionList: React.FC = () => {
111 url: results?.[index] 104 url: results?.[index]
112 } 105 }
113 }) 106 })
114 - console.log('sxPreViewList', sxPreViewList)  
115 localStorage.setItem('sxPreViewListStorage', JSON.stringify(sxPreViewList)); 107 localStorage.setItem('sxPreViewListStorage', JSON.stringify(sxPreViewList));
116 - navigate(`/production/detail?name=${sxPreViewList?.[0]?.name}`); 108 + localStorage.setItem('sxListPath', `${location?.pathname}${location?.search}`);
  109 + navigate(`/production/detail?name=${sxPreViewList?.[0]?.name}`, { replace: true });
117 }) 110 })
118 .catch(err => { 111 .catch(err => {
119 localStorage.setItem('sxPreViewListStorage', ''); 112 localStorage.setItem('sxPreViewListStorage', '');
120 - console.log('err', err) 113 + localStorage.setItem('sxListPath', '');
121 }); 114 });
122 } else { 115 } else {
123 localStorage.setItem('sxPreViewListStorage', ''); 116 localStorage.setItem('sxPreViewListStorage', '');
  117 + localStorage.setItem('sxListPath', '');
124 Toast.show({ 118 Toast.show({
125 content: '请先选择数据!', 119 content: '请先选择数据!',
126 maskClassName: 'to-detail-mask', 120 maskClassName: 'to-detail-mask',
@@ -129,19 +123,15 @@ const ProductionList: React.FC = () => { @@ -129,19 +123,15 @@ const ProductionList: React.FC = () => {
129 123
130 } 124 }
131 125
132 - // useEffect(() => {  
133 - // console.log('sxPreViewList', sxPreViewList)  
134 - // if (sxPreViewList?.length) {  
135 - // const _name = sxPreViewList?.[0]?.name;  
136 - // console.log('_name', _name)  
137 - // navigate(`/production/detail?name=${_name}`);  
138 - // }  
139 - // }, [sxPreViewList])  
140 -  
141 return ( 126 return (
142 <div className={'sxjx-content-main sxjx-layout-main-unfoot'}> 127 <div className={'sxjx-content-main sxjx-layout-main-unfoot'}>
143 <div className={`production-list ${showBatch ? 'production-list--batch' : ''}`}> 128 <div className={`production-list ${showBatch ? 'production-list--batch' : ''}`}>
144 - <NavBar title={title} showBack={true} rightInfo={ !showBatch ? rightInfo : ''}/> 129 + <NavBar title={title} showBack={true} rightInfo={ !showBatch ? rightInfo : ''}
  130 + customBack={{onClick: () => {
  131 + const _url = '/production/management';
  132 + navigate(_url, { replace: true });
  133 + }}}
  134 + />
145 { 135 {
146 !show ? <SpinLoading color='primary'/> : 136 !show ? <SpinLoading color='primary'/> :
147 <div className={'production-list_list'}> 137 <div className={'production-list_list'}>
@@ -184,6 +174,7 @@ const ProductionList: React.FC = () => { @@ -184,6 +174,7 @@ const ProductionList: React.FC = () => {
184 indeterminate={checkValues.length > 0 && checkValues?.length < checkItems?.length} 174 indeterminate={checkValues.length > 0 && checkValues?.length < checkItems?.length}
185 checked={checkValues?.length === checkItems?.length} 175 checked={checkValues?.length === checkItems?.length}
186 onChange={checked => { 176 onChange={checked => {
  177 + console.log('checked', checked)
187 if (checked) { 178 if (checked) {
188 setCheckValues(checkItems) 179 setCheckValues(checkItems)
189 } else { 180 } else {
@@ -36,7 +36,6 @@ const ProductionManagement: React.FC = () => { @@ -36,7 +36,6 @@ const ProductionManagement: React.FC = () => {
36 }, []) 36 }, [])
37 37
38 const toProductionList = (item: any) => { 38 const toProductionList = (item: any) => {
39 - console.log('toProductionList-item', item)  
40 navigate(`/production/list?id=${item?.id}&name=${item?.name}`); 39 navigate(`/production/list?id=${item?.id}&name=${item?.name}`);
41 } 40 }
42 41