实现文本框选择功能
数据格式如下对应的是phrases.value的数据格式
let zhi = [
{
id: '2',
caption: '景别',
multiselect: false,
phrases: [
{
prompt: '近景',
promptForModel: 'maintaining a Close Shot',
previewVideoURL: ''
}
]
},
{
id: '3',
caption: '光影(多选)',
multiselect: true,
phrases: [
{
prompt: '阳光',
promptForModel: 'sunlight',
previewVideoURL: ''
}
]
}
];
s
a.vue
<template>
<div>
<div class="designer-secondary-panel" style="">
<div class="secondary-title">
<span>词库</span>
<svg class="svg-icon" aria-hidden="true" style="width: 16px; height: 16px; color: var(--color-text-1);">
<use xlink:href="#icon-close" class="svg-icon"></use>
</svg>
<el-icon class="cursor-pointer" @click="closeDialog"><el-icon-close /></el-icon>
</div>
<!---->
<!---->
<div id="designer-secondary-panel" class="secondary-content">
<div class="prompt-library-box phrase">
<el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClick">
<el-tab-pane v-for="(item,index) in tabList" :key="index" :label="item.label" :name="item.name"></el-tab-pane>
</el-tabs>
<div class="phrase-box" v-show="activeName=='first'">
<div class="category" v-for="(item,index) in phrases" :key="index">
<div class="category-caption">{{item.caption}}</div>
<div class="category-phrases">
<div
class="category-phrases-item multiple"
v-for="(itemSon,indexSon) in item.phrases"
:class="itemSon.isSelect?'active':''"
@click="selectCategory(index,indexSon)"
:key="indexSon"
>
<div class="el-tooltip__trigger">{{itemSon.prompt}}</div>
<div class="multiple-tag all-center" v-show="itemSon.isSelect&&item.multiselect">
<el-icon style="width: 16px; height: 16px; color: var(--color-text-5);"><Select /></el-icon>
</div>
<!---->
</div>
</div>
</div>
</div>
</div>
<!----><!----><!----><!----><!---->
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import {chlibraries} from '@/api/AIcreation/index';
import EventBus from '@/utils/EventBus';
const allPromptWords=ref([])
const saveRplace=ref([])
const xjYs=ref(false)
// { name: 'second', label: '我的预设' }
const tabList = ref([
{ name: 'first', label: '灵感词库' }
]);
// 记录取消选中的词语内容
const noteDelContent=ref([])
const oldNoteDContent=ref([])
const selectCategory=(ifs,is)=>{
let fatherC=phrases.value[ifs].caption;
//允许单选选择提示词
if(!phrases.value[ifs].multiselect){
if(phrases.value[ifs].phrases[is].isSelect)return;
for(let i=0;i<phrases.value[ifs].phrases.length;i++){
if(phrases.value[ifs].phrases[i].isSelect){
//保存取消选中的内容
noteDelContent.value.push(phrases.value[ifs].phrases[i].prompt)
phrases.value[ifs].phrases[i].isSelect=false;
allPromptWords.value.splice(allPromptWords.value.indexOf(phrases.value[ifs].phrases[is].prompt),1);
}
}
// 选中之前删除,取消选中词语记录数组中与之相同的内容
if(noteDelContent.value.includes(phrases.value[ifs].phrases[is].prompt)){
noteDelContent.value.splice(noteDelContent.value.indexOf(phrases.value[ifs].phrases[is].prompt),1);
}
phrases.value[ifs].phrases[is].isSelect=true;
allPromptWords.value.push(phrases.value[ifs].phrases[is].prompt);
commonEMit();
return;
}
// 多选选择提示词
if(phrases.value[ifs].phrases[is].isSelect){
phrases.value[ifs].phrases[is].isSelect=false;
console.log("多选取消选中了");
console.log(phrases.value[ifs].phrases[is]);
//保存取消选中的内容
noteDelContent.value.push(phrases.value[ifs].phrases[is].prompt)
allPromptWords.value.splice(allPromptWords.value.indexOf(phrases.value[ifs].phrases[is].prompt),1);
commonEMit();
if(!phrases.value[ifs].multiselect&&saveRplace.value.includes(fatherC)){
saveRplace.value.splice(saveRplace.value.indexOf(fatherC),1);
return;
}
return;
}
phrases.value[ifs].phrases[is].isSelect=true;
// 选中之前删除,取消选中词语记录数组中与之相同的内容
if(noteDelContent.value.includes(phrases.value[ifs].phrases[is].prompt)){
noteDelContent.value.splice(noteDelContent.value.indexOf(phrases.value[ifs].phrases[is].prompt),1);
}
allPromptWords.value.push(phrases.value[ifs].phrases[is].prompt);
commonEMit();
}
const commonOptionNoteDel=(data)=>{
}
const phrases=ref([])
const emit = defineEmits(['closeDialog','sendphrases'])
const commonEMit=()=>{
console.log("oldNoteDContent.value.length");
console.log(oldNoteDContent.value);
console.log(noteDelContent.value);
EventBus._emit('sendphrases', allPromptWords.value,noteDelContent.value);
// if(oldNoteDContent.value.length>0){
// for(let i=0;i<oldNoteDContent.value.length;i++){
// noteDelContent.value.splice(noteDelContent.value.indexOf(oldNoteDContent.value[i]),1);
// }
// }
noteDelContent.value=JSON.parse(JSON.stringify(Array.from(new Set(noteDelContent.value))))
// 记录上一次的旧数据
oldNoteDContent.value=noteDelContent.value;
}
const closeDialog=()=>{
emit('closeDialog',false)
}
const activeName = ref('first');
const handleClick = (val) => {
activeName.value = val;
};
const getChlibraries=async()=>{
let res=await chlibraries('1.6');
phrases.value=res?.data?.data?.phrases.categories
console.log(phrases.value);
}
onMounted(() => {
getChlibraries();
})
</script>
<style lang="scss" scoped>
@import "./../../../AIcreation/pages/Video/style/klindex.scss";
.designer-secondary-panel {
height: calc(100vh - 80px);
width: 400px;
.secondary-title {
width: 100%;
height: 64px;
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
background: var(--subMenuBg);
padding: 0 20px;
span {
font-size: 16px;
font-weight: bolder;
}
.svg-icon {
cursor: pointer;
}
}
.secondary-content {
padding: 20px;
width: 100%;
box-sizing: border-box;
}
}
.prompt-library-box {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
#designer-secondary-panel {
flex: none;
width: 100%;
height: calc(100vh - 144px);
// height: 100%;
background-color: var(--subMenuBg);
transition: all 0.3s ease;
}
.phrase-box {
overflow-y: scroll;
border-radius: 12px;
flex-grow: 1;
.category {
margin-bottom: 32px;
.category-caption {
font-size: 14px;
height: 24px;
line-height: 24px;
font-weight: 600;
margin-bottom: 12px;
}
.category-phrases {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.category-phrases-item {
font-size: 14px;
cursor: pointer;
position: relative;
padding: 6px 16px;
border: 1px solid var(--border-color);
border-radius: 8px;
line-height: 24px;
user-select: none;
&.active{
background-color: var(--el-color-primary);
border: 1px solid transparent;
color: #FFFFFF;
&.multiple {
position: relative;
overflow: hidden;
.multiple-tag {
width: 14px;
height: 12px;
border-radius: 4px 0;
position: absolute;
right: 0;
bottom: 0;
background: var(--el-color-primary);
}
}
}
}
}
}
.all-center {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.preset-box {
overflow: hidden;
flex-grow: 1;
display: flex;
flex-direction: column;
.operation {
height: 36px;
flex-shrink: 0;
display: flex;
margin-bottom: 24px;
}
.operation-query {
flex: 1;
}
.operation-btn {
display: flex;
height: 100%;
justify-content: center;
align-items: center;
border-radius: 8px;
background: var(--color-other-1);
margin-left: 8px;
padding: 0 12px;
color: var(--color-text-1);
cursor: pointer;
&:hover {
span {
display: inline-block;
margin-left: 4px;
}
}
span {
display: none;
font-size: 14px;
width:61px;
}
.el-icon{
font-size: 20px;
}
}
.preset-wrap {
overflow-y: scroll;
flex-grow: 1;
flex-shrink: 1;
}
.presets-list {
.preset-item {
height: 68px;
padding: 12px 16px;
margin-bottom: 8px;
cursor: pointer;
border-radius: 8px;
width: 100%;
display: flex;
background: var(--color-fill-light);
justify-content: space-between;
&:hover {
background: var(--color-other-1);
.content-wrap {
width: calc(100% - 84px);
}
}
&:hover .operation-wrap{
display: inline-flex;
display: flex;
align-items: center;
flex-shrink: 0;
gap: 20px;
}
.content-wrap {
width: 100%;
}
.operation-wrap{
display: none;
}
div{
user-select: none;
}
}
.preset-item-name {
height: 22px;
margin-bottom: 2px;
font-size: 13px;
line-height: 22px;
font-weight: 600;
color: var(--color-text-1);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.preset-item-prompt {
height: 22px;
line-height: 22px;
font-size: 13px;
color: var(--color-text-2);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.preset-edit {
display: flex;
flex-direction: column;
.preset-edit-title {
height: 24px;
line-height: 24px;
color: var(--color-text-1);
margin-bottom: 8px;
}
.edit-content {
margin-bottom: 24px;
}
.edit-operation {
width: 100%;
height: 32px;
display: flex;
align-items: center;
justify-content: flex-end;
button {
margin-left: 10px;
}
}
}
}
.kling-input {
width: 100%;
.el-input.big {
height: 36px;
}
&.el-input {
&.large {
height: 40px;
.el-input__wrapper {
padding: 8px 16px;
font-size: 14px;
}
}
&.big .el-input__wrapper {
padding: 6px 12px;
font-size: 14px;
}
.el-input__wrapper {
background: transparent;
border: solid 1px var(--color-border-component);
box-shadow: none;
border-radius: 8px;
font-weight: 400;
color: var(--color-text-1);
}
}
.el-textarea {
background-color: transparent;
padding: 12px 12px 32px;
border: 1px solid var(--color-border-component);
border-radius: 8px;
.el-textarea__inner {
background-color: transparent;
box-shadow: none;
padding: 0;
color: var(--color-text-1);
font-size: 13px;
line-height: 22px;
font-weight: 400;
border: none;
}
.el-input__count {
background: transparent;
width: calc(100% - 24px);
height: 12px;
bottom: 12px;
line-height: 12px;
color: var(--color-text-3);
}
}
}
</style>
b.vue
<template>
<el-input
v-model="creativeDescription"
type="textarea"
maxlength="2500"
:clearable="true"
:rows="8"
ref="creativeInputRef"
resize="none"
placeholder="请描述你想生成的视频内容"
></el-input>
</template>
<script setup lang="ts">
onMounted(async () => {
//触发增加文本内容
EventBus._on('sendphrases', (data,delContent) => {
getAllWorTsc.value=data.join(',')
creativeDescription.value = [...creativeDescription.value.split(',').filter(item => !data.includes(item)),...data].join(',')
let zhi=[];
//判断将内容删除一部分
if(delContent.length>0){
zhi=creativeDescription.value.split(',');
delContent.forEach((vs,index)=>{
if(zhi.includes(vs)){
zhi.splice(zhi.indexOf(vs),1)
}
})
creativeDescription.value=zhi.join(',')
}
})
})
onBeforeUnmount(() => {
EventBus._off('sendphrases');
});
</script>