فهرست منبع

fix: 编写文档

bill 5 ماه پیش
والد
کامیت
de01339a15

+ 23 - 17
src/api/animation.ts

@@ -13,16 +13,17 @@ export interface AnimationAction {
   id: string;
   title: string;
   url: string;
-  action: string
+  action: string;
 }
+
 export type AnimationModelAction = {
   amplitude: number;
   speed: number;
   time: number;
   duration: number;
   id: string;
-  key: string
-  name: string
+  key: string;
+  name: string;
 };
 export type AnimationModelSubtitle = {
   content: string;
@@ -30,12 +31,18 @@ export type AnimationModelSubtitle = {
   time: number;
   id: string;
   background: string;
-  name: string
+  name: string;
 };
 export type AnimationModelFrame = {
   time: number;
   id: string;
-  name: string
+  name: string;
+  mat?: {
+    position?: SceneLocalPos;
+    scale?: number;
+    rotation?: SceneLocalPos;
+    originPosition?: SceneLocalPos;
+  };
   duration?: number;
 };
 export type AnimationModelPath = {
@@ -44,7 +51,7 @@ export type AnimationModelPath = {
   time: number;
   duration: number;
   id: string;
-  name: string
+  name: string;
 };
 
 export interface AnimationModel {
@@ -75,7 +82,7 @@ export const fetchAnimationModels = async () => {
   return [
     {
       id: "1",
-      title: 'dog',
+      title: "dog",
       url: "/animation/dog.glb",
       showTitle: true,
       fontSize: 12,
@@ -96,16 +103,15 @@ export const fetchAnimationModels = async () => {
 
 export const fetchAnimationActions = async () => {
   return [
-    { id: "1", action: 'Walk', title: "走", url: "" },
-    { id: "2", action: 'Run', title: "跑", url: "" },
-    { id: "3", action: 'Climb', title: "爬", url: "" },
-    { id: "2", action: 'JumpUp', title: "向上跳", url: "" },
-    { id: "3", action: 'JumpDown', title: "向下跳", url: "" },
-    { id: "2", action: 'TurnLeft', title: "左转", url: "" },
-    { id: "3", action: 'TurnRight', title: "右转", url: "" },
-    { id: "3", action: 'FallForward', title: "向前倒地", url: "" }, 
-    { id: "3", action: 'FallBackward', title: "向后倒地", url: "" },
-
+    { id: "1", action: "Walk", title: "走", url: "" },
+    { id: "2", action: "Run", title: "跑", url: "" },
+    { id: "3", action: "Climb", title: "爬", url: "" },
+    { id: "2", action: "JumpUp", title: "向上跳", url: "" },
+    { id: "3", action: "JumpDown", title: "向下跳", url: "" },
+    { id: "2", action: "TurnLeft", title: "左转", url: "" },
+    { id: "3", action: "TurnRight", title: "右转", url: "" },
+    { id: "3", action: "FallForward", title: "向前倒地", url: "" },
+    { id: "3", action: "FallBackward", title: "向后倒地", url: "" },
   ];
 };
 

+ 325 - 3
src/components/bill-ui/components/icon/iconfont/demo_index.html

@@ -55,6 +55,90 @@
           <ul class="icon_lists dib-box">
           
             <li class="dib">
+              <span class="icon iconfont">&#xe78a;</span>
+                <div class="name">rectification</div>
+                <div class="code-name">&amp;#xe78a;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe78b;</span>
+                <div class="name">a-zoom</div>
+                <div class="code-name">&amp;#xe78b;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe78c;</span>
+                <div class="name">a-play</div>
+                <div class="code-name">&amp;#xe78c;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe78d;</span>
+                <div class="name">a-animation_s</div>
+                <div class="code-name">&amp;#xe78d;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe78e;</span>
+                <div class="name">keys</div>
+                <div class="code-name">&amp;#xe78e;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe78f;</span>
+                <div class="name">a-anchor</div>
+                <div class="code-name">&amp;#xe78f;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe790;</span>
+                <div class="name">a-monitoring_s</div>
+                <div class="code-name">&amp;#xe790;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe791;</span>
+                <div class="name">a-rotate</div>
+                <div class="code-name">&amp;#xe791;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe792;</span>
+                <div class="name">a-move</div>
+                <div class="code-name">&amp;#xe792;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe793;</span>
+                <div class="name">a-path_s</div>
+                <div class="code-name">&amp;#xe793;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe794;</span>
+                <div class="name">a-pause</div>
+                <div class="code-name">&amp;#xe794;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe795;</span>
+                <div class="name">a-guide_s</div>
+                <div class="code-name">&amp;#xe795;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe788;</span>
+                <div class="name">magnify</div>
+                <div class="code-name">&amp;#xe788;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe789;</span>
+                <div class="name">reduce</div>
+                <div class="code-name">&amp;#xe789;</div>
+              </li>
+          
+            <li class="dib">
               <span class="icon iconfont">&#xe778;</span>
                 <div class="name">pic_path</div>
                 <div class="code-name">&amp;#xe778;</div>
@@ -600,9 +684,9 @@
 <pre><code class="language-css"
 >@font-face {
   font-family: 'iconfont';
-  src: url('iconfont.woff2?t=1734660652855') format('woff2'),
-       url('iconfont.woff?t=1734660652855') format('woff'),
-       url('iconfont.ttf?t=1734660652855') format('truetype');
+  src: url('iconfont.woff2?t=1741331539860') format('woff2'),
+       url('iconfont.woff?t=1741331539860') format('woff'),
+       url('iconfont.ttf?t=1741331539860') format('truetype');
 }
 </code></pre>
           <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@@ -629,6 +713,132 @@
         <ul class="icon_lists dib-box">
           
           <li class="dib">
+            <span class="icon iconfont icon-rectification"></span>
+            <div class="name">
+              rectification
+            </div>
+            <div class="code-name">.icon-rectification
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-a-zoom"></span>
+            <div class="name">
+              a-zoom
+            </div>
+            <div class="code-name">.icon-a-zoom
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-a-play"></span>
+            <div class="name">
+              a-play
+            </div>
+            <div class="code-name">.icon-a-play
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-a-animation_s"></span>
+            <div class="name">
+              a-animation_s
+            </div>
+            <div class="code-name">.icon-a-animation_s
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-keys"></span>
+            <div class="name">
+              keys
+            </div>
+            <div class="code-name">.icon-keys
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-a-anchor"></span>
+            <div class="name">
+              a-anchor
+            </div>
+            <div class="code-name">.icon-a-anchor
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-a-monitoring_s"></span>
+            <div class="name">
+              a-monitoring_s
+            </div>
+            <div class="code-name">.icon-a-monitoring_s
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-a-rotate"></span>
+            <div class="name">
+              a-rotate
+            </div>
+            <div class="code-name">.icon-a-rotate
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-a-move"></span>
+            <div class="name">
+              a-move
+            </div>
+            <div class="code-name">.icon-a-move
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-a-path_s"></span>
+            <div class="name">
+              a-path_s
+            </div>
+            <div class="code-name">.icon-a-path_s
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-a-pause"></span>
+            <div class="name">
+              a-pause
+            </div>
+            <div class="code-name">.icon-a-pause
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-a-guide_s"></span>
+            <div class="name">
+              a-guide_s
+            </div>
+            <div class="code-name">.icon-a-guide_s
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-magnify"></span>
+            <div class="name">
+              magnify
+            </div>
+            <div class="code-name">.icon-magnify
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-reduce"></span>
+            <div class="name">
+              reduce
+            </div>
+            <div class="code-name">.icon-reduce
+            </div>
+          </li>
+          
+          <li class="dib">
             <span class="icon iconfont icon-pic_path"></span>
             <div class="name">
               pic_path
@@ -1449,6 +1659,118 @@
           
             <li class="dib">
                 <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-rectification"></use>
+                </svg>
+                <div class="name">rectification</div>
+                <div class="code-name">#icon-rectification</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-a-zoom"></use>
+                </svg>
+                <div class="name">a-zoom</div>
+                <div class="code-name">#icon-a-zoom</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-a-play"></use>
+                </svg>
+                <div class="name">a-play</div>
+                <div class="code-name">#icon-a-play</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-a-animation_s"></use>
+                </svg>
+                <div class="name">a-animation_s</div>
+                <div class="code-name">#icon-a-animation_s</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-keys"></use>
+                </svg>
+                <div class="name">keys</div>
+                <div class="code-name">#icon-keys</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-a-anchor"></use>
+                </svg>
+                <div class="name">a-anchor</div>
+                <div class="code-name">#icon-a-anchor</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-a-monitoring_s"></use>
+                </svg>
+                <div class="name">a-monitoring_s</div>
+                <div class="code-name">#icon-a-monitoring_s</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-a-rotate"></use>
+                </svg>
+                <div class="name">a-rotate</div>
+                <div class="code-name">#icon-a-rotate</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-a-move"></use>
+                </svg>
+                <div class="name">a-move</div>
+                <div class="code-name">#icon-a-move</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-a-path_s"></use>
+                </svg>
+                <div class="name">a-path_s</div>
+                <div class="code-name">#icon-a-path_s</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-a-pause"></use>
+                </svg>
+                <div class="name">a-pause</div>
+                <div class="code-name">#icon-a-pause</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-a-guide_s"></use>
+                </svg>
+                <div class="name">a-guide_s</div>
+                <div class="code-name">#icon-a-guide_s</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-magnify"></use>
+                </svg>
+                <div class="name">magnify</div>
+                <div class="code-name">#icon-magnify</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-reduce"></use>
+                </svg>
+                <div class="name">reduce</div>
+                <div class="code-name">#icon-reduce</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
                   <use xlink:href="#icon-pic_path"></use>
                 </svg>
                 <div class="name">pic_path</div>

+ 59 - 3
src/components/bill-ui/components/icon/iconfont/iconfont.css

@@ -1,8 +1,8 @@
 @font-face {
   font-family: "iconfont"; /* Project id 4647199 */
-  src: url('iconfont.woff2?t=1734660652855') format('woff2'),
-       url('iconfont.woff?t=1734660652855') format('woff'),
-       url('iconfont.ttf?t=1734660652855') format('truetype');
+  src: url('iconfont.woff2?t=1741331539860') format('woff2'),
+       url('iconfont.woff?t=1741331539860') format('woff'),
+       url('iconfont.ttf?t=1741331539860') format('truetype');
 }
 
 .iconfont {
@@ -13,6 +13,62 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-rectification:before {
+  content: "\e78a";
+}
+
+.icon-a-zoom:before {
+  content: "\e78b";
+}
+
+.icon-a-play:before {
+  content: "\e78c";
+}
+
+.icon-a-animation_s:before {
+  content: "\e78d";
+}
+
+.icon-keys:before {
+  content: "\e78e";
+}
+
+.icon-a-anchor:before {
+  content: "\e78f";
+}
+
+.icon-a-monitoring_s:before {
+  content: "\e790";
+}
+
+.icon-a-rotate:before {
+  content: "\e791";
+}
+
+.icon-a-move:before {
+  content: "\e792";
+}
+
+.icon-a-path_s:before {
+  content: "\e793";
+}
+
+.icon-a-pause:before {
+  content: "\e794";
+}
+
+.icon-a-guide_s:before {
+  content: "\e795";
+}
+
+.icon-magnify:before {
+  content: "\e788";
+}
+
+.icon-reduce:before {
+  content: "\e789";
+}
+
 .icon-pic_path:before {
   content: "\e778";
 }

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
src/components/bill-ui/components/icon/iconfont/iconfont.js


+ 98 - 0
src/components/bill-ui/components/icon/iconfont/iconfont.json

@@ -6,6 +6,104 @@
   "description": "",
   "glyphs": [
     {
+      "icon_id": "43549167",
+      "name": "rectification",
+      "font_class": "rectification",
+      "unicode": "e78a",
+      "unicode_decimal": 59274
+    },
+    {
+      "icon_id": "43549165",
+      "name": "a-zoom",
+      "font_class": "a-zoom",
+      "unicode": "e78b",
+      "unicode_decimal": 59275
+    },
+    {
+      "icon_id": "43549159",
+      "name": "a-play",
+      "font_class": "a-play",
+      "unicode": "e78c",
+      "unicode_decimal": 59276
+    },
+    {
+      "icon_id": "43549156",
+      "name": "a-animation_s",
+      "font_class": "a-animation_s",
+      "unicode": "e78d",
+      "unicode_decimal": 59277
+    },
+    {
+      "icon_id": "43549164",
+      "name": "keys",
+      "font_class": "keys",
+      "unicode": "e78e",
+      "unicode_decimal": 59278
+    },
+    {
+      "icon_id": "43549163",
+      "name": "a-anchor",
+      "font_class": "a-anchor",
+      "unicode": "e78f",
+      "unicode_decimal": 59279
+    },
+    {
+      "icon_id": "43549160",
+      "name": "a-monitoring_s",
+      "font_class": "a-monitoring_s",
+      "unicode": "e790",
+      "unicode_decimal": 59280
+    },
+    {
+      "icon_id": "43549162",
+      "name": "a-rotate",
+      "font_class": "a-rotate",
+      "unicode": "e791",
+      "unicode_decimal": 59281
+    },
+    {
+      "icon_id": "43549161",
+      "name": "a-move",
+      "font_class": "a-move",
+      "unicode": "e792",
+      "unicode_decimal": 59282
+    },
+    {
+      "icon_id": "43549158",
+      "name": "a-path_s",
+      "font_class": "a-path_s",
+      "unicode": "e793",
+      "unicode_decimal": 59283
+    },
+    {
+      "icon_id": "43549157",
+      "name": "a-pause",
+      "font_class": "a-pause",
+      "unicode": "e794",
+      "unicode_decimal": 59284
+    },
+    {
+      "icon_id": "43549155",
+      "name": "a-guide_s",
+      "font_class": "a-guide_s",
+      "unicode": "e795",
+      "unicode_decimal": 59285
+    },
+    {
+      "icon_id": "43549168",
+      "name": "magnify",
+      "font_class": "magnify",
+      "unicode": "e788",
+      "unicode_decimal": 59272
+    },
+    {
+      "icon_id": "43549166",
+      "name": "reduce",
+      "font_class": "reduce",
+      "unicode": "e789",
+      "unicode_decimal": 59273
+    },
+    {
       "icon_id": "42880568",
       "name": "pic_path",
       "font_class": "pic_path",

BIN
src/components/bill-ui/components/icon/iconfont/iconfont.ttf


BIN
src/components/bill-ui/components/icon/iconfont/iconfont.woff


BIN
src/components/bill-ui/components/icon/iconfont/iconfont.woff2


+ 2 - 2
src/components/drawing-time-line/action.vue

@@ -68,10 +68,10 @@ const getTextConfig = (ndx: number) => {
 const invConfig = useViewerInvertTransformConfig();
 const rects = computed(() => {
   return props.items.map((item) => {
-    const origin = { x: item.time * misPixel, y: props.top };
+    const origin = { x: item.time * misPixel, y: props.top + 1 };
     const end = {
       x: (item.time + item.duration) * misPixel,
-      y: props.top + 30,
+      y: props.top + 28,
     };
 
     return {

+ 22 - 0
src/components/drawing-time-line/empty.vue

@@ -0,0 +1,22 @@
+<template>
+  <v-text
+    :config="{
+      text: '未添加动画',
+      height: size?.height,
+      width: size?.width,
+      fill: '#fff',
+      fontSize: 14,
+      opacity: 0.3,
+      align: 'center',
+      verticalAlign: 'middle',
+      ...invConfig,
+      y: 20,
+    }"
+  />
+</template>
+<script lang="ts" setup>
+import { useGlobalResize, useViewerInvertTransformConfig } from "../drawing/hook";
+
+const { size } = useGlobalResize();
+const invConfig = useViewerInvertTransformConfig();
+</script>

+ 2 - 1
src/components/drawing-time-line/index.vue

@@ -4,7 +4,7 @@
       width: size?.width,
       height: height,
       fill: background ? background : '#000',
-      opacity: background ? 1 : 0,
+      opacity: opacity,
       ...bgConfig,
     }"
   />
@@ -55,6 +55,7 @@ const props = defineProps<{
   itemsRenderer: any;
   background?: string;
   height: number;
+  opacity: number;
   top: number;
   active?: TLItem;
 }>();

+ 2 - 2
src/components/drawing-time/current.vue

@@ -52,7 +52,7 @@ watch(drag, (drag) => {
   const offsetX = drag.x;
 
   const currentX = props.currentTime * misPixel + offsetX;
-  emit("update:currentTime", currentX / misPixel);
+  currentX >= 0 && emit("update:currentTime", currentX / misPixel);
 });
 
 const invConfig = useViewerInvertTransformConfig();
@@ -74,7 +74,7 @@ watch(
     return currentX.value;
   },
   (x) => {
-    if (!x) return;
+    if (typeof x !== "number") return;
     const currentPixel = viewerMat.value.point({ x: currentX.value, y: 0 }).x;
     const offsetX = size.value!.width / 2 - currentPixel;
     viewer.movePixel({ x: offsetX, y: 0 });

+ 2 - 2
src/components/drawing-time/time.vue

@@ -1,5 +1,5 @@
 <template>
-  <template v-if="shapeConfig">
+  <v-group v-if="shapeConfig">
     <v-line v-for="line in shapeConfig.lines" :config="line" />
     <v-line
       :config="{
@@ -14,7 +14,7 @@
     />
     <v-text v-for="texConfig in shapeConfig.texts" :config="{ ...texConfig }" />
     <slot />
-  </template>
+  </v-group>
 </template>
 
 <script setup lang="ts">

+ 50 - 42
src/components/materials/index.vue

@@ -25,7 +25,7 @@
               type="file"
             >
               <template v-slot:replace>
-                <Button type="primary" ghost>
+                <Button type="primary" ghost v-if="!readonly">
                   <ui-icon type="add" class="icon" />上传文件
                 </Button>
               </template>
@@ -96,7 +96,7 @@
 
 <script lang="ts" setup>
 import { Modal, Input, Table, Empty, TableProps, Button } from "ant-design-vue";
-import { computed, reactive, ref, watch } from "vue";
+import { computed, reactive, readonly, ref, watch } from "vue";
 import { createLoadPack, debounceStack, getSizeStr } from "@/utils";
 import type { PagingResult } from "@/api";
 import {
@@ -117,6 +117,7 @@ const props = defineProps<{
   maxSize?: number;
   visible: boolean;
   count?: number;
+  readonly?: boolean;
   afterClose?: () => void;
 }>();
 
@@ -170,46 +171,53 @@ const rowSelection: any = ref({
     };
   },
 });
-const cloumns = computed(() => [
-  {
-    title: "名称",
-    dataIndex: "name",
-    key: "name",
-  },
-  {
-    width: "100px",
-    title: "格式",
-    dataIndex: "format",
-    key: "format",
-  },
-  {
-    width: "100px",
-    title: "大小",
-    dataIndex: "size",
-    key: "size",
-  },
-  {
-    width: "100px",
-    title: "状态",
-    dataIndex: "status",
-    key: "status",
-  },
-  {
-    width: "100px",
-    title: "分组",
-    dataIndex: "group",
-    key: "group",
-    filters: groups.value.map((g) => ({
-      text: g.name,
-      value: g.id,
-    })),
-  },
-  {
-    width: "100px",
-    title: "操作",
-    key: "action",
-  },
-]);
+const cloumns = computed(() => {
+  const cloumns = [
+    {
+      title: "名称",
+      dataIndex: "name",
+      key: "name",
+    },
+    {
+      width: "100px",
+      title: "格式",
+      dataIndex: "format",
+      key: "format",
+    },
+    {
+      width: "100px",
+      title: "大小",
+      dataIndex: "size",
+      key: "size",
+    },
+    {
+      width: "100px",
+      title: "状态",
+      dataIndex: "status",
+      key: "status",
+    },
+    {
+      width: "100px",
+      title: "分组",
+      dataIndex: "group",
+      key: "group",
+      filters: props.readonly
+        ? undefined
+        : groups.value.map((g) => ({
+            text: g.name,
+            value: g.id,
+          })),
+    },
+  ];
+  if (!props.readonly) {
+    cloumns.push({
+      width: "100px",
+      title: "操作",
+      key: "action",
+    } as any);
+  }
+  return cloumns;
+});
 
 const fetchData = createLoadPack(() =>
   Promise.all([fetchMaterialGroups(), fetchMaterialPage(params)])

+ 1 - 0
src/components/materials/quisk.ts

@@ -8,6 +8,7 @@ export const selectMaterials = async (props: {
   format?: string[];
   maxSize?: number;
   count?: number
+  readonly?: boolean;
 } = {}) => {
   return new Promise<Material[] | null>((resolve) => {
     const mprops = reactive({

+ 1 - 0
src/main.ts

@@ -14,6 +14,7 @@ import "@/assets/style/global.less";
 const app = createApp(App);
 app.use(Components);
 app.use(router);
+app.use(VueKonva);
 app.mount("#app");
 
 if (import.meta.env.DEV) {

+ 195 - 88
src/sdk/sdk.ts

@@ -13,7 +13,13 @@ import {
   Scene,
 } from "@/store";
 import type { Emitter } from "mitt";
-import { TaggingPositionType } from "@/api";
+import {
+  AnimationModel,
+  AnimationModelAction,
+  AnimationModelFrame,
+  AnimationModelPath,
+  TaggingPositionType,
+} from "@/api";
 export enum SettingResourceType {
   map = "map",
   color = "color",
@@ -42,7 +48,7 @@ export type SceneModel = ToChangeAPI<SceneModelAttrs> & {
   enterRotateMode: () => void;
   enterMoveMode: () => void;
   leaveTransform: () => void;
-  getDefaultRotation: () => SceneLocalPos
+  getDefaultRotation: () => SceneLocalPos;
   enterAlignment: () => void;
   leaveAlignment: () => void;
   enterScaleSet: () => ScaleSet;
@@ -95,8 +101,8 @@ export interface CameraComeToProps {
   dur?: number;
   modelId?: FuseModel["id"];
   distance?: 1 | 2 | 3;
-  maxDis?:number
-  isFlyToTag?: boolean
+  maxDis?: number;
+  isFlyToTag?: boolean;
 }
 
 export type CalcPathProps = [
@@ -164,8 +170,8 @@ export interface SDK {
   switchScene: (
     scene: { type: SceneType; num: string } | null
   ) => Promise<void>;
-  startAddSth: () => void
-  endAddSth: () => void
+  startAddSth: () => void;
+  endAddSth: () => void;
   addModel: (props: AddModelProps) => SceneModel;
   setCameraFov: (fov: number) => void;
   enableMap(dom: HTMLDivElement, latlng: number[]): void;
@@ -182,7 +188,9 @@ export interface SDK {
   getPositionByScreen: (
     screenPos: ScreenLocalPos,
     modelId?: FuseModel["id"]
-  ) => (ScenePos & { worldPos: SceneLocalPos, localNormal: SceneLocalPos }) | null;
+  ) =>
+    | (ScenePos & { worldPos: SceneLocalPos; localNormal: SceneLocalPos })
+    | null;
   getScreenByPosition: (
     localPos: SceneLocalPos,
     modelId?: FuseModel["id"]
@@ -190,7 +198,7 @@ export interface SDK {
   screenshot: (width: number, height: number) => Promise<string>;
   getPose: () => Pose;
   comeTo: (pos: CameraComeToProps) => void;
-  
+
   enterSceneGuide: (data: SceneGuidePath[]) => SceneGuide;
 
   drawMeasure<T extends StoreMeasure["type"]>(
@@ -200,39 +208,41 @@ export interface SDK {
   ): Measure<T>;
   startMeasure<T extends StoreMeasure["type"]>(type: T): StartMeasure<T>;
 
-  createTagging: (props: Tagging3DProps) => Tagging3D
+  createTagging: (props: Tagging3DProps) => Tagging3D;
+
+  createPath: (props: PathProps) => Path;
 
-  createPath: (props: PathProps) => Path
+  createAnimationGroup: () => AnimationGroup
 }
 
 export type PathProps = {
   // 线段名称
-  name: string,
+  name: string;
   // 是否显示名称,
-  showName: boolean,
+  showName: boolean;
   // 文字大小
-  fontSize: number,
+  fontSize: number;
   // 是否显示方向,
-  showDirection: boolean,
+  showDirection: boolean;
   // 方向是否反向
-  reverseDirection: boolean,
+  reverseDirection: boolean;
   line: {
-    width: number,
-    color: string,
-    altitudeAboveGround: number
-    position?: SceneLocalPos,
-    modelId?: string
-  },
+    width: number;
+    color: string;
+    altitudeAboveGround: number;
+    position?: SceneLocalPos;
+    modelId?: string;
+  };
   points: {
     // 点位名称
-    name: string,
-    position: SceneLocalPos,
-    modelId: string,
-  }[]
-}
+    name: string;
+    position: SceneLocalPos;
+    modelId: string;
+  }[];
+};
 export type Path = {
   bus: Emitter<{
-    activePoint: number
+    activePoint: number;
     // 标注点击事件
     click: void;
     // 鼠标移入标注事件
@@ -241,67 +251,69 @@ export type Path = {
     leave: void;
     // 线段坐标更改事件
     linePositionChange: {
-      pos: SceneLocalPos,
-      modelId: string
-    }
-    focus: boolean
+      pos: SceneLocalPos;
+      modelId: string;
+    };
+    focus: boolean;
     // 路径点位置变更
-    changePoints: PathProps['points']
-    drawed: void
+    changePoints: PathProps["points"];
+    drawed: void;
   }>;
-  changeDirection: ( show: boolean,  reverse: boolean ) => void
-  changeFontSize: (fontSize: number) => void
-  focus: (f: boolean) => void
+  changeDirection: (show: boolean, reverse: boolean) => void;
+  changeFontSize: (fontSize: number) => void;
+  focus: (f: boolean) => void;
   highlight: (f: boolean) => void;
-  changeVisibilityRange: (range: number) => void
-  changePointName: (index: number, name: string) => void
+  changeVisibilityRange: (range: number) => void;
+  changePointName: (index: number, name: string) => void;
   // 飞向路径
-  fly: () => void,
+  fly: () => void;
   // 更改路径点
-  changePathPoints: (points: Omit<PathProps['points'][number], 'name'>[]) => void
+  changePathPoints: (
+    points: Omit<PathProps["points"][number], "name">[]
+  ) => void;
   // 播放路径,相机沿着路径运动,传入播放完毕回调
-  play: (playedHandler: () => void) => void
+  play: (playedHandler: () => void) => void;
   // 停止播放路径
-  pause: () => void
+  pause: () => void;
   // 是否可编辑
-  changeCanEdit: (canMove: boolean) => void
-  deletePoint: (index: number) => void
-  changeEditMode: (editMode: boolean) => void
+  changeCanEdit: (canMove: boolean) => void;
+  deletePoint: (index: number) => void;
+  changeEditMode: (editMode: boolean) => void;
   // 可见性
-  visibility: (visibility: boolean) => void
+  visibility: (visibility: boolean) => void;
   // 气泡是否可见
-  visibilityName: (visibility: boolean) => void
+  visibilityName: (visibility: boolean) => void;
   // 更改标题气泡属性
-  changeLine: (props: Partial<PathProps['line']>) => void
+  changeLine: (props: Partial<PathProps["line"]>) => void;
   // 更改标题气泡属性
-  changeName: (name: string) => void
+  changeName: (name: string) => void;
   // 线段销毁
-  destroy: () => void
-}
+  destroy: () => void;
+};
 
 export type Tagging3DProps = {
-  lineHeight: number
-  fontSize: number,
+  lineHeight: number;
+  fontSize: number;
   // 标题
-  title: string
+  title: string;
   // 标注类型 2d | 3d
-  type: TaggingPositionType,
+  type: TaggingPositionType;
   // 模型id
-  modelId: string,
+  modelId: string;
   // 贴地射线获取的位置
-  position: SceneLocalPos
-  normal: SceneLocalPos
+  position: SceneLocalPos;
+  normal: SceneLocalPos;
   // 是否可以移动
-  canMove: boolean,
+  canMove: boolean;
   // 贴地图片url
-  image: string
-  
+  image: string;
+
   // 贴地图片的变换
   mat: {
-    scale: number,
-    rotation: number,
-  }
-}
+    scale: number;
+    rotation: number;
+  };
+};
 export type Tagging3D = {
   bus: Emitter<{
     // 标注点击事件
@@ -311,44 +323,139 @@ export type Tagging3D = {
     // 鼠标移出标注事件
     leave: void;
     // 位置变更
-    changePosition: {pos: SceneLocalPos, modelId: string, normal: SceneLocalPos}
+    changePosition: {
+      pos: SceneLocalPos;
+      modelId: string;
+      normal: SceneLocalPos;
+    };
   }>;
-  changePosition: (position: { 
-    modelId: string,
+  changePosition: (position: {
+    modelId: string;
     // 贴地射线获取的位置
-    position: SceneLocalPos
-    normal: SceneLocalPos
-  }) => void
-  changeFontSize: (fontSize: number) => void
-  changeLineHeight: (lineHeight: number) => void
+    position: SceneLocalPos;
+    normal: SceneLocalPos;
+  }) => void;
+  changeFontSize: (fontSize: number) => void;
+  changeLineHeight: (lineHeight: number) => void;
   // 设置标题
-  changeTitle: (title: string) => void
+  changeTitle: (title: string) => void;
   // 标题是否可见
-  visibilityTitle: (visibility: boolean) => void
+  visibilityTitle: (visibility: boolean) => void;
   // 更改可拖拽移动
-  changeCanMove: (canMove: boolean) => void
+  changeCanMove: (canMove: boolean) => void;
   // 获取图标中心三维坐标
-  getImageCenter: () => SceneLocalPos
+  getImageCenter: () => SceneLocalPos;
   // 更改图标
-  changeImage: (url: string) => void
+  changeImage: (url: string) => void;
   // 标注可见性
-  visibility: (visibility: boolean) => void
+  visibility: (visibility: boolean) => void;
   // 标注图片变换,传入变换
-  changeMat: (props: Tagging3DProps['mat']) => void
+  changeMat: (props: Tagging3DProps["mat"]) => void;
   // 更改热点类型
-  changeType: (val: TaggingPositionType) => void
+  changeType: (val: TaggingPositionType) => void;
   // 距离相机位置
-  getCameraDisSquared: () => number
+  getCameraDisSquared: () => number;
   // 标注销毁
-  destory: () => void
-}
+  destory: () => void;
+};
+
+// 动画组对象
+export type AnimationGroup = {
+  // 播放
+  play: () => void;
+  // 暂停
+  pause: () => void;
+  // 添加动画模型
+  addAnimationModel: (data: AnimationModel) => AnimationModel3D;
+
+  // 设置当前时间, 单位为秒
+  setCurrentTime: (s: number) => void
+};
+
+export type AnimationModel3D = {
+  // 销毁动画模型
+  destory: () => void;
+  // 更改动画模型可见性
+  visibility: (show: boolean) => void;
+  // 更改动画可见范围  不传为全局可见
+  changeVisibilityRange: (range?: number) => void;
+  // 更改模型名称
+  changeTitle: (name: string) => void;
+  // 更改名称字体大小
+  changeFontSize: (size: number) => void;
+  // 更改名称可见性
+  visibilityTitle: (show: boolean) => void;
+
+  // 添加模型帧
+  addFrame: (frame: AnimationModelFrame) => AnimationModelFrame3D;
+  // 添加模型动作
+  addAction: (frame: AnimationModelAction) => AnimationModelAction3D;
+  // 添加模型路径
+  addPath: (frame: Omit<AnimationModelPath, 'pathId'> & {path: Path}) => AnimationModelPath3D;
+
+  // 获取当前模型旁白出现的适合位置,传入旁边dom的宽高,返回像素位置
+  getCurrentSubtitlePixel: (size: {width: number, height: number}) => {x: number, y: number}
+  // 获取当前时间改模型的姿态
+  getCurrentMat: () => {
+    position?: SceneLocalPos;
+    scale?: number;
+    rotation?: SceneLocalPos;
+    originPosition?: SceneLocalPos
+  }
+  // 设置当前操控模式, translate rotate scale originTranslate
+  setCurrentMode: (mode?: string) => void
+};
+
+export type AnimationModelFrame3D = {
+  // 销毁动画模型帧
+  destory: () => void;
+  // 修改帧播放时间 单位为秒
+  changeTime: (s: number) => void
+  // 动画帧姿态修改数据
+  bus: Emitter<{
+    matChange: {
+      position?: SceneLocalPos;
+      scale?: number;
+      rotation?: SceneLocalPos;
+      originPosition?: SceneLocalPos
+    };
+  }>;
+};
+
+export type AnimationModelAction3D = {
+  // 销毁动画模型动作
+  destory: () => void;
+  // 修改动作播放时间 单位为秒
+  changeTime: (s: number) => void
+  // 修改动作幅度  
+  changeAmplitude: (n: number) => void
+  // 修改动作速度
+  changeSpeed: (n: number) => void
+  // 修改动持续时间 单位为秒
+  changeDuration: (n: number) => void
+};
+
+
+export type AnimationModelPath3D = {
+  // 销毁动画模型路径
+  destory: () => void;
+  // 修改路径 传入参数为你之前返回的路径对象
+  changePath: (path: Path) => void
+  // 修改播放是否要反向
+  changeReverse: (reverse: boolean) => void
+  // 修改路径播放时间 单位为秒
+  changeTime: (s: number) => void
+  // 修改路径续时间 单位为秒
+  changeDuration: (n: number) => void
+};
+
 
 export let sdk: SDK;
 export type InialSDKProps = {
-  laserRoot?: string
-  ossRoot?: string
-  laserOSSRoot?: string
-  panoOSSRoot?: string
+  laserRoot?: string;
+  ossRoot?: string;
+  laserOSSRoot?: string;
+  panoOSSRoot?: string;
   layout: HTMLDivElement;
   scenes: Scene[];
   lonlat?: number[];

+ 107 - 34
src/views/animation/bottom.vue

@@ -2,10 +2,24 @@
   <ui-editor-toolbar toolbar class="animation-toolbar">
     <div class="top-bar">
       <div class="play-bar">
-        <ui-icon type="close" ctrl @click="play = !play" />
+        <ui-icon
+          :type="play ? 'a-pause' : 'a-play'"
+          ctrl
+          @click="
+            () => {
+              play = !play;
+              $emit('update:follow', play);
+            }
+          "
+        />
       </div>
       <div class="scale-bar">
-        <ui-icon type="close" class="icon" ctrl />
+        <ui-icon
+          type="reduce"
+          class="icon"
+          ctrl
+          @click="scale = Math.max(0.5, scale - 0.5)"
+        />
         <Slider
           class="slider"
           v-model:value="scale"
@@ -14,36 +28,52 @@
           :step="0.01"
           :tooltipOpen="false"
         />
-        <ui-icon type="close" class="icon" ctrl />
+        <ui-icon
+          type="magnify"
+          class="icon"
+          ctrl
+          @click="scale = Math.min(8, scale + 0.5)"
+        />
       </div>
     </div>
     <div class="oper-bar" :class="{ disabled: play }">
       <Renderer v-model:scale="scale">
-        <TimeLine
-          v-for="prop in tlProps"
-          :items="am[prop.attr]"
-          :height="prop.height"
-          :top="prop.top"
-          :itemsRenderer="prop.component"
-          @update="({ ndx, time }) => (am[prop.attr][ndx].time = time)"
-          @add="
-            (item) => {
-              am[prop.attr].push(item);
-              $emit('update:active', { key: prop.attr, ndx: am[prop.attr].length - 1 });
-            }
-          "
-          @del="(ndx) => am[prop.attr].splice(ndx, 1)"
-          :active="prop.attr === active?.key ? am[prop.attr][active.ndx] : undefined"
-          @update:active="(active: any) => $emit('update:active', active && { key: prop.attr, ndx: am[prop.attr].indexOf(active) })"
-        />
-
-        <Time @update-current-time="(time) => $emit('update:currentTime', time)">
-          <TimeCurrent
-            :currentTime="currentTime"
-            @update:current-time="(time) => $emit('update:currentTime', time)"
-            :follow="play"
-          />
-        </Time>
+        <v-group>
+          <template v-for="prop in tlProps">
+            <TimeLine
+              v-if="am[prop.attr].length"
+              :items="am[prop.attr]"
+              :height="prop.height"
+              :background="prop.background"
+              :opacity="prop.opacity"
+              :top="prop.top"
+              :itemsRenderer="prop.component"
+              @update="({ ndx, time }) => (am[prop.attr][ndx].time = time)"
+              @add="
+                (item) => {
+                  am[prop.attr].push(item);
+                  $emit('update:active', {
+                    key: prop.attr,
+                    ndx: am[prop.attr].length - 1,
+                  });
+                }
+              "
+              @del="(ndx) => am[prop.attr].splice(ndx, 1)"
+              :active="prop.attr === active?.key ? am[prop.attr][active.ndx] : undefined"
+              @update:active="(active: any) => $emit('update:active', active && { key: prop.attr, ndx: am[prop.attr].indexOf(active) })"
+            />
+          </template>
+          <empty v-if="!count" />
+        </v-group>
+        <v-group>
+          <Time @update-current-time="(time) => $emit('update:currentTime', time)">
+            <TimeCurrent
+              :currentTime="currentTime"
+              @update:current-time="(time) => $emit('update:currentTime', time)"
+              :follow="follow"
+            />
+          </Time>
+        </v-group>
       </Renderer>
     </div>
   </ui-editor-toolbar>
@@ -51,7 +81,7 @@
 
 <script lang="ts" setup>
 import { Slider } from "ant-design-vue";
-import { ref, watch } from "vue";
+import { computed, ref, watch } from "vue";
 import { AnimationModel } from "@/store/animation";
 import Renderer from "@/components/drawing/renderer.vue";
 import Time from "@/components/drawing-time/time.vue";
@@ -59,23 +89,62 @@ import TimeCurrent from "@/components/drawing-time/current.vue";
 import TimeLine from "@/components/drawing-time-line/index.vue";
 import TimeLineFrame from "@/components/drawing-time-line/frame.vue";
 import TimeLineAction from "@/components/drawing-time-line/action.vue";
+import empty from "@/components/drawing-time-line/empty.vue";
 import { Active } from "./type";
 
-const props = defineProps<{ am: AnimationModel; active?: Active; currentTime: number }>();
+const props = defineProps<{
+  am: AnimationModel;
+  active?: Active;
+  currentTime: number;
+  follow: boolean;
+}>();
 const emit = defineEmits<{
   (e: "update:active", data: Active | undefined): void;
+  (e: "update:follow", data: boolean): void;
   (e: "update:currentTime", v: number): void;
 }>();
 
 const scale = ref(1);
 
 const tlProps = [
-  { attr: "frames", component: TimeLineFrame, height: 30, top: 24 },
-  { attr: "actions", component: TimeLineAction, height: 30, top: 65 },
-  { attr: "subtitles", component: TimeLineAction, height: 30, top: 105 },
-  { attr: "paths", component: TimeLineAction, height: 30, top: 140 },
+  {
+    attr: "frames",
+    component: TimeLineFrame,
+    height: 30,
+    top: 24,
+    background: "#000",
+    opacity: 0.5,
+  },
+  {
+    attr: "actions",
+    component: TimeLineAction,
+    height: 30,
+    top: 65,
+    background: "#000",
+    opacity: 0.5,
+  },
+  {
+    attr: "subtitles",
+    component: TimeLineAction,
+    height: 30,
+    top: 105,
+    background: "#000",
+    opacity: 0.5,
+  },
+  {
+    attr: "paths",
+    component: TimeLineAction,
+    height: 30,
+    top: 145,
+    background: "#000",
+    opacity: 0.5,
+  },
 ] as const;
 
+const count = computed(() =>
+  Object.values(tlProps).reduce((t, c) => t + props.am[c.attr].length, 0)
+);
+
 const play = ref(false);
 
 watch(play, (_a, _b, onCleanup) => {
@@ -104,6 +173,9 @@ watch(play, (_a, _b, onCleanup) => {
     flex: 1;
     display: flex;
     justify-content: center;
+    .icon {
+      font-size: 16px;
+    }
   }
   .scale-bar {
     width: 180px;
@@ -126,6 +198,7 @@ watch(play, (_a, _b, onCleanup) => {
     }
     .icon {
       margin: 0 5px;
+      font-size: 16px;
     }
   }
 }

+ 21 - 8
src/views/animation/index.vue

@@ -10,10 +10,12 @@
     <Right
       v-if="focusAM"
       :am="focusAM"
+      :frameAction="frameAction"
+      @change-frame-action="(f) => (frameAction = f.action)"
       class="animation-right"
       v-model:activeAttrib="activeAttrib"
       @add-frame="add('frames')"
-      @add-path="add('paths', { reverse: false })"
+      @add-path="(preset) => add('paths', { reverse: false, ...preset })"
       @add-subtitle="add('subtitles', { content: '', background: '#fff' })"
       @add-action="(preset) => add('actions', preset)"
       @apply-global="k => ams.forEach((am: any) => (am[k] = focusAM![k]))"
@@ -21,6 +23,7 @@
     <Bottom
       v-if="focusAM"
       :am="focusAM"
+      v-model:follow="follow"
       v-model:current-time="currentTime"
       class="animation-toolbar"
       v-model:active="activeAttrib"
@@ -42,7 +45,7 @@ import {
   initAnimationActions,
   initialAnimationModels,
 } from "@/store/animation";
-import { reactive, ref, watch, watchEffect } from "vue";
+import { nextTick, reactive, ref, watch } from "vue";
 import { Active } from "./type";
 import { getAddTLItemAttr } from "@/components/drawing-time-line/check";
 import { Message } from "bill/expose-common";
@@ -57,6 +60,8 @@ useViewStack(autoSaveAnimationModel);
 const focusAM = ref<AnimationModel>();
 const activeAttrib = ref<Active>();
 const currentTime = ref(0);
+const follow = ref(false);
+const frameAction = ref<string>();
 
 const updateFocus = (am?: AnimationModel) => {
   activeAttrib.value = undefined;
@@ -66,14 +71,22 @@ const updateFocus = (am?: AnimationModel) => {
 watch(activeAttrib, (_a, _b, onCleanup) => {
   if (!activeAttrib.value) return;
   const cur = focusAM.value![activeAttrib.value.key][activeAttrib.value.ndx];
+  const updateFocus = () => {
+    const rang = [cur.time, cur.time + (cur.duration || 0)];
+    if (currentTime.value < rang[0] || currentTime.value > rang[1]) {
+      activeAttrib.value = undefined;
+    }
+  };
+
+  follow.value = true;
   currentTime.value = cur.time!;
+  nextTick(() => (follow.value = false));
+
   onCleanup(
-    watch(currentTime, () => {
-      const rang = [cur.time, cur.time + (cur.duration || 0)];
-      if (currentTime.value < rang[0] || currentTime.value > rang[1]) {
-        activeAttrib.value = undefined;
-      }
-    })
+    watch(
+      () => [currentTime.value, cur.time, cur.time + (cur.duration || 0)],
+      updateFocus
+    )
   );
 });
 

+ 1 - 0
src/views/animation/left.vue

@@ -101,6 +101,7 @@ const selectModel = async () => {
     uploadFormat: ["animation-model"],
     format: ["glb"],
     maxSize: 2 * 1024 * 1024 * 1024,
+    readonly: true,
   });
   if (!list?.length) return;
   list.forEach((item) => {

+ 43 - 4
src/views/animation/right/am.vue

@@ -53,13 +53,13 @@
         <ui-group-option class="item">
           <span class="label">加帧</span>
           <span class="oper" @click="$emit('addFrame')">
-            <ui-icon type="add" ctrl />
+            <ui-icon type="keys" ctrl />
           </span>
         </ui-group-option>
         <ui-group-option class="item">
           <span class="label">路径</span>
           <span class="oper">
-            <ui-icon @click="$emit('addPath')" type="add" ctrl />
+            <ui-icon @click="visibleSelectPath = true" type="add" ctrl />
           </span>
         </ui-group-option>
         <ui-group-option class="item">
@@ -85,21 +85,60 @@
       </ui-group>
     </TabPane>
   </Tabs>
+
+  <Modal
+    width="400px"
+    title="选择路径"
+    :open="visibleSelectPath"
+    @ok="selectPathHandler"
+    @cancel="visibleSelectPath = false"
+    okText="确定"
+    cancelText="取消"
+    class="model-table"
+  >
+    <div style="margin: 20px 0">
+      <ui-input
+        width="100%"
+        type="select"
+        :options="options"
+        placeholder="请选择路径"
+        v-model="pathId"
+      />
+    </div>
+  </Modal>
 </template>
 
 <script lang="ts" setup>
 import { Switch, Slider, TabPane, Tabs } from "ant-design-vue";
 import { AnimationModel } from "@/api";
 import SignItem from "@/views/tagging-position/sign-item.vue";
-import { ref } from "vue";
+import { computed, ref } from "vue";
 import { amActions } from "@/store/animation";
+import { paths } from "@/store/path";
+import Message from "bill/components/message/message.vue";
+import { Modal } from "ant-design-vue";
 
 defineProps<{ am: AnimationModel }>();
-defineEmits<{
+const emit = defineEmits<{
   (e: "addFrame" | "addPath" | "addSubtitle" | "addAction", preset?: any): void;
   (e: "applyGlobal", d: keyof AnimationModel): void;
 }>();
 const activeKey = ref("setting");
+
+const options = computed(() =>
+  paths.value.map((item) => ({ label: item.name, value: item.id }))
+);
+const pathId = ref<string>();
+const visibleSelectPath = ref(false);
+const selectPathHandler = () => {
+  if (!pathId.value) {
+    Message.error("请选择路径");
+    return;
+  }
+  const name = options.value.find(({ value }) => value === pathId.value)!.label;
+  emit("addPath", { name });
+  visibleSelectPath.value = false;
+};
 </script>
 
 <style scoped lang="scss">

+ 9 - 7
src/views/animation/right/frame.vue

@@ -21,13 +21,12 @@
 
 <script lang="ts" setup>
 import { AnimationModelFrame } from "@/api";
-import { ref } from "vue";
 
 const actions = [
-  { key: "translate", icon: "close" },
-  { key: "rotate", icon: "close" },
-  { key: "scale", icon: "close" },
-  { key: "originTranslate", icon: "close" },
+  { key: "translate", icon: "a-move" },
+  { key: "rotate", icon: "a-rotate" },
+  { key: "scale", icon: "a-zoom" },
+  { key: "originTranslate", icon: "a-anchor" },
 ];
 
 defineProps<{ data: AnimationModelFrame; frameAction?: string }>();
@@ -49,18 +48,21 @@ defineEmits<{
   display: flex;
   align-items: center;
   justify-content: space-between;
-  padding: 0 10px;
+  padding: 0 4px;
 
   span {
     width: 32px;
     height: 32px;
-    font-size: 16px;
     display: flex;
     border-radius: 4px;
     align-items: center;
     cursor: pointer;
     justify-content: center;
 
+    .icon {
+      font-size: 18px;
+    }
+
     &.active {
       background: rgba(0, 200, 175, 0.3);
     }

+ 1 - 1
src/views/animation/right/index.vue

@@ -1,7 +1,7 @@
 <template>
   <RightFillPano class="animation-right" v-if="activeAttrib?.key !== 'frames'">
     <AM
-      v-show="!activeAttrib || !~activeAttrib.ndx"
+      v-if="!activeAttrib || !~activeAttrib.ndx"
       :am="am"
       @add-frame="(preset) => emit('addFrame', preset)"
       @add-path="(preset) => emit('addPath', preset)"

+ 159 - 0
对接文档.txt

@@ -0,0 +1,159 @@
+sdk 加一个方法 createAnimationGroup 不传参数放回动画组对象 AnimationGroup
+
+// 动画组对象
+type AnimationGroup = {
+  // 播放
+  play: () => void;
+  // 暂停
+  pause: () => void;
+  // 添加动画模型
+  addAnimationModel: (data: AnimationModel) => AnimationModel3D;
+
+  // 设置当前时间, 单位为秒
+  setCurrentTime: (s: number) => void
+};
+
+动画模型传入参数如下
+AnimationModel = {
+  title: string;   模型名称
+  url: string;     模型路径
+  showTitle: boolean;   是否显示名称
+  fontSize: number;     名称字体大小
+  globalVisibility: boolean;   是否全局可视
+  visibilityRange: number;     可视范围
+}
+
+
+动画模型对象
+export type AnimationModel3D = {
+  // 销毁动画模型
+  destory: () => void;
+  // 更改动画模型可见性
+  visibility: (show: boolean) => void;
+  // 更改动画可见范围  不传为全局可见
+  changeVisibilityRange: (range?: number) => void;
+  // 更改模型名称
+  changeTitle: (name: string) => void;
+  // 更改名称字体大小
+  changeFontSize: (size: number) => void;
+  // 更改名称可见性
+  visibilityTitle: (show: boolean) => void;
+
+  // 添加模型帧
+  addFrame: (frame: AnimationModelFrame) => AnimationModelFrame3D;
+  // 添加模型动作
+  addAction: (frame: AnimationModelAction) => AnimationModelAction3D;
+  // 添加模型路径
+  addPath: (frame: Omit<AnimationModelPath, 'pathId'> & {path: Path}) => AnimationModelPath3D;
+
+  // 获取当前模型旁白出现的适合位置,传入旁边dom的宽高,返回像素位置
+  getCurrentSubtitlePixel: (size: {width: number, height: number}) => {x: number, y: number}
+
+// 获取当前时间改模型的姿态
+  getCurrentMat: () => {
+    position?: SceneLocalPos;
+    scale?: number;
+    rotation?: SceneLocalPos;
+    originPosition?: SceneLocalPos
+  }
+
+  // 设置当前操控模式, translate rotate scale originTranslate,传undefined则不进入设置
+  setCurrentMode: (mode?: string) => void
+};
+
+
+添加模型帧参数如下
+export type AnimationModelFrame = {
+  // 模型帧播放时间
+  time: number;
+  // 模型的姿态, 
+  mat: {
+      position: SceneLocalPos;
+      scale: number;
+      rotation: SceneLocalPos;
+      originPosition: SceneLocalPos
+  }
+};
+
+返回的模型帧对象
+export type AnimationModelFrame3D = {
+  // 销毁动画模型帧
+  destory: () => void;
+  // 修改帧播放时间 单位为秒
+  changeTime: (s: number) => void
+  bus: Emitter<{
+    // 动画帧姿态修改数据,发送的时间,
+    matChange: {
+      position?: SceneLocalPos;
+      scale?: number;
+      rotation?: SceneLocalPos;
+      originPosition?: SceneLocalPos
+    };
+  }>;
+};
+
+
+添加模型动作参数如下
+export type AnimationModelAction = {
+  // 幅度
+  amplitude: number;
+  // 速度
+  speed: number;
+  // 开始播放时间
+  time: number;
+  // 播放时长
+  duration: number;
+  // 哪个动作, 
+  // "Walk"    "走"
+  // "Run"    "跑"
+  // "Climb"    "爬"
+  // "JumpUp"    "向上跳"
+  // "JumpDown"    "向下跳"
+  // "TurnLeft"    "左转"
+  // "TurnRight"    "右转"
+  // "FallForward"    "向前倒地"
+  // "FallBackward"    "向后倒地"
+  key: string;
+};
+
+
+返回的模型帧动作对象
+export type AnimationModelAction3D = {
+  // 销毁动画模型动作
+  destory: () => void;
+  // 修改动作播放时间 单位为秒
+  changeTime: (s: number) => void
+  // 修改动作幅度  
+  changeAmplitude: (n: number) => void
+  // 修改动作速度
+  changeSpeed: (n: number) => void
+  // 修改动持续时间 单位为秒
+  changeDuration: (n: number) => void
+};
+
+
+添加模型路径参数如下
+export type AnimationModelPath = {
+  // 是否反向
+  reverse: boolean;
+  // 路径对象  之前createPath返回的
+  path?: object;
+  // 播放时间
+  time: number;
+  // 播放时长
+  duration: number;
+};
+
+返回路径对象如下
+export type AnimationModelPath3D = {
+  // 销毁动画模型路径
+  destory: () => void;
+  // 修改路径 传入参数为你之前返回的路径对象
+  changePath: (path: Path) => void
+  // 修改播放是否要反向
+  changeReverse: (reverse: boolean) => void
+  // 修改路径播放时间 单位为秒
+  changeTime: (s: number) => void
+  // 修改路径续时间 单位为秒
+  changeDuration: (n: number) => void
+};