relight提示词相关内容
This commit is contained in:
@@ -308,6 +308,20 @@ const handleInputChange = (index: number, event: Event) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 增强中文输入事件处理
|
||||
const handleCompositionStart = (index: number, event: CompositionEvent) => {
|
||||
compositionState.isComposing = true
|
||||
compositionState.currentInputIndex = index
|
||||
|
||||
const target = event.target as HTMLSpanElement
|
||||
// 如果是placeholder状态,开始中文输入时清除placeholder
|
||||
if (target.classList.contains('has-placeholder')) {
|
||||
target.classList.remove('has-placeholder')
|
||||
target.textContent = ''
|
||||
data.content[index].value = ''
|
||||
}
|
||||
}
|
||||
|
||||
// 添加专门的粘贴事件处理
|
||||
const handleInputPaste = (event: ClipboardEvent, index: number) => {
|
||||
const target = event.target as HTMLSpanElement
|
||||
@@ -338,6 +352,11 @@ const handleInputPaste = (event: ClipboardEvent, index: number) => {
|
||||
const handleInputKeydown = (event: KeyboardEvent, index: number) => {
|
||||
const target = event.target as HTMLSpanElement
|
||||
|
||||
// 如果是中文输入过程中,不处理普通按键
|
||||
if (compositionState.isComposing) {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === 'Backspace') {
|
||||
// 如果显示placeholder,阻止删除
|
||||
if (target.classList.contains('has-placeholder')) {
|
||||
@@ -357,7 +376,7 @@ const handleInputKeydown = (event: KeyboardEvent, index: number) => {
|
||||
}
|
||||
}
|
||||
} else if (event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
|
||||
// 普通字符输入
|
||||
// 普通字符输入 - 只有在非中文输入状态下才处理
|
||||
if (target.classList.contains('has-placeholder')) {
|
||||
event.preventDefault()
|
||||
target.textContent = event.key
|
||||
@@ -407,23 +426,13 @@ const handlePasteInInput = (index: number, element: HTMLElement) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 添加中文输入事件处理
|
||||
const handleCompositionStart = (index: number, event: CompositionEvent) => {
|
||||
compositionState.isComposing = true
|
||||
compositionState.currentInputIndex = index
|
||||
|
||||
const target = event.target as HTMLSpanElement
|
||||
// 如果是placeholder状态,开始中文输入时清除placeholder
|
||||
if (target.classList.contains('has-placeholder')) {
|
||||
target.classList.remove('has-placeholder')
|
||||
target.textContent = ''
|
||||
data.content[index].value = ''
|
||||
}
|
||||
}
|
||||
|
||||
const handleCompositionEnd = (index: number, event: CompositionEvent) => {
|
||||
compositionState.isComposing = false
|
||||
compositionState.currentInputIndex = -1
|
||||
// 延迟设置 isComposing 为 false,确保所有相关事件都处理完毕
|
||||
setTimeout(() => {
|
||||
compositionState.isComposing = false
|
||||
compositionState.currentInputIndex = -1
|
||||
}, 0)
|
||||
|
||||
const target = event.target as HTMLSpanElement
|
||||
const newValue = target.textContent || ''
|
||||
@@ -432,14 +441,28 @@ const handleCompositionEnd = (index: number, event: CompositionEvent) => {
|
||||
// 如果中文输入后内容为空,显示placeholder
|
||||
const item = data.content[index]
|
||||
if (newValue.trim() === '' && item.placeholder) {
|
||||
target.classList.add('has-placeholder')
|
||||
target.textContent = item.placeholder
|
||||
// 延迟显示 placeholder,确保光标位置正确
|
||||
nextTick(() => {
|
||||
if (target.textContent?.trim() === '') {
|
||||
target.classList.add('has-placeholder')
|
||||
target.textContent = item.placeholder
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 添加输入框焦点事件处理,确保中文输入状态正确重置
|
||||
const handleInputFocus = (index: number) => {
|
||||
compositionState.currentInputIndex = index
|
||||
}
|
||||
|
||||
// 修改输入框的 blur 处理
|
||||
const handleInputBlur = (index: number) => {
|
||||
compositionState.isComposing = false
|
||||
compositionState.currentInputIndex = -1
|
||||
// 延迟重置状态,避免与 compositionend 冲突
|
||||
setTimeout(() => {
|
||||
compositionState.isComposing = false
|
||||
compositionState.currentInputIndex = -1
|
||||
}, 100)
|
||||
updateInputDisplay(index)
|
||||
}
|
||||
|
||||
@@ -528,6 +551,7 @@ defineExpose({
|
||||
<span>{{ $t('ProductImg.PromptAssit') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- {{ data.content }} -->
|
||||
<div
|
||||
v-show="assistModel"
|
||||
ref="editableArea"
|
||||
@@ -547,11 +571,12 @@ defineExpose({
|
||||
</span>
|
||||
|
||||
<span v-else class="input-field" :data-index="index">
|
||||
<span
|
||||
<span
|
||||
class="input-content"
|
||||
contenteditable="plaintext-only"
|
||||
@input="e => handleInputChange(index, e)"
|
||||
@keydown="e => handleInputKeydown(e, index)"
|
||||
@focus="() => handleInputFocus(index)"
|
||||
@blur="() => handleInputBlur(index)"
|
||||
@paste="e => handleInputPaste(e, index)"
|
||||
@compositionstart="e => handleCompositionStart(index, e)"
|
||||
|
||||
467
src/component/home/tools/toProduct/PromptEditProduct.vue
Normal file
467
src/component/home/tools/toProduct/PromptEditProduct.vue
Normal file
@@ -0,0 +1,467 @@
|
||||
<template>
|
||||
<!-- <div ref="modalContainer"></div> -->
|
||||
<a-modal
|
||||
class="promptEditProduct-modal generalModel"
|
||||
v-model:visible="showModal"
|
||||
:footer="null"
|
||||
width="78%"
|
||||
:maskClosable="false"
|
||||
:centered="true"
|
||||
:closable="false"
|
||||
wrapClassName="#app"
|
||||
:keyboard="false"
|
||||
>
|
||||
<div class="generalModel_btn">
|
||||
<div class="generalModel_closeIcon" @click.stop="handleClose()">
|
||||
<svg
|
||||
width="100%"
|
||||
height="100%"
|
||||
viewBox="0 0 46 46"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle cx="23" cy="23" r="23" fill="#000" fill-opacity="0.3" />
|
||||
<rect
|
||||
x="32.5063"
|
||||
y="12"
|
||||
width="3"
|
||||
height="29"
|
||||
rx="1.5"
|
||||
transform="rotate(45 32.5063 12)"
|
||||
fill="white"
|
||||
/>
|
||||
<rect
|
||||
x="34.6274"
|
||||
y="32.5059"
|
||||
width="3"
|
||||
height="29"
|
||||
rx="1.5"
|
||||
transform="rotate(135 34.6274 32.5059)"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="title-container">
|
||||
<div class="title">{{ $t('ProductImg.PromptAssit') }}</div>
|
||||
<div class="sub-title">{{ status == 0 ? $t('ProductImg.Edited') : $t('ProductImg.AssitSubTitle') }}</div>
|
||||
</div>
|
||||
<div class="example-content" v-show="status == 0" :class="{'active': status !== 0}">
|
||||
<div
|
||||
class="example-wrapper"
|
||||
>
|
||||
<div class="example-item"
|
||||
v-for="item in editedList"
|
||||
:key="item.text">
|
||||
<div class="imgItem">
|
||||
<img :src="item.src" />
|
||||
<div class="icon">
|
||||
<SvgIcon v-if="item.status === 1" name="promptEditProductYes" size="35" />
|
||||
<SvgIcon v-else name="promptEditProductNo" size="35" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="text">
|
||||
{{ item.text }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="example-content prompt" v-show="status == 1" :class="{'active': status == 0}">
|
||||
<div
|
||||
class="example-wrapper"
|
||||
>
|
||||
|
||||
<div class="example-item">
|
||||
<div class="imgItem">
|
||||
<img :src="listImgOriginal" />
|
||||
<div class="info">{{ $t('ProductImg.OriginalImage') }}</div>
|
||||
</div>
|
||||
<SvgIcon
|
||||
class="download-icon"
|
||||
name="CDownload"
|
||||
size="20"
|
||||
color="#8E8E8E"
|
||||
@click.stop="handleDownload(item)"
|
||||
/>
|
||||
<div class="text">
|
||||
{{ $t('ProductImg.EditGarmen') }}:
|
||||
</div>
|
||||
</div>
|
||||
<div class="example-item"
|
||||
v-for="item in presentList"
|
||||
:key="item.text">
|
||||
<div class="imgItem">
|
||||
<img :src="item.src" />
|
||||
<div class="info">{{ item.info }}</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="textCopy">
|
||||
{{ item.text }}
|
||||
<SvgIcon
|
||||
name="CCopy"
|
||||
size="25"
|
||||
color="#BCBCBC"
|
||||
class="copy-icon"
|
||||
@click.stop="handleCopy(item)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="prompt-list">
|
||||
<div v-for="item in promptList" :key="item" class="prompt-item">
|
||||
<SvgIcon
|
||||
name="CCopy"
|
||||
size="25"
|
||||
color="#BCBCBC"
|
||||
class="copy-icon"
|
||||
@click.stop="handleCopy(item)"
|
||||
/>
|
||||
{{ item }}
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="nextOrPrevious">
|
||||
<div class="Previous" @click="setNextOrPrevious('Previous')">
|
||||
<i class="fi fi-bs-angle-left"></i>
|
||||
</div>
|
||||
<div class="next" @click="setNextOrPrevious('next')">
|
||||
<i class="fi fi-bs-angle-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, useTemplateRef, onMounted } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import listImgOriginal from '@/assets/images/editProduct/PromptEditProduct_listOriginal.png'
|
||||
import edited1 from '@/assets/images/editProduct/PromptEditProduct_edited1.png'
|
||||
import edited2 from '@/assets/images/editProduct/PromptEditProduct_edited2.png'
|
||||
import edited3 from '@/assets/images/editProduct/PromptEditProduct_edited3.png'
|
||||
|
||||
import listImg1 from '@/assets/images/editProduct/PromptEditProduct_list1.png'
|
||||
import listImg2 from '@/assets/images/editProduct/PromptEditProduct_list2.png'
|
||||
import listImg3 from '@/assets/images/editProduct/PromptEditProduct_list3.png'
|
||||
import listImg4 from '@/assets/images/editProduct/PromptEditProduct_list4.png'
|
||||
import listImg5 from '@/assets/images/editProduct/PromptEditProduct_list5.png'
|
||||
import listImg6 from '@/assets/images/editProduct/PromptEditProduct_list6.png'
|
||||
import listImg7 from '@/assets/images/editProduct/PromptEditProduct_list7.png'
|
||||
import listImg8 from '@/assets/images/editProduct/PromptEditProduct_list8.png'
|
||||
import listImg9 from '@/assets/images/editProduct/PromptEditProduct_list9.png'
|
||||
import listImg10 from '@/assets/images/editProduct/PromptEditProduct_list10.png'
|
||||
import listImg11 from '@/assets/images/editProduct/PromptEditProduct_list11.png'
|
||||
|
||||
import { downloadIamge } from '@/tool/util'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const { t, locale } = useI18n()
|
||||
|
||||
const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const showModal = defineModel<boolean>('showModal', { required: true })
|
||||
|
||||
const status = ref(0)
|
||||
const promptPage = ref(1)
|
||||
const editedList = ref([
|
||||
{
|
||||
src:edited1,
|
||||
text:t('ProductImg.Background'),
|
||||
status:1,
|
||||
},
|
||||
{
|
||||
src:edited2,
|
||||
text:t('ProductImg.BackgroundColor'),
|
||||
status:1,
|
||||
},
|
||||
{
|
||||
src:edited3,
|
||||
text:t('ProductImg.ComplexBackground'),
|
||||
status:0,
|
||||
}
|
||||
])
|
||||
const promptList = ref([
|
||||
{
|
||||
src:listImg1,
|
||||
info:t('ProductImg.ChangeviewInfo'),
|
||||
text:t('ProductImg.Changeview')
|
||||
},{
|
||||
src:listImg2,
|
||||
info:t('ProductImg.ChangeposeInfo'),
|
||||
text:t('ProductImg.Changepose')
|
||||
},{
|
||||
src:listImg3,
|
||||
info:t('ProductImg.ChangehairInfo'),
|
||||
text:t('ProductImg.Changehair')
|
||||
},{
|
||||
src:listImg4,
|
||||
info:t('ProductImg.ChangeAsianInfo'),
|
||||
text:t('ProductImg.ChangeAsian')
|
||||
},{
|
||||
src:listImg5,
|
||||
info:t('ProductImg.ChangedeminInfo'),
|
||||
text:t('ProductImg.Changedemin')
|
||||
},{
|
||||
src:listImg6,
|
||||
info:t('ProductImg.ChaRemoveInfo'),
|
||||
text:t('ProductImg.ChaRemove')
|
||||
},{
|
||||
src:listImg7,
|
||||
info:t('ProductImg.ChangeSunglassesInfo'),
|
||||
text:t('ProductImg.ChangeSunglasses')
|
||||
},{
|
||||
src:listImg8,
|
||||
info:t('ProductImg.ChangeHeelsInfo'),
|
||||
text:t('ProductImg.ChangeHeels')
|
||||
},{
|
||||
src:listImg9,
|
||||
info:t('ProductImg.ChangeUrbanInfo'),
|
||||
text:t('ProductImg.ChangeUrban')
|
||||
},{
|
||||
src:listImg10,
|
||||
info:t('ProductImg.ChangeBarInfo'),
|
||||
text:t('ProductImg.ChangeBar')
|
||||
},{
|
||||
src:listImg11,
|
||||
info:t('ProductImg.ChangeGardenInfo'),
|
||||
text:t('ProductImg.ChangeGarden')
|
||||
},
|
||||
])
|
||||
const presentList = ref([
|
||||
|
||||
]) as any
|
||||
|
||||
const setPresentList = (pageSize = 4)=>{
|
||||
const startIndex = (promptPage.value - 1) * pageSize;
|
||||
const endIndex = startIndex + pageSize;
|
||||
return promptList.value.slice(startIndex, endIndex);
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
showModal.value = false
|
||||
}
|
||||
|
||||
const handleDownload = () => {
|
||||
downloadIamge(listImgOriginal)
|
||||
}
|
||||
|
||||
const handleCopy = async (item: any) => {
|
||||
let value = item.text.replace(/\n/g, ' ');
|
||||
try {
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
await navigator.clipboard.writeText(value)
|
||||
message.success(t('ProductImg.CopySuccess'))
|
||||
} else {
|
||||
// 降级方案:使用传统的 document.execCommand 方法
|
||||
const textArea = document.createElement('textarea')
|
||||
textArea.value = value
|
||||
textArea.style.position = 'fixed'
|
||||
textArea.style.left = '-999999px'
|
||||
textArea.style.top = '-999999px'
|
||||
document.body.appendChild(textArea)
|
||||
textArea.focus()
|
||||
textArea.select()
|
||||
try {
|
||||
document.execCommand('copy')
|
||||
message.success(t('ProductImg.CopySuccess'))
|
||||
} catch (err) {
|
||||
message.error(t('ProductImg.CopyFailed'))
|
||||
}
|
||||
document.body.removeChild(textArea)
|
||||
}
|
||||
} catch (err) {
|
||||
message.error(t('ProductImg.CopyFailed'))
|
||||
}
|
||||
|
||||
}
|
||||
const setNextOrPrevious = (type) => {
|
||||
if(type === 'Previous'){
|
||||
if(promptPage.value == 1){
|
||||
status.value = 0
|
||||
}else{
|
||||
promptPage.value--
|
||||
}
|
||||
}else{
|
||||
if(status.value == 0){
|
||||
status.value = 1
|
||||
}else{
|
||||
promptPage.value++
|
||||
}
|
||||
}
|
||||
if(promptPage.value > 0)presentList.value = setPresentList()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.promptEditProduct-modal{
|
||||
&.generalModel{
|
||||
.ant-modal-body{
|
||||
padding: 5rem 4.7rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.promptEditProduct-modal {
|
||||
.title-container {
|
||||
.title {
|
||||
font-size: 3.5rem;
|
||||
color: #181818;
|
||||
}
|
||||
.sub-title {
|
||||
font-size: 2rem;
|
||||
font-weight: 400;
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
.nextOrPrevious{
|
||||
position: absolute;
|
||||
bottom: 2.2rem;
|
||||
display: flex;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
gap: 3.6rem;
|
||||
> div{
|
||||
width: 3.6rem;
|
||||
height: 3.6rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #E9E9E9;
|
||||
&:hover{
|
||||
background: #000000;
|
||||
color: #fff;
|
||||
}
|
||||
> i{
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
.example-content {
|
||||
margin-top: 4.7rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
overflow-x: auto;
|
||||
justify-content: center;
|
||||
.example-wrapper {
|
||||
display: flex;
|
||||
gap: 6.4rem;
|
||||
.example-item {
|
||||
// width: 20.3rem;
|
||||
position: relative;
|
||||
> .imgItem{
|
||||
position: relative;
|
||||
height: 44.6rem;
|
||||
border: 1px solid #EEEEEE;
|
||||
img {
|
||||
height: 100%;
|
||||
}
|
||||
> .icon{
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
bottom: -.3rem;
|
||||
right: -1.4rem;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
> .info{
|
||||
|
||||
}
|
||||
}
|
||||
> .text{
|
||||
margin-top: 4rem;
|
||||
font-size: 2rem;
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
}
|
||||
.download-icon {
|
||||
position: absolute;
|
||||
top: 0.77rem;
|
||||
right: 0.84rem;
|
||||
cursor: pointer;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.prompt{
|
||||
margin-top: 2.5rem;
|
||||
.example-wrapper {
|
||||
gap: 4rem;
|
||||
.example-item {
|
||||
> .imgItem{
|
||||
height: 45.7rem;
|
||||
img {
|
||||
height: 100%;
|
||||
}
|
||||
> .info{
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
line-height: 2.2rem;
|
||||
text-align: center;
|
||||
background-color: #fff;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
> .textCopy{
|
||||
margin-top: 3rem;
|
||||
width: 22.8rem;
|
||||
height: 6.6rem;
|
||||
border-radius: 8px;
|
||||
word-break: break-word;
|
||||
white-space: pre-wrap;
|
||||
border: 1px solid #000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #969696;
|
||||
padding: 0 1.3rem;
|
||||
position: relative;
|
||||
> .copy-icon{
|
||||
position: absolute;
|
||||
right: .7rem;
|
||||
top: .7rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.download-icon {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// .prompt-list {
|
||||
// margin-top: 3.5rem;
|
||||
// display: flex;
|
||||
// column-gap: 6.3rem;
|
||||
// .prompt-item {
|
||||
// height: 12.8rem;
|
||||
// line-height: 2.3rem;
|
||||
// padding: 1.8rem 3.5rem 1.8rem 2rem;
|
||||
// color: #969696;
|
||||
// font-size: 1.9rem;
|
||||
// border: 1px solid #000;
|
||||
// border-radius: 0.8rem;
|
||||
// overflow-y: auto;
|
||||
// position: relative;
|
||||
// // &:first-child{
|
||||
// // width: 53.6rem;
|
||||
// // }
|
||||
// .copy-icon {
|
||||
// position: absolute;
|
||||
// top: 1.1rem;
|
||||
// right: 1rem;
|
||||
// cursor: pointer;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
.c-svg {
|
||||
width: initial;
|
||||
height: initial;
|
||||
}
|
||||
</style>
|
||||
@@ -320,7 +320,8 @@
|
||||
}"
|
||||
:isProductimg="true"
|
||||
></scaleImage>
|
||||
<Prompt v-model:showModal="showPromptAssist" :promptList="promptTextList" />
|
||||
<Prompt v-if="productimgMenu.value == 'ToProductImage'" v-model:showModal="showPromptAssist" :promptList="promptTextList" />
|
||||
<PromptEditProduct v-if="productimgMenu.value == 'Relight'" v-model:showModal="showPromptAssist"></PromptEditProduct>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -353,6 +354,7 @@ import scaleImage from '@/component/HomePage/scaleImage.vue'
|
||||
import generalMenu from '@/component/HomePage/generalMenu.vue'
|
||||
import generalDrag from '@/component/modules/generalDrag.vue'
|
||||
import Prompt from './Prompt.vue'
|
||||
import PromptEditProduct from './PromptEditProduct.vue'
|
||||
import { List } from 'echarts'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
|
||||
@@ -361,7 +363,8 @@ export default defineComponent({
|
||||
scaleImage,
|
||||
generalMenu,
|
||||
generalDrag,
|
||||
Prompt
|
||||
Prompt,
|
||||
PromptEditProduct
|
||||
},
|
||||
props: {
|
||||
setTask: {
|
||||
|
||||
Reference in New Issue
Block a user