index.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <template>
  2. <div :class="{ focusAM: focusAM }" class="animation-layout">
  3. <Left
  4. :focus="focusAM"
  5. @update:focus="updateFocus"
  6. class="animation-left"
  7. @change-select="changeSelect"
  8. @delete="deleteAm"
  9. />
  10. <Right
  11. v-if="focusAM"
  12. :am="focusAM"
  13. :frameAction="frameAction"
  14. @change-frame-action="(f) => (frameAction = f.action)"
  15. class="animation-right"
  16. v-model:activeAttrib="activeAttrib"
  17. @add-frame="add('frames')"
  18. @add-path="(preset) => add('paths', { reverse: false, ...preset })"
  19. @add-subtitle="add('subtitles', { content: '', background: '#fff' })"
  20. @add-action="(preset) => add('actions', preset)"
  21. @apply-global="k => ams.forEach((am: any) => (am[k] = focusAM![k]))"
  22. />
  23. <Bottom
  24. :am="focusAM"
  25. v-model:follow="follow"
  26. v-model:current-time="currentTime"
  27. class="animation-toolbar"
  28. v-model:active="activeAttrib"
  29. />
  30. </div>
  31. </template>
  32. <script lang="ts" setup>
  33. import Left from "./left.vue";
  34. import Right from "./right/index.vue";
  35. import Bottom from "./bottom.vue";
  36. import router from "@/router";
  37. import { enterEdit } from "@/store";
  38. import { useViewStack } from "@/hook";
  39. import {
  40. ams,
  41. AnimationModel,
  42. autoSaveAnimationModel,
  43. initAnimationActions,
  44. initialAnimationModels,
  45. } from "@/store/animation";
  46. import { computed, nextTick, reactive, ref, watch, watchEffect } from "vue";
  47. import { Active } from "./type";
  48. import { getAddTLItemAttr } from "@/components/drawing-time-line/check";
  49. import { Message } from "bill/expose-common";
  50. import { uuid } from "@/components/drawing/hook";
  51. import { title } from "./type";
  52. import { amMap, getAMKey, currentTime } from "@/sdk/association/animation";
  53. enterEdit(() => router.back());
  54. initialAnimationModels();
  55. initAnimationActions();
  56. useViewStack(autoSaveAnimationModel);
  57. const focusAM = ref<AnimationModel>();
  58. const activeAttrib = ref<Active>();
  59. const follow = ref(false);
  60. const frameAction = ref<string>();
  61. const amM = computed(() => focusAM.value && amMap[getAMKey(focusAM.value)]);
  62. watchEffect((onCleanup) => {
  63. if (!amM.value || activeAttrib.value?.key !== "frames") return;
  64. const frame = focusAM.value!.frames[activeAttrib.value.ndx];
  65. const am3d = amM.value.am;
  66. if (!am3d) return;
  67. am3d.bus.on("transformChanged", (mat) => {
  68. frame.mat = JSON.parse(JSON.stringify(mat));
  69. });
  70. switch (frameAction.value) {
  71. case "translate":
  72. am3d.enterMoveMode();
  73. break;
  74. case "rotate":
  75. am3d.enterRotateMode();
  76. break;
  77. case "scale":
  78. am3d.enterScaleMode();
  79. break;
  80. }
  81. onCleanup(() => am3d.leaveTransform());
  82. });
  83. const updateFocus = (am?: AnimationModel) => {
  84. activeAttrib.value = undefined;
  85. focusAM.value = am;
  86. };
  87. watch(activeAttrib, (_a, _b, onCleanup) => {
  88. if (!activeAttrib.value) return;
  89. const cur = focusAM.value![activeAttrib.value.key][activeAttrib.value.ndx];
  90. const updateFocus = () => {
  91. const rang = [cur.time, cur.time + (cur.duration || 0)];
  92. if (currentTime.value < rang[0] || currentTime.value > rang[1]) {
  93. activeAttrib.value = undefined;
  94. }
  95. };
  96. follow.value = true;
  97. currentTime.value = cur.time!;
  98. nextTick(() => (follow.value = false));
  99. onCleanup(
  100. watch(
  101. () => [currentTime.value, cur.time, cur.time + (cur.duration || 0)],
  102. updateFocus
  103. )
  104. );
  105. });
  106. const add = <T extends Active["key"]>(
  107. key: T,
  108. preset: Partial<AnimationModel[T][0]> = {}
  109. ) => {
  110. const attr = getAddTLItemAttr(focusAM.value![key], currentTime.value, 10, 1);
  111. if (!attr) {
  112. Message.error("当前时间已存在其他" + title[key]);
  113. } else {
  114. const item = reactive({
  115. id: uuid(),
  116. name: title[key],
  117. ...attr,
  118. ...preset,
  119. } as any);
  120. focusAM.value![key].push(item);
  121. activeAttrib.value = {
  122. ndx: focusAM.value![key].length - 1,
  123. key,
  124. };
  125. }
  126. };
  127. const changeSelect = ({ select, unSelect }: Record<string, AnimationModel[]>) => {
  128. select.forEach((item) => amMap[getAMKey(item)].am?.changeShow(true));
  129. unSelect.forEach((item) => amMap[getAMKey(item)].am?.changeShow(false));
  130. };
  131. const deleteAm = (am: AnimationModel) => {
  132. if (am === focusAM.value) {
  133. activeAttrib.value = undefined;
  134. focusAM.value = undefined;
  135. }
  136. ams.value.splice(ams.value.indexOf(am), 1);
  137. };
  138. </script>
  139. <style lang="scss" scoped>
  140. .animation-layout {
  141. --bottom-height: 70px;
  142. &.focusAM {
  143. --bottom-height: 225px;
  144. }
  145. }
  146. .animation-left {
  147. height: calc(100vh - var(--bottom-height));
  148. position: absolute;
  149. width: var(--left-pano-width);
  150. }
  151. .animation-right {
  152. height: calc(100vh - var(--bottom-height));
  153. padding-top: 0;
  154. position: absolute;
  155. right: 0;
  156. top: 0;
  157. }
  158. .animation-toolbar {
  159. height: var(--bottom-height);
  160. width: 100vw;
  161. display: block;
  162. }
  163. </style>