|
@@ -0,0 +1,131 @@
|
|
|
|
+<script setup lang="ts">
|
|
|
|
+import { computed, ref, useTemplateRef, watch } from 'vue';
|
|
|
|
+
|
|
|
|
+import type { CSSProperties } from 'vue';
|
|
|
|
+import type { GroupModuleDevParam } from '@/types';
|
|
|
|
+
|
|
|
|
+interface Props {
|
|
|
|
+ info: GroupModuleDevParam;
|
|
|
|
+ width?: string;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const props = defineProps<Props>();
|
|
|
|
+
|
|
|
|
+const inputNumberRef = useTemplateRef('inputNumber');
|
|
|
|
+const inputVal = ref(props.info.value);
|
|
|
|
+const showInput = ref(false);
|
|
|
|
+
|
|
|
|
+const emit = defineEmits<{
|
|
|
|
+ ok: [value: string];
|
|
|
|
+}>();
|
|
|
|
+
|
|
|
|
+const containerStyle = computed<CSSProperties>(() => {
|
|
|
|
+ return {
|
|
|
|
+ width: props.width || '100%',
|
|
|
|
+ };
|
|
|
|
+});
|
|
|
|
+
|
|
|
|
+watch(
|
|
|
|
+ () => props.info.value,
|
|
|
|
+ () => {
|
|
|
|
+ inputVal.value = props.info.value;
|
|
|
|
+ },
|
|
|
|
+);
|
|
|
|
+
|
|
|
|
+const handlePlaceholderClick = () => {
|
|
|
|
+ showInput.value = true;
|
|
|
|
+
|
|
|
|
+ setTimeout(() => {
|
|
|
|
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
+ (inputNumberRef.value as any)?.focus();
|
|
|
|
+ }, 0);
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const handleInputBlur = () => {
|
|
|
|
+ setTimeout(() => {
|
|
|
|
+ showInput.value = false;
|
|
|
|
+ inputVal.value = props.info.value;
|
|
|
|
+ }, 200);
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const handleSave = () => {
|
|
|
|
+ props.info.value = inputVal.value;
|
|
|
|
+ emit('ok', inputVal.value);
|
|
|
|
+};
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<template>
|
|
|
|
+ <div class="input-save-container" :style="containerStyle">
|
|
|
|
+ <div v-show="!showInput" class="input-save-placeholder" @click="handlePlaceholderClick">{{ info.value }}</div>
|
|
|
|
+ <AInputNumber
|
|
|
|
+ ref="inputNumber"
|
|
|
|
+ v-show="showInput"
|
|
|
|
+ class="input-save-input"
|
|
|
|
+ v-model:value="inputVal"
|
|
|
|
+ :controls="false"
|
|
|
|
+ @blur="handleInputBlur"
|
|
|
|
+ />
|
|
|
|
+ <AButton v-show="showInput" class="input-save-button" type="primary" size="small" @click="handleSave">
|
|
|
|
+ {{ $t('common.save') }}
|
|
|
|
+ </AButton>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
+.input-save-container {
|
|
|
|
+ position: relative;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.input-save-placeholder {
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 32px;
|
|
|
|
+ padding: 0 11px;
|
|
|
|
+ line-height: 32px;
|
|
|
|
+ color: var(--antd-color-text);
|
|
|
|
+ border: 1px solid #d9d9d9;
|
|
|
|
+ border-radius: 6px;
|
|
|
|
+ outline: 0;
|
|
|
|
+ transition: all 0.2s linear;
|
|
|
|
+
|
|
|
|
+ &:hover {
|
|
|
|
+ cursor: text;
|
|
|
|
+ border-color: var(--antd-color-primary-hover);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.input-save-input {
|
|
|
|
+ width: 100%;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.input-save-button {
|
|
|
|
+ position: absolute;
|
|
|
|
+ bottom: -28px;
|
|
|
|
+ left: 50%;
|
|
|
|
+ z-index: 10;
|
|
|
|
+
|
|
|
|
+ /* 添加阴影效果 */
|
|
|
|
+ box-shadow:
|
|
|
|
+ 0 4px 6px -1px rgb(0 0 0 / 10%),
|
|
|
|
+ 0 2px 4px -1px rgb(0 0 0 / 6%);
|
|
|
|
+
|
|
|
|
+ /* 增强视觉层次的过渡效果 */
|
|
|
|
+ transition: all 0.2s ease;
|
|
|
|
+ transform: translate(-50%);
|
|
|
|
+
|
|
|
|
+ /* 悬停时的阴影变化 */
|
|
|
|
+ &:hover {
|
|
|
|
+ box-shadow:
|
|
|
|
+ 0 10px 15px -3px rgb(0 0 0 / 10%),
|
|
|
|
+ 0 4px 6px -2px rgb(0 0 0 / 5%);
|
|
|
|
+ transform: translate(-50%, -2px);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* 点击时的效果 */
|
|
|
|
+ &:active {
|
|
|
|
+ box-shadow:
|
|
|
|
+ 0 4px 6px -1px rgb(0 0 0 / 10%),
|
|
|
|
+ 0 2px 4px -1px rgb(0 0 0 / 6%);
|
|
|
|
+ transform: translate(-50%, 0);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+</style>
|