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 { | ... | ... |