Просмотр исходного кода

增加模型预览功能 fbx? glb

shaogen1995 недель назад: 2
Родитель
Сommit
e54ebe1c57

+ 1 - 1
public/index.html

@@ -16,7 +16,7 @@
 
       // const baseUrlTempOne = 'https://ywgcxt.yw.gov.cn:8887'
       // 测试域名地址
-      // const baseUrlTempOne = 'https://sit-yiwubwg.4dage.com'
+      // const baseUrlTempOne = 'https://sit-y5bwg.4dage.com'
       // const baseUrlTempOne = 'http://192.168.20.61:8096'
 
       // 钉钉模式

Разница между файлами не показана из-за своего большого размера
+ 3797 - 0
public/modelLook/assets/index-P16QZIgH.js


+ 25 - 0
public/modelLook/index.html

@@ -0,0 +1,25 @@
+<!doctype html>
+<html lang="zh-CN">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <meta name="color-scheme" content="light" />
+    <title>GLB 加载演示</title>
+    <style>
+      html,
+      body,
+      #root {
+        height: 100%;
+        background: transparent;
+      }
+      body {
+        margin: 0;
+        overscroll-behavior: none;
+      }
+    </style>
+    <script type="module" crossorigin src="./assets/index-P16QZIgH.js"></script>
+  </head>
+  <body>
+    <div id="root"></div>
+  </body>
+</html>

BIN
src/assets/img/model+.png


BIN
src/assets/img/model-.png


BIN
src/assets/img/modelBack.png


BIN
src/assets/img/modelR.png


+ 25 - 0
src/assets/styles/base.css

@@ -299,6 +299,31 @@ textarea {
   align-items: center;
   width: 48%;
 }
+.Y1info .Y1rowZ .Y1z1 .Y1rowZrr .Y1rowZrrModel {
+  margin-left: 20px;
+  height: 200px;
+  overflow-y: auto;
+  width: calc(100% - 220px);
+  display: flex;
+  align-items: center;
+  color: var(--themeColor);
+}
+.Y1info .Y1rowZ .Y1z1 .Y1rowZrr .Y1rowZrrModel .Y1rowZrrModelBox {
+  width: 100%;
+  max-height: 100%;
+}
+.Y1info .Y1rowZ .Y1z1 .Y1rowZrr .Y1rowZrrModel .Y1rowZrrModelBox > h3 {
+  margin-bottom: 10px;
+}
+.Y1info .Y1rowZ .Y1z1 .Y1rowZrr .Y1rowZrrModel .Y1rowZrrModelBox > div {
+  margin: 4px 0;
+  cursor: pointer;
+  transition: all 0.3s;
+  word-wrap: break-word;
+}
+.Y1info .Y1rowZ .Y1z1 .Y1rowZrr .Y1rowZrrModel .Y1rowZrrModelBox > div:hover {
+  text-shadow: 1px 1px 1px #ccc;
+}
 .Y1info .Y1rowZ .Y1z2 {
   margin-bottom: 20px;
 }

+ 36 - 2
src/assets/styles/base.less

@@ -11,8 +11,16 @@ html {
 }
 
 body {
-  font: 1em/1.4 'Microsoft Yahei', 'PingFang SC', 'Avenir', 'Segoe UI', 'Hiragino Sans GB',
-    'STHeiti', 'Microsoft Sans Serif', 'WenQuanYi Micro Hei', sans-serif;
+  font:
+    1em/1.4 'Microsoft Yahei',
+    'PingFang SC',
+    'Avenir',
+    'Segoe UI',
+    'Hiragino Sans GB',
+    'STHeiti',
+    'Microsoft Sans Serif',
+    'WenQuanYi Micro Hei',
+    sans-serif;
   height: 100%;
   color: black;
 }
@@ -435,6 +443,32 @@ textarea {
         justify-content: center;
         align-items: center;
         width: 48%;
+        .Y1rowZrrModel {
+          margin-left: 20px;
+          height: 200px;
+          overflow-y: auto;
+          width: calc(100% - 220px);
+          display: flex;
+          align-items: center;
+          color: var(--themeColor);
+          .Y1rowZrrModelBox {
+            width: 100%;
+            max-height: 100%;
+            & > h3 {
+              // text-align: center;
+              margin-bottom: 10px;
+            }
+            & > div {
+              margin: 4px 0;
+              cursor: pointer;
+              transition: all 0.3s;
+              word-wrap: break-word;
+              &:hover {
+                text-shadow: 1px 1px 1px #ccc;
+              }
+            }
+          }
+        }
       }
     }
 

+ 33 - 1
src/components/LookDom/index.module.scss

@@ -20,6 +20,14 @@
       cursor: pointer;
       z-index: 10;
     }
+    .closeModel {
+      right: aoto;
+      left: 40px;
+      top: 40px;
+      img {
+        width: 50px;
+      }
+    }
 
     .viedoBox {
       position: absolute;
@@ -50,7 +58,7 @@
     }
 
     .modelBox {
-      background-color: rgba(0, 0, 0, 0.6);
+      background-color: rgba(0, 0, 0, 0.7);
       position: absolute;
       top: 0;
       left: 0;
@@ -61,6 +69,30 @@
         width: 100%;
         height: 100%;
       }
+
+      .modelBtn {
+        cursor: pointer;
+        position: absolute;
+        z-index: 10;
+        right: 30px;
+        bottom: 50px;
+        img {
+          display: block;
+          margin: 15px 0;
+        }
+      }
+      .modelName {
+        pointer-events: none;
+        position: absolute;
+        z-index: 10;
+        bottom: 80px;
+        left: 50%;
+        transform: translateX(-50%);
+        font-size: 18px;
+        font-weight: 700;
+        color: var(--themeColor);
+        letter-spacing: 4px;
+      }
     }
   }
 }

+ 45 - 6
src/components/LookDom/index.tsx

@@ -1,11 +1,22 @@
-import React from 'react'
+import React, { useCallback } from 'react'
 import { CloseCircleOutlined } from '@ant-design/icons'
 import styles from './index.module.scss'
 import { useSelector } from 'react-redux'
 import store, { RootState } from '@/store'
 import { baseURL } from '@/utils/http'
+import classNames from 'classnames'
+
 function LookDom() {
-  const { src, type, flag } = useSelector((state: RootState) => state.A0Layout.lookDom)
+  const { src, type, flag, name } = useSelector((state: RootState) => state.A0Layout.lookDom)
+
+  // 控制放大缩小复位
+  const modelMoveFu = useCallback((fuName: 'resetView' | 'zoomIn' | 'zoomOut') => {
+    const dom: any = document.querySelector('#modelIframe')
+    if (dom && dom.contentWindow && dom.contentWindow.sceneFc[fuName]) {
+      dom.contentWindow.sceneFc[fuName]()
+    }
+  }, [])
+
   return (
     <div className={styles.LookDom} style={src ? { opacity: 1, pointerEvents: 'auto' } : {}}>
       {src ? (
@@ -20,20 +31,48 @@ function LookDom() {
             </div>
           ) : (
             <div className='modelBox'>
-              <iframe src={`model.html?m=${baseURL + src}`} frameBorder='0' title='model'></iframe>
+              <iframe
+                id='modelIframe'
+                src={`./modelLook/index.html?src=${baseURL + src}&min=0.3&max=3`}
+                frameBorder='0'
+                title='model'
+              ></iframe>
+              <div className='modelBtn'>
+                <img
+                  onClick={() => modelMoveFu('zoomIn')}
+                  src={require('@/assets/img/model+.png')}
+                  alt=''
+                />
+                <img
+                  onClick={() => modelMoveFu('zoomOut')}
+                  src={require('@/assets/img/model-.png')}
+                  alt=''
+                />
+                <img
+                  onClick={() => modelMoveFu('resetView')}
+                  src={require('@/assets/img/modelR.png')}
+                  alt=''
+                />
+              </div>
+
+              {name ? <div className='modelName'>{name}</div> : null}
             </div>
           )}
 
           <div
-            className='close'
+            className={classNames('close', type === 'model' ? 'closeModel' : '')}
             onClick={() =>
               store.dispatch({
                 type: 'layout/lookDom',
-                payload: { src: '', type: '', flag: false }
+                payload: { src: '', type: '', flag: false, name: '' }
               })
             }
           >
-            <CloseCircleOutlined rev={undefined} />
+            {type === 'model' ? (
+              <img src={require('@/assets/img/modelBack.png')} alt='' />
+            ) : (
+              <CloseCircleOutlined rev={undefined} />
+            )}
           </div>
         </>
       ) : null}

+ 2 - 2
src/pages/A3_ledger/ComPage/C4import/index.tsx

@@ -148,10 +148,10 @@ function C4import({ colseFu }: Props) {
           </span>
           {acTxt === '导入藏品数据' ? (
             <>
-              一普数据{' '}
+              馆内数据{' '}
               <a
                 href={`${baseURL}/baseData/ZP_TEMP.xlsx`}
-                download='一普数据模板'
+                download='馆内数据模板'
                 target='_blank'
                 rel='noreferrer'
               >

+ 13 - 2
src/pages/C_goodsManage/C1register/AddGoods/index.tsx

@@ -15,7 +15,7 @@ import Z3upFiles from '@/components/Z3upFiles'
 import { GoodFileType } from './type'
 import { baseURL } from '@/utils/http'
 import { fileImgArr, fileVideoArr } from '@/store/action/layout'
-import { API_C2dels } from '@/store/action/C2files'
+import { API_C2dels, API_C2setFile } from '@/store/action/C2files'
 import { API_goodsAdd, API_goodsInfo } from '@/store/action/C1ledger'
 import { C1GoodType } from '@/pages/A3_ledger/C1ledger/type'
 import { MessageFu } from '@/utils/message'
@@ -84,6 +84,8 @@ function AddGoods({ nowSta, closeFu, succFu, isEdit, editSnap }: Props) {
         // 藏品编辑信息保存
         objOld.current = { ...res.data }
 
+        // 不知道为啥存卷变成了'null'
+        if (res.data.pressFile === 'null') res.data.pressFile = ''
         // dateMaking inGoodsDate 2个日期需要格式处理一下
         const obj = editSnap && editSnap.id ? { ...editSnap } : { ...res.data }
         if (obj.dateMaking) obj.dateMaking = dayjs(obj.dateMaking)
@@ -214,7 +216,16 @@ function AddGoods({ nowSta, closeFu, succFu, isEdit, editSnap }: Props) {
             disabled={disabledSelect(item.id)}
             options={cascaderObjFu()['附件用途']}
             value={item.effect ? item.effect.split(',') : []}
-            onChange={e => tableFu('effect', item.id, e ? e.join(',') : '')}
+            onChange={async e => {
+              const res = await API_C2setFile({
+                effect: e ? e.join(',') : '',
+                type: item.type,
+                ids: [item.id]
+              })
+              if (res.code === 0) {
+                tableFu('effect', item.id, e ? e.join(',') : '')
+              }
+            }}
             placeholder='请选择'
             fieldNames={{ label: 'name', value: 'id', children: 'children' }}
           />

+ 7 - 3
src/pages/C_goodsManage/C22goodEdit/C22revamp/index.tsx

@@ -141,7 +141,7 @@ function C22revamp({ goodsId, closeFu, type, sId, upTableFu }: Props) {
                       id: v.id,
                       fileName: v.fileName,
                       filePath: v.filePath
-                    } as GoodFileType)
+                    }) as GoodFileType
                 ),
                 hou: fileNew.map(
                   v =>
@@ -149,7 +149,7 @@ function C22revamp({ goodsId, closeFu, type, sId, upTableFu }: Props) {
                       id: v.id,
                       fileName: v.fileName,
                       filePath: v.filePath
-                    } as GoodFileType)
+                    }) as GoodFileType
                 ),
                 key: 'fileIds'
               })
@@ -187,8 +187,12 @@ function C22revamp({ goodsId, closeFu, type, sId, upTableFu }: Props) {
                 }
               ]
             }
+            // if (1 + 1 === 2) {
+            //   console.log(123, obj2)
+            //   console.log('pppp', JSON.parse(obj2.snaps[0].snap))
+            //   return
+            // }
 
-            // console.log('pppp', JSON.parse(obj2.snaps[0].snap))
             const res = sta === '存草稿' ? await C6_APIsaveDraft(obj2) : await C6_APIsaveApply(obj2)
 
             if (res.code === 0) {

+ 11 - 0
src/pages/C_goodsManage/C2files/index.tsx

@@ -18,6 +18,7 @@ import { RootState } from '@/store'
 import { downFileFu, resJiLianFu } from '@/utils/history'
 import { MessageFu } from '@/utils/message'
 import { GoodFileType } from '@/components/Z3upFiles'
+import { lookModelClick, lookModelFu } from '@/pages/Y_goodsDetails/Y1cathet/data'
 const { RangePicker } = DatePicker
 
 function C2files() {
@@ -199,6 +200,16 @@ function C2files() {
           const fileNameLast = fileNameArr[fileNameArr.length - 1]
           return (
             <>
+              {lookModelFu(item.fileName) ? (
+                <Button
+                  size='small'
+                  type='text'
+                  onClick={() => lookModelClick(item.filePath, item.goodName)}
+                >
+                  预览
+                </Button>
+              ) : null}
+
               {downImg['图片'] === '原图和缩略图' &&
               fileImgArr.includes(fileNameLast.toLowerCase()) ? (
                 <Popconfirm

+ 32 - 2
src/pages/Y_goodsDetails/Y1cathet/Y11com.tsx

@@ -1,8 +1,17 @@
 import ImageLazy from '@/components/ImageLazy'
-import React from 'react'
+import React, { useMemo } from 'react'
 import classNames from 'classnames'
-import { Y11infoArr1, Y11infoArr2, Y11infoArr3, Y11infoArr4, Y11infoArr5 } from './data'
+import {
+  lookModelArrResFu,
+  lookModelClick,
+  Y11infoArr1,
+  Y11infoArr2,
+  Y11infoArr3,
+  Y11infoArr4,
+  Y11infoArr5
+} from './data'
 import { C1GoodType } from '@/pages/A3_ledger/C1ledger/type'
+import { GoodFileType } from '@/components/Z3upFiles'
 
 const domArr = [
   { name: '藏品基本信息', arr: Y11infoArr2 },
@@ -16,6 +25,12 @@ type Props = {
 }
 
 function Y11com({ info }: Props) {
+  const lookModelArr = useMemo(() => {
+    let arr: GoodFileType[] = []
+    if (info.file && info.file.length) arr = lookModelArrResFu(info.file)
+    return arr
+  }, [info.file])
+
   return (
     <div className='Y1rowZ'>
       <div className='Y1tit'>档案信息</div>
@@ -35,6 +50,21 @@ function Y11com({ info }: Props) {
             srcBig={info.thumbPc || info.filePath}
             src={info.thumb}
           />
+          {lookModelArr.length ? (
+            <div className='Y1rowZrrModel'>
+              <div className='Y1rowZrrModelBox'>
+                <h3>模型预览</h3>
+                {lookModelArr.map(fileItem => (
+                  <div
+                    onClick={() => lookModelClick(fileItem.filePath, info.name)}
+                    key={fileItem.id}
+                  >
+                    {fileItem.fileName}
+                  </div>
+                ))}
+              </div>
+            </div>
+          ) : null}
         </div>
       </div>
 

+ 16 - 4
src/pages/Y_goodsDetails/Y1cathet/Y33com.tsx

@@ -15,6 +15,7 @@ import { useSelector } from 'react-redux'
 import { RootState } from '@/store'
 import { GoodFileType } from '@/components/Z3upFiles'
 import { C1GoodType } from '@/pages/A3_ledger/C1ledger/type'
+import { lookModelClick, lookModelFu } from './data'
 // import { API_setGoodsCover } from '@/store/action/C1ledger'
 
 type Props = {
@@ -42,16 +43,17 @@ function Y33com({ isLook, sId, info, setImgCover }: Props) {
   // 附件表格对象
   const tableObj = useMemo(() => {
     let obj: any = {
-      '': fileList
+      all: fileList
     }
     fileList.forEach(v => {
       if (obj[v.type]) obj[v.type].push(v)
       else obj[v.type] = [v]
     })
+
     return obj
   }, [fileList])
 
-  const [btnAc, setBtnAc] = useState('')
+  const [btnAc, setBtnAc] = useState('all')
 
   // 多选
   const [checkArr, setCheckArr] = useState<number[]>([])
@@ -173,6 +175,16 @@ function Y33com({ isLook, sId, info, setImgCover }: Props) {
         const fileNameLast = fileNameArr[fileNameArr.length - 1]
         return (
           <>
+            {lookModelFu(item.fileName) ? (
+              <Button
+                size='small'
+                type='text'
+                onClick={() => lookModelClick(item.filePath, info.name)}
+              >
+                预览
+              </Button>
+            ) : null}
+
             {downImg['图片'] === '原图和缩略图' &&
             fileImgArr.includes(fileNameLast.toLowerCase()) ? (
               <Popconfirm
@@ -220,7 +232,7 @@ function Y33com({ isLook, sId, info, setImgCover }: Props) {
     })
 
     return arr
-  }, [delFu, downImg, isLook])
+  }, [delFu, downImg, info.name, isLook])
 
   const [typeMo, setTypeMo] = useState({} as infoType)
 
@@ -244,7 +256,7 @@ function Y33com({ isLook, sId, info, setImgCover }: Props) {
         <>
           <div className='Y33top'>
             <div className='Y33topll'>
-              {[{ label: '全部', value: '' }, ...selectObj['附件类型']].map(v => (
+              {[{ label: '全部', value: 'all' }, ...selectObj['附件类型']].map(v => (
                 <Button
                   key={v.value}
                   onClick={() => {

+ 33 - 0
src/pages/Y_goodsDetails/Y1cathet/data.tsx

@@ -1,4 +1,6 @@
+import { GoodFileType } from '@/components/Z3upFiles'
 import { C1GoodType } from '@/pages/A3_ledger/C1ledger/type'
+import store from '@/store'
 import { resJiLianFu, textFu } from '@/utils/history'
 import { selectObj } from '@/utils/select'
 
@@ -186,3 +188,34 @@ export const Y11infoArr5: ArrKeyType = [
   { name: '著作及有关书目', key: 'historyWork' },
   { name: '流传经历', key: 'historyUndergo' }
 ]
+
+// 过滤出可以预览的模型
+const lookModelFlag = ['glb', 'fbx']
+
+// 过滤数组
+export const lookModelArrResFu = (list: GoodFileType[]) => {
+  const arr: GoodFileType[] = []
+  list.forEach(v => {
+    const lastNameArr = v.fileName.split('.')
+    let lastName = lastNameArr[lastNameArr.length - 1]
+    lastName = lastName.toLowerCase()
+
+    if (lookModelFlag.includes(lastName)) arr.push(v)
+  })
+  return arr
+}
+
+// 过滤单个
+export const lookModelFu = (name: string) => {
+  let flag = false
+  const lastNameArr = name.split('.')
+  let lastName = lastNameArr[lastNameArr.length - 1]
+  lastName = lastName.toLowerCase()
+  if (lookModelFlag.includes(lastName)) flag = true
+  return flag
+}
+
+// 点击预览模型
+export const lookModelClick = (url: string, name?: string) => {
+  store.dispatch({ type: 'layout/lookDom', payload: { type: 'model', src: url, name } })
+}

+ 26 - 0
src/pages/Y_goodsDetails/Y2look/index.module.scss

@@ -113,6 +113,32 @@
             justify-content: center;
             width: 48%;
           }
+          .Y1rowZrrModel {
+            margin-left: 20px;
+            height: 200px;
+            overflow-y: auto;
+            width: calc(100% - 220px);
+            display: flex;
+            align-items: center;
+            color: var(--themeColor);
+            .Y1rowZrrModelBox {
+              width: 100%;
+              max-height: 100%;
+              & > h3 {
+                // text-align: center;
+                margin-bottom: 10px;
+              }
+              & > div {
+                margin: 4px 0;
+                cursor: pointer;
+                transition: all 0.3s;
+                word-wrap: break-word;
+                &:hover {
+                  text-shadow: 1px 1px 1px #ccc;
+                }
+              }
+            }
+          }
         }
 
         .Y1z2 {

+ 1 - 1
src/store/action/layout.ts

@@ -34,7 +34,7 @@ export const fileVideoArr = ['mp4', 'mov', 'avi', 'mkv', 'flv', 'wmv', 'mpeg', '
 const fileObj: FileObjType = {
   img: fileImgArr,
   video: fileVideoArr,
-  model: ['4dage', 'obj', 'stl', 'fbx', 'gltf', '3ds', 'blend', 'dae', 'step'],
+  model: ['4dage', 'obj', 'stl', 'fbx', 'gltf', '3ds', 'blend', 'dae', 'step', 'glb'],
   audio: ['mp3', 'wav', 'flac', 'aac', 'ogg', 'm4a'],
   doc: ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'md', 'html']
   // 'other':[]

+ 1 - 0
src/types/api/layot.d.ts

@@ -2,6 +2,7 @@ export type LookDomType = {
   src: string
   type: 'video' | 'audio' | 'model' | ''
   flag?: boolean
+  name?: string
 }
 
 export type RouterTypeRow = {

+ 1 - 1
src/utils/tableData.ts

@@ -226,7 +226,7 @@ export const C4tableCFu = (val: string) => {
   ]
 
   if (val === '导入藏品数据')
-    arr.unshift(['txtChange', '数据类型', 'type', { '1': '一普数据', '2': '省平台数据' }])
+    arr.unshift(['txtChange', '数据类型', 'type', { '1': '馆内数据', '2': '省平台数据' }])
 
   return arr
 }