sign.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <template>
  2. <ui-group-option
  3. class="sign-measure"
  4. :class="{ active: measure.selected, search }"
  5. @mouseenter="measure.selected = true"
  6. @mouseleave="measure.selected = false"
  7. >
  8. <div class="info">
  9. <ui-icon :type="MeasureTypeMeta[measure.type].icon" class="type" />
  10. <div v-show="!isEditTitle">
  11. <p @click="edit && (isEditTitle = true)">
  12. {{ measure.title || MeasureTypeMeta[measure.type].unitDesc }}
  13. </p>
  14. <span>{{ desc }} {{ MeasureTypeMeta[measure.type].unit }}</span>
  15. </div>
  16. <ui-input
  17. class="view-title-input"
  18. type="text"
  19. :modelValue="measure.title"
  20. :maxlength="15"
  21. @update:modelValue="(title: string) => $emit('updateTitle', title.trim())"
  22. v-show="isEditTitle"
  23. ref="inputRef"
  24. height="28px"
  25. />
  26. </div>
  27. <div class="actions">
  28. <!-- <ui-icon type="del" ctrl @click.stop="$emit('delete')" v-if="edit" /> -->
  29. <ui-icon
  30. type="pin"
  31. ctrl
  32. @click="fly"
  33. :class="{ disabled: !getMeasureIsShow(measure) }"
  34. />
  35. <ui-more
  36. v-if="edit"
  37. :options="menus"
  38. style="margin-left: 20px"
  39. @click="(action: keyof typeof actions) => actions[action]()"
  40. />
  41. </div>
  42. </ui-group-option>
  43. </template>
  44. <script setup lang="ts">
  45. import { MeasureTypeMeta, getMeasureIsShow } from "@/store";
  46. import { getSceneMeasure, getSceneMeasureDesc } from "@/sdk";
  47. import { useFocus } from "bill/hook/useFocus";
  48. import type { Measure } from "@/store";
  49. import { computed, ref, watch, watchEffect } from "vue";
  50. import { Message } from "bill/index";
  51. import { custom } from "@/env";
  52. const props = withDefaults(
  53. defineProps<{ measure: Measure; edit?: boolean; search?: boolean }>(),
  54. {
  55. edit: true,
  56. search: false,
  57. }
  58. );
  59. const emit = defineEmits<{
  60. (e: "delete"): void;
  61. (e: "updateTitle", title: string): void;
  62. }>();
  63. const inputRef = ref();
  64. const isEditTitle = useFocus(computed(() => inputRef.value?.vmRef.root));
  65. const menus = [
  66. { label: "重命名", value: "rename" },
  67. { label: "删除", value: "delete" },
  68. ];
  69. const actions = {
  70. delete: () => emit("delete"),
  71. rename: () => (isEditTitle.value = true),
  72. };
  73. watchEffect(() => {
  74. if (!isEditTitle.value && !props.measure.title.length) {
  75. isEditTitle.value = true;
  76. Message.warning("测量名称不可为空");
  77. }
  78. });
  79. const fly = () => {
  80. getSceneMeasure(props.measure)?.fly();
  81. };
  82. const desc = ref("-");
  83. watch(
  84. () => [props.measure, custom.showMeasures, custom.showModelsMap],
  85. () => {
  86. const smeasure = getSceneMeasure(props.measure);
  87. desc.value = smeasure ? getSceneMeasureDesc(smeasure, props.measure) : "-";
  88. },
  89. { deep: true, flush: "post", immediate: true }
  90. );
  91. </script>
  92. <style lang="scss" scoped>
  93. .sign-measure {
  94. display: flex;
  95. justify-content: space-between;
  96. align-items: center;
  97. padding: 20px 0;
  98. margin: 0;
  99. border-bottom: 1px solid var(--colors-border-color);
  100. position: relative;
  101. &.search {
  102. padding: 0;
  103. border-bottom: none;
  104. margin-bottom: 5px;
  105. }
  106. &.active:not(.search)::after {
  107. content: "";
  108. position: absolute;
  109. pointer-events: none;
  110. inset: 0 -20px;
  111. background-color: rgba(0, 200, 175, 0.16);
  112. z-index: -1;
  113. }
  114. .info {
  115. flex: 1;
  116. display: flex;
  117. align-items: center;
  118. .type {
  119. width: 48px;
  120. height: 48px;
  121. border-radius: 4px;
  122. overflow: hidden;
  123. display: flex;
  124. background: rgba(0, 0, 0, 0.5);
  125. flex: 0 0 auto;
  126. font-size: 18px;
  127. align-items: center;
  128. justify-content: center;
  129. }
  130. div {
  131. margin-left: 10px;
  132. p {
  133. color: #fff;
  134. font-size: 14px;
  135. }
  136. span {
  137. color: rgba(255, 255, 255, 0.6);
  138. font-size: 12px;
  139. }
  140. }
  141. }
  142. .actions {
  143. flex: none;
  144. > * {
  145. margin-left: 22px;
  146. }
  147. }
  148. }
  149. </style>
  150. <style>
  151. .view-title-input.ui-input .text.suffix input {
  152. padding-right: 50px;
  153. }
  154. </style>