Commit bda229309dd1a6e8575f97c24dfa1f3cbece4b80
1 parent
f40a6f53
feat: 生产线详情-预览功能:pdt(单个与批量)+回退自定义方法
Showing
9 changed files
with
74 additions
and
41 deletions
... | ... | @@ -15,8 +15,8 @@ |
15 | 15 | "axios": "^1.7.9", |
16 | 16 | "react": "^18.3.1", |
17 | 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 | 21 | "devDependencies": { |
22 | 22 | "@eslint/js": "^9.17.0", |
... | ... | @@ -33,6 +33,7 @@ |
33 | 33 | "postcss-px-to-viewport": "^1.1.1", |
34 | 34 | "typescript": "~5.6.2", |
35 | 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 | } | ... | ... |
src/components/pdf-preview/index.less
0 → 100644
src/components/pdf-preview/index.tsx
0 → 100644
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; | |
\ No newline at end of file | ... | ... |
src/components/video-play.tsx
renamed from
src/components/videoPlay.tsx
1 | 1 | import React, {useEffect, useState} from 'react' |
2 | 2 | import './style.less' |
3 | 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 | 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 | 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 | 12 | const ProductionDetail: React.FC = () => { |
13 | + let navigate = useNavigate(); | |
14 | 14 | const [title, setTitle] = useState<string>(''); |
15 | 15 | const [filePathItem, setFilePathItem] = useState(); |
16 | 16 | // 自动预览 定时器 |
... | ... | @@ -23,8 +23,6 @@ const ProductionDetail: React.FC = () => { |
23 | 23 | |
24 | 24 | const sxPreViewList = localStorage.getItem('sxPreViewListStorage') ? JSON.parse(localStorage.getItem('sxPreViewListStorage')) : []; |
25 | 25 | |
26 | - console.log('sxPreViewList', sxPreViewList) | |
27 | - | |
28 | 26 | useEffect(() => { |
29 | 27 | if (sxPreViewList?.length) { |
30 | 28 | const _isLoop = sxPreViewList?.length > 1; |
... | ... | @@ -68,6 +66,9 @@ const ProductionDetail: React.FC = () => { |
68 | 66 | |
69 | 67 | useEffect(() => { |
70 | 68 | console.log('filePathItem', filePathItem) |
69 | + if (!_.isEmpty(filePathItem)) { | |
70 | + setTitle(filePathItem?.name) | |
71 | + } | |
71 | 72 | }, [filePathItem]) |
72 | 73 | |
73 | 74 | |
... | ... | @@ -75,7 +76,11 @@ const ProductionDetail: React.FC = () => { |
75 | 76 | return ( |
76 | 77 | <div className={'sxjx-content-main sxjx-layout-main-unfoot'}> |
77 | 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 | 85 | filePathItem?.type === 'mp4' ? <div className={'production-detail-video-box'}> |
81 | 86 | <VideoPlay |
... | ... | @@ -83,8 +88,7 @@ const ProductionDetail: React.FC = () => { |
83 | 88 | url={filePathItem?.url || ''} |
84 | 89 | className={'production-detail-video'} |
85 | 90 | /> |
86 | - </div> : <> | |
87 | - </> | |
91 | + </div> : filePathItem?.type === 'pdf' ? <PdfPreview url={filePathItem?.url}/> : '' | |
88 | 92 | } |
89 | 93 | </div> |
90 | 94 | </div> | ... | ... |
... | ... | @@ -8,8 +8,7 @@ import _preview from './preview.png'; |
8 | 8 | import {useSearchParams} from "react-router-dom"; |
9 | 9 | import {getFilePreview, getProductBook} from "@/api/apiConfig"; |
10 | 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 | 13 | interface ListType { |
15 | 14 | id: string; |
... | ... | @@ -26,21 +25,18 @@ const ProductionList: React.FC = () => { |
26 | 25 | const [show, setShow] = useState<boolean>(false); |
27 | 26 | const [showBatch, setShowBatch] = useState<boolean>(false); |
28 | 27 | const navigate = useNavigate(); |
28 | + const location = useLocation(); | |
29 | + console.log('location', location?.pathname, location?.search) | |
29 | 30 | const [checkItems, setCheckItems] = useState<CheckboxValue[]>([]) |
30 | 31 | const [checkValues, setCheckValues] = useState<CheckboxValue[]>([]) |
31 | - // const [sxPreViewList, setSxPreViewList] = useState<ListType[]>([]) | |
32 | 32 | |
33 | 33 | |
34 | 34 | // 因是hook,必须写在组件的顶部执行,useSearchParams() 返回的是数组 |
35 | 35 | const [params] = useSearchParams(); |
36 | - console.log('ProductionList===params', params) | |
37 | 36 | // 通过 get 方法获取目标参数 |
38 | 37 | const name = params.get("name") || ""; |
39 | 38 | const id = params.get("id") || ""; |
40 | 39 | |
41 | - useEffect(() => { | |
42 | - localStorage.setItem('sxPreViewListStorage', ''); | |
43 | - }, []) | |
44 | 40 | |
45 | 41 | useEffect(() => { |
46 | 42 | if (name) { |
... | ... | @@ -55,7 +51,7 @@ const ProductionList: React.FC = () => { |
55 | 51 | setShow(true); |
56 | 52 | let _checkItems = []; |
57 | 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 | 55 | const _arr = item?.guide_book_file_info_?.[0]?.name?.split('.') || []; |
60 | 56 | return { |
61 | 57 | id: item?.id || '', |
... | ... | @@ -83,7 +79,6 @@ const ProductionList: React.FC = () => { |
83 | 79 | ) |
84 | 80 | |
85 | 81 | const checkboxChange = (value: CheckboxValue[]) => { |
86 | - console.log('checkboxChange-value', value) | |
87 | 82 | setCheckValues(value) |
88 | 83 | } |
89 | 84 | |
... | ... | @@ -96,10 +91,8 @@ const ProductionList: React.FC = () => { |
96 | 91 | |
97 | 92 | |
98 | 93 | const toDetail = async (ids: CheckboxValue[]) => { |
99 | - console.log('toDetail-ids', ids) | |
100 | 94 | if (ids?.length) { |
101 | 95 | let _arr = list?.filter((item: ListType) => ids?.includes(item?.id || '')) || []; |
102 | - console.log('_arr', _arr) | |
103 | 96 | // 创建一个promise数组,每个promise都是对API的一次调用 |
104 | 97 | const promises = _arr?.map((item: ListType) => fetchData(item)); |
105 | 98 | // 使用Promise.all来并行地解决这些promise |
... | ... | @@ -111,16 +104,17 @@ const ProductionList: React.FC = () => { |
111 | 104 | url: results?.[index] |
112 | 105 | } |
113 | 106 | }) |
114 | - console.log('sxPreViewList', sxPreViewList) | |
115 | 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 | 111 | .catch(err => { |
119 | 112 | localStorage.setItem('sxPreViewListStorage', ''); |
120 | - console.log('err', err) | |
113 | + localStorage.setItem('sxListPath', ''); | |
121 | 114 | }); |
122 | 115 | } else { |
123 | 116 | localStorage.setItem('sxPreViewListStorage', ''); |
117 | + localStorage.setItem('sxListPath', ''); | |
124 | 118 | Toast.show({ |
125 | 119 | content: '请先选择数据!', |
126 | 120 | maskClassName: 'to-detail-mask', |
... | ... | @@ -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 | 126 | return ( |
142 | 127 | <div className={'sxjx-content-main sxjx-layout-main-unfoot'}> |
143 | 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 | 136 | !show ? <SpinLoading color='primary'/> : |
147 | 137 | <div className={'production-list_list'}> |
... | ... | @@ -184,6 +174,7 @@ const ProductionList: React.FC = () => { |
184 | 174 | indeterminate={checkValues.length > 0 && checkValues?.length < checkItems?.length} |
185 | 175 | checked={checkValues?.length === checkItems?.length} |
186 | 176 | onChange={checked => { |
177 | + console.log('checked', checked) | |
187 | 178 | if (checked) { |
188 | 179 | setCheckValues(checkItems) |
189 | 180 | } else { | ... | ... |