Bläddra i källkod

feat: 重构模板使用页面

HOME\tianlin01 11 månader sedan
förälder
incheckning
229d8f506e

+ 5 - 2
.env.development

@@ -18,8 +18,11 @@ VUE_APP_OFFLINE_MAP_PROXY = '/tiles'
 # VUE_APP_GATEWAY = 'isoc.artaplay.com:7443'
 # VUE_APP_KEYCLOAK_OPTIONS_URL = 'https://isoc.artaplay.com:8443/auth'
 # 110.5服务器
-VUE_APP_GATEWAY = '10.58.110.5'
-VUE_APP_KEYCLOAK_OPTIONS_URL = 'http://10.58.110.5:9080/auth'
+#VUE_APP_GATEWAY = '10.58.110.5'
+#VUE_APP_KEYCLOAK_OPTIONS_URL = 'http://10.58.110.5:9080/auth'
+
+VUE_APP_GATEWAY = '192.168.2.120'
+VUE_APP_KEYCLOAK_OPTIONS_URL = 'http://192.168.2.120:9080/auth'
 #浪潮云
 # VUE_APP_GATEWAY = 'msr.inspur.com:8084'
 # VUE_APP_KEYCLOAK_OPTIONS_URL = 'https://msr.inspur.com:8084/auth'

+ 0 - 1
alais.config.js

@@ -11,4 +11,3 @@ module.exports = {
     }
   }
 }
-

+ 132 - 32
src/components/dialog/TemplateAssetChooseDialog/index.vue

@@ -25,16 +25,15 @@
             >
               <div class="c-viewer__list">
                 <div
-                  v-for="(widget,index) in layers"
+                  v-for="widget in layers"
                   ref="widgetElements"
-                  :key="index"
+                  :key="widget.id"
                   class="c-sibling-item--v o-layer"
-                  :class="{ active: index == selectedWidgetIndex }"
-                  @click="onWidgetClick(widget,index,$event)"
+                  :class="{ active: widget.id === selectedWidgetId }"
+                  @click="onWidgetClick(widget, $event)"
                 >
                   <widget-shortcut
                     :widget="widget"
-                    editable
                     @view="onView"
                   />
                 </div>
@@ -242,6 +241,27 @@
               @customPaste="onCustomPaste"
             />
           </div>
+          <div
+            ref="canvas"
+            style="position: absolute;top:0;left: 0;z-index: -1;"
+            class="l-flex__none"
+            :style="canvasStyles"
+          >
+            <div
+              class="c-viewer__canvas has-bg"
+              :style="[transformStyles, styles]"
+            >
+              <div
+                class="c-viewer__background has-bg"
+                :style="backgroundStyles"
+              />
+              <widget
+                v-for="item in widgets"
+                :key="item.id"
+                :node="item"
+              />
+            </div>
+          </div>
         </div>
       </template>
     </confirm-dialog>
@@ -274,6 +294,9 @@ import {
   Toolbar
 } from '@wangeditor/editor-for-vue'
 import '@wangeditor/editor/dist/css/style.css'
+import domToImage from 'dom-to-image'
+import mixin2 from '@/views/screen/material/program/ast/mixin2'
+import Widget from '@/views/screen/material/program/ast/core/widget/WidgetViewer'
 
 export default {
   name: 'TemplateAssetChooseDialog',
@@ -281,8 +304,10 @@ export default {
     Draggable,
     WidgetShortcut,
     Editor,
-    Toolbar
+    Toolbar,
+    Widget
   },
+  mixins: [mixin2],
   props: {
     title: {
       type: String,
@@ -299,6 +324,8 @@ export default {
   },
   data () {
     return {
+      snapping: false,
+      canvasStyles: null,
       inputValues: [],
       lastIndex: 0,
       types: [],
@@ -310,7 +337,6 @@ export default {
       options: {},
       isStream: false,
       selectedWidget: null, //
-      selectedWidgetIndex: 0,
       program: null,
       isMedia: true,
       editor: null,
@@ -340,20 +366,17 @@ export default {
     //   return this.title || (this.types.length > 1 ? '请选择资源' : `请选择${AssetTypeInfo[this.types[0]]}`)
     // },
     layers () {
-      const arr = this.program.detail.widgets.slice()
-        .reverse()
-      console.log('widgets', arr)
-      return arr
+      return this.widgets.slice().reverse()
     },
     count () {
-      if (this.program.detail) {
-        return this.program.detail.widgets.length
+      if (this.node) {
+        return this.layers.length
       }
       return 0
     },
-    // selectedWidgetId () {
-    //   return this.selectedWidget?.id
-    // },
+    selectedWidgetId () {
+      return this.selectedWidget?.id
+    },
     hasRootAssets () {
       if (this.node) {
         const { backgroundImage, bgm } = this.node
@@ -426,7 +449,7 @@ export default {
   },
   watch: {
     selectedWidget () {
-      this.program && setTimeout(() => {
+      this.node && setTimeout(() => {
         if (this.selectedWidget) {
           this.$refs.widgetElements?.find(element => element.classList.contains('active'))
             ?.scrollIntoView({ behavior: 'smooth', block: 'start' })
@@ -441,6 +464,60 @@ export default {
     this.updateInputValues()
   },
   methods: {
+    checkRatio () {
+      if (this.canvasStyles) {
+        return
+      }
+      const { width, height } = this.node
+      if (width <= 960 && height <= 540) {
+        this.canvasStyles = {}
+      } else {
+        const wScale = 960 / width
+        const hScale = 540 / height
+        this.scale = Math.min(wScale, hScale) * 100 | 0
+        if (wScale <= hScale) {
+          this.canvasStyles = {
+            width: '960px',
+            height: `${height * wScale}px`
+          }
+        } else {
+          this.canvasStyles = {
+            width: `${width * hScale}px`,
+            height: '540px'
+          }
+        }
+      }
+    },
+    toSnap () {
+      setTimeout(() => {
+        this.test()
+      }, 100)
+    },
+    async test () {
+      const base64 = await this.snap()
+      if (base64) {
+        const result = /^data:(.+);base64,(.+)$/.exec(base64)
+        console.log('base64:', result[0])
+        this.imageBase64 = result[0]
+      }
+    },
+    snap () {
+      this.snapping = true
+      return domToImage.toJpeg(this.$refs.canvas, {
+        filter (node) {
+          const { tagName } = node
+          if (tagName === 'CANVAS') {
+            return /^data:.+;base64,.+/.test(node.toDataURL())
+          }
+          return tagName !== 'VIDEO' && tagName !== 'IFRAME'
+        },
+        width: this.node.width * this.scale / 100 | 0,
+        height: this.node.height * this.scale / 100 | 0,
+        quality: 0.1
+      }).finally(() => {
+        this.snapping = false
+      })
+    },
     onEditorCreated (editor) {
       this.editor = Object.seal(editor)
     },
@@ -523,6 +600,14 @@ export default {
               this.showMessage('error', '布局分辨率异常,请联系管理员')
               return
             }
+            // this.$emit('update-program',{
+            //   id, status, name, resolutionRatio,
+            //   detail: {
+            //     width: Number(width),
+            //     height: Number(height),
+            //     ...JSON.parse(itemJsonStr)
+            //   }
+            // } );
             this.program = {
               id, status, name, resolutionRatio,
               detail: {
@@ -531,14 +616,14 @@ export default {
                 ...JSON.parse(itemJsonStr)
               }
             }
-
+            console.log('progam', this.program)
+            this.initCanvas(this.program.detail)
             // 默认选中第一个
             const widget = this.layers[0]
-            this.chooseWidget(widget, 0)
-
+            this.chooseWidget(widget)
             this.$refs.dialog.show()
           } catch (e) {
-            console.log(e)
+            console.log('catch:', e)
             this.showMessage('error', '布局解析失败')
           }
         })
@@ -770,12 +855,28 @@ export default {
       this.selectedWidget.sources = this.assets
     },
     onConfirm (done) {
-      // if (this.choosen) {
-      //   this.choosen(this.assets)
-      //     .then(done)
-      // } else {
-      done()
-      // }
+      // 检查资源是否都有了
+      // forEach()
+      // 输入名字
+      this.$prompt(
+        '<p class="u-color--black u-font-size--sm u-bold">请输入节目名称</p>',
+        '保存节目',
+        {
+          dangerouslyUseHTMLString: true,
+          closeOnClickModal: false,
+          inputValue: '模板名字',
+          inputPlaceholder: '请输入节目名称',
+          inputPattern: /^.{0,30}$/,
+          inputErrorMessage: '最多30个字符',
+          confirmButtonText: '保存',
+          cancelButtonText: '取消'
+        }
+      ).then(({ value }) => {
+        console.log('value', value)
+        done()
+      }).catch(() => {
+        console.log('cancel')
+      })
     },
     onSetImageDuration () {
       const duration = this.duration
@@ -811,15 +912,15 @@ export default {
       console.log('onView:', source)
       this.$refs.previewDialog.show(source)
     },
-
-    onWidgetClick (widget, index, evt) {
+    onWidgetClick (widget, evt) {
       console.log('onWidgetClick', widget)
       evt.stopPropagation()
-      this.chooseWidget(widget, index)
+      this.chooseWidget(widget)
     },
-    chooseWidget (widget, index) {
+    chooseWidget (widget) {
       if (!this.selectedWidget || this.selectedWidget !== widget) {
         this.selectedWidget = widget
+        console.log('selectedWidget:', widget)
         if (this.selectedWidget.type === 'CText') {
           this.isMedia = false
           this.showText(widget)
@@ -828,7 +929,6 @@ export default {
           this.showMediaChoose(widget)
         }
       }
-      this.selectedWidgetIndex = index
     }
 
   }

+ 13 - 4
src/views/screen/material/program/ast/Viewer.vue

@@ -11,8 +11,12 @@
     />
     <div class="l-flex__none c-viewer__header u-relative u-color--black">
       <div class="c-viewer__wrapper l-flex--row">
-        <span class="l-flex__self c-sibling-item u-font-size--md u-bold u-ellipsis">{{ program.name }}</span>
-        <span class="l-flex__none c-sibling-item near u-color--info u-font-size--xs">{{ program.resolutionRatio }}</span>
+        <span class="l-flex__self c-sibling-item u-font-size--md u-bold u-ellipsis">
+          {{ program.name }}
+        </span>
+        <span class="l-flex__none c-sibling-item near u-color--info u-font-size--xs">
+          {{ program.resolutionRatio }}
+        </span>
         <div
           v-if="hasAudio"
           class="l-flex__none c-sibling-item o-icon o-icon--hover u-pointer"
@@ -32,8 +36,12 @@
     <div class="l-flex__none l-flex">
       <div class="l-flex__none l-flex--col c-viewer__asserts">
         <div class="l-flex__none l-flex--row c-viewer__count has-padding--h">
-          <span class="l-flex__auto u-color--black u-font-size u-bold">资源</span>
-          <span class="l-flex__none u-color--info u-font-size--xs">{{ count }}</span>
+          <span class="l-flex__auto u-color--black u-font-size u-bold">
+            资源
+          </span>
+          <span class="l-flex__none u-color--info u-font-size--xs">
+            {{ count }}
+          </span>
         </div>
         <el-scrollbar
           class="l-flex__fill l-flex--col c-viewer__scrollbar"
@@ -192,6 +200,7 @@ export default {
       this.muted = this.$muted
     },
     checkRatio () {
+      console.log('canvasStyles', this.canvasStyles)
       if (this.canvasStyles) {
         return
       }

+ 2 - 0
src/views/screen/material/program/ast/mixin.js

@@ -48,6 +48,7 @@ export default {
     },
     styles () {
       if (this.node) {
+        console.log('styles------')
         const { width, height } = this.node
         return {
           width: `${width}px`,
@@ -127,6 +128,7 @@ export default {
       }
     },
     checkRatio () {
+      console.log('checkRatio')
       const wrapper = this.$refs.wrapper
       if (wrapper && this.node) {
         const width = wrapper.offsetWidth - this.padding * 2

+ 159 - 0
src/views/screen/material/program/ast/mixin2.js

@@ -0,0 +1,159 @@
+import '@/scss/iconfont/iconfont.css'
+
+import {
+  getAssetUrl,
+  getThumbnailUrl
+} from '@/api/asset'
+import {
+  create,
+  switchToNext
+} from './core/utils'
+import WidgetShortcut from './components/WidgetShortcut.vue'
+import Volume from './components/Volume'
+
+export default {
+  provide () {
+    return {
+      control: this
+    }
+  },
+  components: {
+    WidgetShortcut,
+    Volume
+  },
+  props: {
+    // program: {
+    //   type: Object,
+    //   required: false
+    // }
+  },
+  data () {
+    return {
+      scale: 100,
+      minScale: 100,
+      maxScale: 100,
+      padding: 0,
+      selectedWidgetIndex: -1,
+      node: null,
+      bgm: '',
+      muted: true,
+      program: null
+    }
+  },
+  computed: {
+    transformStyles () {
+      return {
+        transform: `scale(${this.scale / 100})`,
+        'transform-origin': '0 0'
+      }
+    },
+    styles () {
+      if (this.node) {
+        const { width, height } = this.node
+        return {
+          width: `${width}px`,
+          height: `${height}px`
+        }
+      }
+      return null
+    },
+    backgroundStyles () {
+      if (this.node) {
+        const { backgroundImage, backgroundColor } = this.node
+        return {
+          'background-color': backgroundColor,
+          'background-image': backgroundImage[0] ? `url("${getThumbnailUrl(backgroundImage[0], 'size')}")` : 'none'
+        }
+      }
+      return null
+    },
+    widgets () {
+      return this.node?.widgets || []
+    },
+    widget () {
+      return this.widgets[this.selectedWidgetIndex] || this.node
+    },
+    hasAudio () {
+      if (this.node) {
+        if (this.node.bgm.length) {
+          return true
+        }
+        return this.node.widgets.some(widget => widget.mute === 0 && (widget.sources?.length || widget.url))
+      }
+      return false
+    },
+    bgmUrl () {
+      return this.bgm ? getAssetUrl(this.bgm) : null
+    },
+    hasNext () {
+      return !this.muted && this.node?.bgm.length > 1
+    }
+  },
+  watch: {
+    'node.bgm' () {
+      this.setBgm()
+    }
+  },
+  mounted () {
+    if (this.program) {
+      this.initCanvas(this.program.detail)
+      this.checkRatio()
+      window.addEventListener('resize', this.checkRatio)
+    }
+  },
+  methods: {
+    onBack () {
+      window.close()
+    },
+    toggleMute () {
+      this.muted = !this.muted
+    },
+    setBgm () {
+      this.$bgmIndex = -1
+      this.switchBgm()
+    },
+    switchBgm () {
+      const { bgm, toggleType } = this.node
+      this.$bgmIndex = switchToNext(toggleType, bgm, this.$bgmIndex)
+      this.bgm = bgm[this.$bgmIndex]?.keyName
+    },
+    onAudioEnded () {
+      if (this.node.bgm.length > 1) {
+        this.switchBgm()
+      }
+      this.$refs.audio.play()
+    },
+    onAudioError (e) {
+      console.warn('audio error', e)
+      if (this.node?.bgm.length > 1) {
+        this.switchBgm()
+      }
+    },
+    checkRatio () {
+      const wrapper = this.$refs.wrapper
+      if (wrapper && this.node) {
+        const width = wrapper.offsetWidth - this.padding * 2
+        const height = wrapper.offsetHeight - this.padding * 2
+        const { width: cWidth, height: cHeight } = this.node
+        const wScale = width / cWidth
+        const hScale = height / cHeight
+        if (cWidth > width || cHeight > height) {
+          this.scale = Math.min(wScale, hScale) * 100 | 0
+          this.maxScale = Math.max(1, wScale, hScale) * 100 | 0
+        } else {
+          this.scale = 100
+          this.maxScale = Math.max(2, wScale, hScale) * 100 | 0
+        }
+        this.minScale = this.scale
+        console.log('width: layout -> window', cWidth, '->', width, wScale)
+        console.log('height: layout -> window', cHeight, '->', height, hScale)
+        console.log(this.scale, this.maxScale)
+      }
+    },
+    initCanvas (canvas) {
+      console.log('initCanvas', canvas)
+      this.node = create(canvas)
+      console.log('initCanvas', this.node)
+    }
+  }
+}