feat: 弹窗&prompt i18n

This commit is contained in:
zhangyh
2025-11-14 15:10:32 +08:00
parent 80472a9cec
commit c32afb99ce
11 changed files with 444 additions and 162 deletions

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, reactive, toRefs, nextTick } from "vue";
import { ref, onMounted, reactive, toRefs, nextTick, useTemplateRef, watch } from "vue";
interface ContentItem {
id: string;
@@ -336,18 +336,62 @@ const initPlaceholders = () => {
}
const getFullText = () => {
return content.value.map(item => {
if (item.type === 'text') {
return item.value
} else {
// 只获取用户实际输入的值,即使为空也显示空括号
return `${item.value}`
}
}).join('')
if(assistModel.value){
return content.value.map(item => {
if (item.type === 'text') {
return item.value
} else {
// 如果 input 没有输入 value则用 placeholder 填充,并去掉首尾的 []
if (item.value) {
return ` ${item.value} `
} else if (item.placeholder) {
let placeholderText = item.placeholder
// 去掉首尾的 []
if (placeholderText.startsWith('[') && placeholderText.endsWith(']')) {
placeholderText = placeholderText.slice(1, -1)
}
return ` ${placeholderText} `
}
return ''
}
}).join('')
}
return textareaValue.value
}
const textareaValue = ref('')
const assistModel= ref(false)
const handleClickAssistBtn = () => {
assistModel.value = !assistModel.value
}
// 监听 assistModel 变化,切换到 textarea 模式时调整高度
watch(assistModel, (newVal) => {
if (!newVal) {
// 切换到 textarea 模式
nextTick(() => {
handleInputResize()
})
}
})
const textareaRef = useTemplateRef<HTMLTextAreaElement>('textareaRef')
const handleInputResize = () => {
const textarea = textareaRef.value
if (textarea) {
textarea.style.height = 'auto'
textarea.style.height = textarea.scrollHeight + 'px'
}
}
onMounted(() => {
initPlaceholders()
// 如果初始状态是 textarea 模式,设置初始高度
if (!assistModel.value) {
nextTick(() => {
handleInputResize()
})
}
})
defineExpose({
@@ -357,16 +401,42 @@ defineExpose({
</script>
<template>
<div ref="editableArea" class="promptInput" @keydown="handleKeydown" @click="handleContainerClick">
<div v-show="!assistModel" class="textarea-container">
<textarea
class="area"
v-model="textareaValue"
ref="textareaRef"
@input="handleInputResize"
:placeholder="$t('poseTransfer.PormptPlaceholder')"
/>
<div class="asistant-btn" @click="handleClickAssistBtn">
<i class="fi fi-bs-magic-wand asistant-icon"></i>
<span>{{ $t('ProductImg.PromptAssit') }}</span>
</div>
</div>
<div v-show="assistModel" ref="editableArea" class="promptInput" @keydown="handleKeydown" @click="handleContainerClick">
<template v-for="(item, index) in content" :key="item.id">
<span v-if="item.type === 'text'" class="text-field" :data-index="index" contenteditable="plaintext-only">{{
item.value }}</span>
<span
v-if="item.type === 'text'"
class="text-field"
:data-index="index"
contenteditable="plaintext-only">
{{item.value }}
</span>
<span v-else class="input-field" :data-index="index">
<span class="input-content" contenteditable="plaintext-only" @input="(e) => handleInputChange(index, e)"
@keydown="(e) => handleInputKeydown(e, index)" @blur="() => handleInputBlur(index)"></span>
<span
class="input-content"
contenteditable="plaintext-only"
@input="(e) => handleInputChange(index, e)"
@keydown="(e) => handleInputKeydown(e, index)"
@blur="() => handleInputBlur(index)"></span>
</span>
</template>
<div class="asistant-btn" @click="handleClickAssistBtn">
<i class="fi fi-bs-magic-wand asistant-icon"></i>
<span>{{ $t('ProductImg.PromptAssit') }}</span>
</div>
</div>
</template>
@@ -387,6 +457,9 @@ defineExpose({
white-space: pre-wrap;
user-select: text;
cursor: text;
position: relative;
padding-bottom: 4rem;
.text-field {
display: inline;
@@ -399,8 +472,8 @@ defineExpose({
.input-field {
display: inline-block;
background: #e3f2fd;
border: 1px solid #bbdefb;
// background: #e3f2fd;
// border: 1px solid #bbdefb;
margin: 0 .2rem;
padding: .2rem 1rem;
font-size: 1.8rem;
@@ -408,15 +481,62 @@ defineExpose({
.input-content {
outline: none;
color: #1976d2;
display: inline-block;
min-width: 2rem;
&.has-placeholder {
color: #95a5a6;
font-style: italic;
color: #b9b9b9;
// font-style: italic;
}
}
}
}
.textarea-container{
position: relative;
border-radius: 10px;
border: 2px solid #dcdfe6;
padding: 1.5rem 1.5rem 3rem;
height: auto;
.area{
width: 100%;
min-height: 12rem;
height: auto;
background: white;
line-height: 1.6;
outline: none;
white-space: pre-wrap;
user-select: text;
cursor: text;
position: relative;
// padding-bottom: 4rem;
resize: none;
border: none;
}
}
.asistant-btn {
height: 2.3rem;
padding: 0 0.6rem;
font-size: 1rem;
font-weight: 400;
color: #313131;
position: absolute;
bottom: 1.3rem;
left: 1.3rem;
display: flex;
column-gap: 0.3rem;
justify-content: center;
align-items: center;
background-color: #f2f2f2;
border: 1px solid #dfdfdf;
border-radius: 0.5rem;
cursor: pointer;
.asistant-icon {
font-size: 1rem;
margin-right: 0;
width: initial;
// margin-top: -0.2rem;
}
}
</style>