123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- <template>
- <ui-group-option
- class="sign-tagging"
- :class="{ active: selected, edit }"
- @click="edit && getTaggingIsShow(tagging) && emit('select', true)"
- >
- <div class="info">
- <img :src="getResource(getFileUrl(findImage))" v-if="findImage" />
- <div>
- <p>{{ tagging.title }}</p>
- <span>放置:{{ positions.length }}</span>
- </div>
- </div>
- <div class="actions" @click.stop>
- <ui-icon
- v-if="!edit"
- type="pin"
- ctrl
- @click.stop="$emit('select', true)"
- :class="{ disabled: !getTaggingIsShow(tagging) }"
- />
- <template v-else>
- <ui-icon type="pin1" ctrl @click.stop="$emit('fixed')" tip="放置" />
- <ui-more
- :options="menus"
- style="margin-left: 20px"
- @click="(action: keyof typeof actions) => actions[action]()"
- />
- </template>
- </div>
- </ui-group-option>
- </template>
- <script setup lang="ts">
- import { getFileUrl, getUrlType, MetaType } from "@/utils";
- import { computed, ref, watchEffect, nextTick } from "vue";
- import { getResource, showTaggingPositionsStack } from "@/env";
- import { getTaggingPosNode, sdk } from "@/sdk";
- import {
- getTaggingStyle,
- getTaggingPositions,
- getFuseModel,
- getFuseModelShowVariable,
- getTaggingIsShow,
- } from "@/store";
- import type { Tagging } from "@/store";
- const props = withDefaults(
- defineProps<{ tagging: Tagging; selected?: boolean; edit?: boolean }>(),
- { edit: true }
- );
- const style = computed(() => getTaggingStyle(props.tagging.styleId));
- const positions = computed(() => getTaggingPositions(props.tagging));
- const emit = defineEmits<{
- (e: "delete"): void;
- (e: "edit"): void;
- (e: "select", selected: boolean): void;
- (e: "fixed"): void;
- }>();
- const findImage = computed(() => {
- let img = props.tagging.images.find(
- (a) => getUrlType(getResource(getFileUrl(a))) === MetaType.image
- );
- if (!img) {
- return getTaggingStyle(props.tagging.styleId)?.icon;
- } else {
- return img;
- }
- });
- const menus = [
- { label: "编辑", value: "edit" },
- { label: "删除", value: "delete" },
- ];
- const actions = {
- edit: () => emit("edit"),
- delete: () => emit("delete"),
- };
- const flyTaggingPositions = (tagging: Tagging, callback?: () => void) => {
- const positions = getTaggingPositions(tagging);
- let isStop = false;
- const flyIndex = (i: number) => {
- if (isStop || i >= positions.length) {
- callback && nextTick(callback);
- return;
- }
- const position = positions[i];
- const model = getFuseModel(position.modelId);
- if (!model || !getFuseModelShowVariable(model).value) {
- flyIndex(i + 1);
- return;
- }
- const pop = showTaggingPositionsStack.push(ref(new WeakSet([position])));
- sdk.comeTo({
- position: getTaggingPosNode(position)!.getImageCenter(),
- modelId: position.modelId,
- dur: 300,
- // distance: 3,
- maxDis: 15,
- });
- setTimeout(() => {
- pop();
- flyIndex(i + 1);
- }, 2000);
- };
- flyIndex(0);
- return () => (isStop = true);
- };
- watchEffect((onCleanup) => {
- if (props.selected) {
- const success = () => emit("select", false);
- const stop = flyTaggingPositions(props.tagging, success);
- const keyupHandler = (ev: KeyboardEvent) => ev.code === "Escape" && success();
- document.documentElement.addEventListener("keyup", keyupHandler, false);
- onCleanup(() => {
- stop();
- document.documentElement.removeEventListener("keyup", keyupHandler, false);
- });
- }
- });
- </script>
- <style lang="scss" scoped src="./style.scss"></style>
|