Commit ed4c035db03ced5adeb777f486059eda67ee0b61

Authored by xp.Huang
2 parents 22dfee7d fa94448f

Merge branch 'fix/teambition/10-17/2024' into 'main_dev'

fix(src/packages): 新增或者编辑3D模型编辑器,携带区分标识,云端大屏绑定摄像头点击全屏后,视频暂停了

See merge request yunteng/thingskit-view!294
1 1 <!DOCTYPE html>
2 2 <html lang="en">
  3 + <head>
  4 + <title>ThingsKit 3D Model Editor</title>
  5 + <meta charset="utf-8" />
  6 + <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
  7 + </head>
3 8
4   -<head>
5   - <title>3D Model Editor</title>
6   - <meta charset="utf-8">
7   - <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
8   -</head>
9   -
10   -<body>
11   - <link rel="stylesheet" href="css/main.css">
12   - <link rel="stylesheet" href="js/libs/codemirror/codemirror.css">
13   - <link rel="stylesheet" href="js/libs/codemirror/theme/monokai.css">
14   - <link rel="stylesheet" href="js/libs/codemirror/addon/dialog.css">
15   - <link rel="stylesheet" href="js/libs/codemirror/addon/show-hint.css">
16   - <link rel="stylesheet" href="js/libs/codemirror/addon/tern.css">
17   -
18   - <script type="module" src="./jsm/libs/draco/draco_encoder.js"></script>
19   - <script type="module" src="./js/libs/codemirror/codemirror.js"></script>
20   - <script type="module" src="./js/libs/codemirror/mode/javascript.js"></script>
21   - <script type="module" src="./js/libs/codemirror/mode/glsl.js"></script>
22   - <script type="module" src="./js/libs/esprima.js"></script>
23   - <script type="module" src="./js/libs/jsonlint.js"></script>
24   - <script type="module" src="./js/libs/ffmpeg/ffmpeg.min.js"></script>
25   - <script type="module" src="./js/libs/codemirror/addon/dialog.js"></script>
26   - <script type="module" src="./js/libs/codemirror/addon/show-hint.js"></script>
27   - <script type="module" src="./js/libs/codemirror/addon/tern.js"></script>
28   - <script type="module" src="./js/libs/acorn/acorn.js"></script>
29   - <script type="module" src="./js/libs/acorn/acorn_loose.js"></script>
30   - <script type="module" src="./js/libs/acorn/walk.js"></script>
31   - <script type="module" src="./js/libs/ternjs/polyfill.js"></script>
32   - <script type="module" src="./js/libs/ternjs/signal.js"></script>
33   - <script type="module" src="./js/libs/ternjs/tern.js"></script>
34   - <script type="module" src="./js/libs/ternjs/def.js"></script>
35   - <script type="module" src="./js/libs/ternjs/comment.js"></script>
36   - <script type="module" src="./js/libs/ternjs/infer.js"></script>
37   - <script type="module" src="./js/libs/ternjs/doc_comment.js"></script>
38   - <script type="module" src="./js/libs/tern-threejs/threejs.js"></script>
39   - <script type="module" src="./js/libs/signals.min.js"></script>
40   - <script type="module" src="./js/libs/axios.min.js"></script>
41   - <script type="module" src="./js/libs/http/config.js"></script>
42   -
43   - <script src="./main.js" type="module"></script>
44   -</body>
45   -
  9 + <body>
  10 + <link rel="stylesheet" href="css/main.css" />
  11 + <link rel="stylesheet" href="js/libs/codemirror/codemirror.css" />
  12 + <link rel="stylesheet" href="js/libs/codemirror/theme/monokai.css" />
  13 + <link rel="stylesheet" href="js/libs/codemirror/addon/dialog.css" />
  14 + <link rel="stylesheet" href="js/libs/codemirror/addon/show-hint.css" />
  15 + <link rel="stylesheet" href="js/libs/codemirror/addon/tern.css" />
  16 + <script type="module" src="./jsm/libs/draco/draco_encoder.js"></script>
  17 + <script type="module" src="./js/libs/codemirror/codemirror.js"></script>
  18 + <script type="module" src="./js/libs/codemirror/mode/javascript.js"></script>
  19 + <script type="module" src="./js/libs/codemirror/mode/glsl.js"></script>
  20 + <script type="module" src="./js/libs/esprima.js"></script>
  21 + <script type="module" src="./js/libs/jsonlint.js"></script>
  22 + <script type="module" src="./js/libs/ffmpeg/ffmpeg.min.js"></script>
  23 + <script type="module" src="./js/libs/codemirror/addon/dialog.js"></script>
  24 + <script type="module" src="./js/libs/codemirror/addon/show-hint.js"></script>
  25 + <script type="module" src="./js/libs/codemirror/addon/tern.js"></script>
  26 + <script type="module" src="./js/libs/acorn/acorn.js"></script>
  27 + <script type="module" src="./js/libs/acorn/acorn_loose.js"></script>
  28 + <script type="module" src="./js/libs/acorn/walk.js"></script>
  29 + <script type="module" src="./js/libs/ternjs/polyfill.js"></script>
  30 + <script type="module" src="./js/libs/ternjs/signal.js"></script>
  31 + <script type="module" src="./js/libs/ternjs/tern.js"></script>
  32 + <script type="module" src="./js/libs/ternjs/def.js"></script>
  33 + <script type="module" src="./js/libs/ternjs/comment.js"></script>
  34 + <script type="module" src="./js/libs/ternjs/infer.js"></script>
  35 + <script type="module" src="./js/libs/ternjs/doc_comment.js"></script>
  36 + <script type="module" src="./js/libs/tern-threejs/threejs.js"></script>
  37 + <script type="module" src="./js/libs/signals.min.js"></script>
  38 + <script type="module" src="./js/libs/axios.min.js"></script>
  39 + <script type="module" src="./js/libs/http/config.js"></script>
  40 + <script type="module" src="./main.js"></script>
  41 + </body>
46 42 </html>
... ...
... ... @@ -51,6 +51,8 @@ editor.storage.init(async function () {
51 51 const paramsStr = window.location.search
52 52 const params = new URLSearchParams(paramsStr)
53 53 const file_uuid = params.get('three_file_uuid')
  54 + const actionType = params.get('action_type')
  55 + if (actionType === 'create') return
54 56 const fileData = await getThreeJsModel(file_uuid)
55 57 if (!fileData) return
56 58 if (!fileData['content']) return
... ...
... ... @@ -5,12 +5,13 @@
5 5 <meta charset="UTF-8" />
6 6 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
7 7 <meta name="renderer" content="webkit" />
8   - <meta name="description" content="GoView 是高效、高性能的拖拽式低代码数据可视化开发平台,将页面元素封装为基础组件,无需编写代码即可完成业务需求。">
9   - <meta name="keywords" content="GoView,goview,低代码,可视化">
10   - <meta name="author" content="奔跑的面条,面条">
  8 + <meta name="description" content="ThingsKit View 是高效、高性能的拖拽式低代码数据可视化开发平台,将页面元素封装为基础组件,无需编写代码即可完成业务需求。">
  9 + <meta name="keywords" content="ThingsKit View,低代码,可视化">
  10 + <meta name="author" content="ThingsKit">
11 11 <meta name="viewport"
12 12 content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0" />
13 13 <link rel="icon" href="./favicon.ico" />
  14 + <title>大屏设计器</title>
14 15 <!-- <link rel="stylesheet" href="./index.css" /> -->
15 16 <style>
16 17 * {
... ...
1 1 <template>
2 2 <div class="go-apple-control-btn">
3 3 <template v-for="item in filterBtnList" :key="item.key">
4   - <div
5   - class="btn"
6   - :class="[item.key, disabled && 'disabled', mini && 'mini']"
7   - @click.stop="handleClick(item.key)"
8   - >
9   - <n-icon size="10" class="icon-base" :class="{ hover: !disabled }">
10   - <component :is="item.icon"></component>
11   - </n-icon>
  4 + <div class="btn" :class="[item.key, disabled && 'disabled', mini && 'mini']" @click.stop="handleClick(item.key)">
  5 + <n-tooltip trigger="hover">
  6 + <template #trigger>
  7 + <n-icon size="10" class="icon-base" :class="{ hover: !disabled }">
  8 + <component :is="item.icon"></component>
  9 + </n-icon>
  10 + </template>
  11 + {{ item.title }}
  12 + </n-tooltip>
12 13 </div>
13 14 </template>
14 15 </div>
... ... @@ -50,7 +51,7 @@ const props = defineProps({
50 51 })
51 52 const t = window['$t']
52 53
53   -const { CloseIcon, RemoveIcon, ResizeIcon } = icon.ionicons5
  54 +const { CloseIcon, RemoveIcon, BrowsersOutlineIcon } = icon.ionicons5
54 55
55 56 const filterBtnList = computed(() => {
56 57 const res = btnList.filter(e => {
... ... @@ -69,19 +70,19 @@ const btnList: {
69 70 icon: any
70 71 }[] = [
71 72 {
72   - title: t('common.closeText'),
  73 + title: t('common.delText'),
73 74 key: 'close',
74 75 icon: CloseIcon
75 76 },
76 77 {
77   - title: t('common.reduceText'),
  78 + title: t('common.reduceText'),
78 79 key: 'remove',
79 80 icon: RemoveIcon
80 81 },
81 82 {
82   - title: isFull.value ? t('common.reduceText') : t('common.amplifyText'),
  83 + title: isFull.value ? t('common.loadThreeModel') : t('common.loadThreeModel'),
83 84 key: props.narrow ? 'fullResize' : 'resize',
84   - icon: ResizeIcon
  85 + icon: BrowsersOutlineIcon
85 86 }
86 87 ]
87 88
... ...
... ... @@ -522,4 +522,5 @@ export default {
522 522 roma: 'roma'
523 523 },
524 524 accessToken: 'Access token',
  525 + loadThreeModel: 'Load three model',
525 526 }
... ...
... ... @@ -521,4 +521,5 @@ export default {
521 521 roma: '罗马红'
522 522 },
523 523 accessToken: '访问令牌',
  524 + loadThreeModel: '加载模型',
524 525 }
... ...
... ... @@ -6,6 +6,13 @@ import cloneDeep from 'lodash/cloneDeep'
6 6
7 7 export const option = {
8 8 dataset: '',
  9 + backgroundColor: '', //场景背景色
  10 + backgroundAlpha: 0, //场景透明度
  11 + borderConfig: {
  12 + color: 'grey',
  13 + size: 1,
  14 + show: false
  15 + }
9 16 }
10 17
11 18 export default class Config extends PublicConfigClass implements CreateComponentType {
... ...
1 1 <template>
2   - <!-- <collapse-item :name="t('component.treeConfig')" :expanded="true">
  2 + <collapse-item :name="t('component.treeConfig')" :expanded="true">
3 3 <setting-item-box :name="t('component.borderConfig')">
4   - <setting-item :name="t('common.colorText')"> </setting-item>
  4 + <setting-item :name="t('common.colorText')">
  5 + <n-color-picker size="small" :show-alpha="false" v-model:value="optionData.borderConfig.color"></n-color-picker>
  6 + </setting-item>
  7 + <setting-item :name="t('component.openBorder')">
  8 + <n-switch v-model:value="optionData.borderConfig.show" size="small" />
  9 + </setting-item>
  10 + <setting-item :name="t('charts.chart.sizeText')">
  11 + <n-input-number :min="0" v-model:value="optionData.borderConfig.size" size="small" />
  12 + </setting-item>
5 13 </setting-item-box>
6   - </collapse-item> -->
  14 + </collapse-item>
7 15 </template>
8 16
9 17 <script setup lang="ts">
10 18 import { PropType } from 'vue'
11 19 import { option } from './config'
12   -// import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  20 +import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
13 21
14 22 defineProps({
15 23 optionData: {
... ... @@ -18,7 +26,7 @@ defineProps({
18 26 }
19 27 })
20 28
21   -// const t = window['$t']
  29 +const t = window['$t']
22 30 </script>
23 31
24 32 <style lang="scss" scoped></style>
... ...
1 1 <template>
2   - <div class="go-content-box">
  2 + <div class="go-content-box" :style="{ border: !borderConfig.show ? 'none' : '' }">
3 3 <div>
4 4 <vue3dLoader
5 5 ref="vue3dLoaderRef"
6 6 :requestHeader="headers"
  7 + :backgroundColor="backgroundColor"
  8 + :backgroundAlpha="backgroundAlpha"
7 9 :webGLRendererOptions="webGLRendererOptions"
8 10 :height="h"
9 11 :width="w"
... ... @@ -69,12 +71,15 @@ const onProcess = (event: Recordable) => {
69 71
70 72 const { w, h } = toRefs(props.chartConfig.attr)
71 73
72   -const { dataset } = toRefs(props.chartConfig.option) as Recordable
  74 +const { dataset, backgroundColor, backgroundAlpha,borderConfig } = toRefs(props.chartConfig.option) as Recordable
73 75 </script>
74 76
75 77 <style lang="scss" scoped>
76 78 .go-content-box {
77 79 height: 100%;
  80 + border-width: v-bind('borderConfig.size + "px"');
  81 + border-style: solid;
  82 + border-color: v-bind('borderConfig.color');
78 83 .process {
79 84 position: absolute;
80 85 top: 50%;
... ...
... ... @@ -70,13 +70,14 @@ async function doPlaySource(params?: Dataset) {
70 70 }
71 71
72 72 function handleOnUserAction(event: UserActionEventType) {
73   - const { from, to } = event
  73 + console.log(event)
  74 + const { from, to, pluginName } = event
74 75 if (from && !to) {
75 76 doPlaySource(dataset?.value)
76 77 nextTick(() => {
77 78 XGPlayerRef.value?.getPlayerInstance()?.play()
78 79 })
79   - } else if (!from && to) {
  80 + } else if (!from && to && pluginName !== "fullscreen") {
80 81 nextTick(() => {
81 82 XGPlayerRef.value?.getPlayerInstance()?.pause()
82 83 })
... ...
  1 +<template>
  2 + <div class="go-content-box">
  3 + <div>
  4 + <vue3dLoader
  5 + ref="vue3dLoaderRef"
  6 + :requestHeader="headers"
  7 + :webGLRendererOptions="webGLRendererOptions"
  8 + :height="200"
  9 + :width="400"
  10 + :filePath="threeModelPath"
  11 + @process="onProcess"
  12 + @load="onLoad"
  13 + :intersectRecursive="true"
  14 + />
  15 + <div v-show="show" class="process">
  16 + <span> 拼命加载中... </span>
  17 + <n-progress type="line" :color="themeColor" :percentage="process" :indicator-placement="'inside'" processing />
  18 + </div>
  19 + </div>
  20 + </div>
  21 +</template>
  22 +<script setup lang="ts">
  23 +import { ref, nextTick, computed } from 'vue'
  24 +import { vue3dLoader } from 'vue-3d-loader'
  25 +import { useDesignStore } from '@/store/modules/designStore/designStore'
  26 +import { getJwtToken } from '@/utils/external/auth'
  27 +
  28 +const designStore = useDesignStore()
  29 +
  30 +defineProps({
  31 + threeModelPath: {
  32 + type: String,
  33 + default: ''
  34 + }
  35 +})
  36 +
  37 +const themeColor = computed(() => {
  38 + return designStore.getAppTheme
  39 +})
  40 +
  41 +const vue3dLoaderRef = ref(null)
  42 +
  43 +const headers = {
  44 + 'x-authorization': `Bearer ${getJwtToken()}`
  45 +}
  46 +const webGLRendererOptions = {
  47 + alpha: true, // 透明
  48 + antialias: true, // 抗锯齿
  49 + // fix: 预览三维图像需加上preserveDrawingBuffer: true
  50 + preserveDrawingBuffer: true //缩略图生效需开启
  51 +}
  52 +
  53 +//三维模型加载
  54 +const show = ref(false)
  55 +
  56 +const onLoad = async () => {
  57 + //加载完成
  58 + await nextTick()
  59 + show.value = false
  60 +}
  61 +
  62 +//三维模型进度条
  63 +const process = ref(0)
  64 +
  65 +const onProcess = (event: Recordable) => {
  66 + process.value = Math.floor((event.loaded / event.total) * 100)
  67 +}
  68 +</script>
  69 +
  70 +<style lang="scss" scoped>
  71 +.go-content-box {
  72 + height: 100%;
  73 + .process {
  74 + position: absolute;
  75 + top: 50%;
  76 + left: 50%;
  77 + width: 50%;
  78 + transform: translate(-50%, -50%);
  79 + }
  80 +}
  81 +</style>
... ...
... ... @@ -8,15 +8,17 @@
8 8 class="top-btn"
9 9 :hidden="['remove']"
10 10 @close="deleteHandle"
11   - @resize="resizeHandle"
  11 + @resize="handleLoadThreeModel"
12 12 ></mac-os-control-btn>
13 13 </div>
14 14 <!-- 中间 -->
15   - <div class="list-content-img" @click="resizeHandle">
  15 + <div class="list-content-img">
  16 + <LoadThreeModelImage v-if="showThreeModel" :threeModelPath="cardData.threeModelFilePath" />
16 17 <n-image
17 18 object-fit="contain"
18 19 height="180"
19 20 preview-disabled
  21 + v-else
20 22 :src="requireUrl('ThreeModelDefault.svg')"
21 23 :fallback-src="requireErrorImg()"
22 24 ></n-image>
... ... @@ -99,6 +101,7 @@ import { MacOsControlBtn } from '@/components/Tips/MacOsControlBtn'
99 101 import { ChartType } from '../..'
100 102 import { updateThreeJsModel } from '@/api/external/contentSave/content'
101 103 const { EllipsisHorizontalCircleSharpIcon, TrashIcon, HammerIcon, SendIcon } = icon.ionicons5
  104 +import LoadThreeModelImage from '../LoadThreeModelImage.vue'
102 105
103 106 const emit = defineEmits(['delete', 'resize', 'edit', 'release', 'inputUpdateCard'])
104 107
... ... @@ -112,6 +115,10 @@ const inputInstRef = ref(null)
112 115
113 116 const title = ref<string>('')
114 117
  118 +const showThreeModel = ref(false)
  119 +
  120 +const handleLoadThreeModel = () => (showThreeModel.value = true)
  121 +
115 122 // 处理url获取
116 123 const requireUrl = (name: string) => {
117 124 return new URL(`../../../../../assets/images/${name}`, import.meta.url).href
... ... @@ -172,10 +179,10 @@ const releaseHandle = () => {
172 179 emit('release', props.cardData)
173 180 }
174 181
175   -// 放大处理
176   -const resizeHandle = () => {
177   - emit('resize', props.cardData)
178   -}
  182 +// // 放大处理
  183 +// const resizeHandle = () => {
  184 +// emit('resize', props.cardData)
  185 +// }
179 186
180 187 const handleFocus = () => {
181 188 focus.value = true
... ... @@ -186,7 +193,7 @@ const handleFocus = () => {
186 193
187 194 const handleBlur = async () => {
188 195 focus.value = false
189   - if(!title.value) return
  196 + if (!title.value) return
190 197 await updateThreeJsModel({
191 198 id: props.cardData?.id as string,
192 199 name: title.value
... ...
... ... @@ -28,9 +28,16 @@ export const useDataListInit = () => {
28 28 pageSize: pagination.pageSize
29 29 })
30 30 if (res) {
  31 + const { host, protocol } = location
  32 + const threeFilePath = `${protocol}//${host}`
  33 + const VITE_GLOB_API_URL = import.meta.env.VITE_GLOB_API_URL
  34 + const VITE_GLOB_API_URL_PREFIX = import.meta.env.VITE_GLOB_API_URL_PREFIX
31 35 const { total, items } = res as PaginationResult<ChartType>
32 36 pagination.count = total
33   - list.value = items
  37 + list.value = items.map(item => ({
  38 + ...item,
  39 + threeModelFilePath: `${threeFilePath}${VITE_GLOB_API_URL}${VITE_GLOB_API_URL_PREFIX}/3d_component/json/${item.id}/scene.json`
  40 + }))
34 41 setTimeout(() => {
35 42 loading.value = false
36 43 }, 500)
... ... @@ -60,7 +67,7 @@ export const useDataListInit = () => {
60 67 // eslint-disable-next-line @typescript-eslint/no-empty-function
61 68 onPositiveCallback: () => {},
62 69 promiseResCallback: async () => {
63   - await threeJsDeleteApi([cardData.id] as string[])
  70 + await threeJsDeleteApi([cardData.id] as string[])
64 71 window['$message'].success(window['$t']('common.deleteSuccessText'))
65 72 fetchList()
66 73 }
... ...
... ... @@ -23,7 +23,7 @@ export const useModalDataInit = () => {
23 23 if (!cardData) return
24 24 if (!cardData?.id) return
25 25 const { host, protocol, pathname } = location
26   - window.open(`${protocol}//${host}${pathname}editor/?three_file_uuid=${cardData?.id}`)
  26 + window.open(`${protocol}//${host}${pathname}editor/?three_file_uuid=${cardData?.id}&action_type=update`)
27 27 }
28 28
29 29 return {
... ...
... ... @@ -7,6 +7,7 @@ export type ChartType = {
7 7 content?: any
8 8 state?: number
9 9 name?: string
  10 + threeModelFilePath?: string
10 11 }
11 12
12 13 export type ChartList = ChartType[]
... ...
... ... @@ -48,7 +48,7 @@ const modalShow = ref<boolean>(false)
48 48 const clickHandle = () => {
49 49 const { host, protocol, pathname } = location
50 50 const randomId = getUUID(32)
51   - window.open(`${protocol}//${host}${pathname}editor/?three_file_uuid=${randomId}`)
  51 + window.open(`${protocol}//${host}${pathname}editor/?three_file_uuid=${randomId}&action_type=create`)
52 52 }
53 53
54 54 const closeHandle = () => {
... ...