Commit bda229309dd1a6e8575f97c24dfa1f3cbece4b80
1 parent
f40a6f53
feat: 生产线详情-预览功能:pdt(单个与批量)+回退自定义方法
Showing
9 changed files
with
74 additions
and
41 deletions
@@ -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 |
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; |
src/components/video-play.tsx
renamed from
src/components/videoPlay.tsx
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 |