Ai_GirlFriend/xuniYou/pages/create/lover.vue
2026-01-31 19:15:41 +08:00

599 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view>
<view class="body">
<view class="list">
<view class="list_create faj">
<text class="faj" v-if="!loverBasicList" @click="imageClick">+创建形象</text>
<text class="faj" v-if="loverBasicList" @click="imageClick">+修改形象</text>
</view>
<view class="list_content">
<view class="list_title">恋人性别</view>
<view class="list_item fa">
<view class="list_table" v-for="(item, index) in genderList" :key="index"
:class="genderIndex == index ? 'list_active' : ''" @click="genderClick(index)">
<image class="list_sexImage" :src="item.image" mode="aspectFill"></image>
<view class="list_name" :style="genderIndex == index ? 'list_active' : ''">{{ item.name }}
</view>
<image class="list_tag" v-if="genderIndex == index" src="/static/images/lover_back.png"
mode="aspectFill"></image>
</view>
</view>
</view>
<view class="list_content fa">
<view class="list_title">昵称</view>
<input class="f1" v-model="form.name" placeholder="给虚拟梦中人起个名字" placeholder-class="list_input" />
</view>
<view class="list_contentCharacter">
<view class="list_title">人物简介</view>
<textarea class="" v-model="form.intro" placeholder="一句话描述这个人物信息" maxlength="50"
@input="openingIntroNum" placeholder-class="list_textarea" />
<view class="list_count">{{ openingIntroNumber }}/50</view>
</view>
<view class="list_content">
<view class="list_title">性格模板</view>
<view class="list_detail fa">
<view class="list_text f1 fa wp">
<text class="faj" v-for="(item, index) in personalityOptions" :key="index"
@click="personalityClick(index)"
:class="personalityIndex == index ? 'list_actives' : ''">{{ item.name }}</text>
</view>
</view>
</view>
<view class="list_contents">
<view class="list_title">故事背景</view>
<textarea class="" v-model="form.story_background" maxlength="100" @input="storyBackgroundNum"
placeholder="添加虚拟人设,如身份、经历、性格等" placeholder-class="list_textarea" />
<view class="list_count">{{ storyBackgroundNumber }}/100</view>
</view>
<view class="list_contents">
<view class="list_title">开场白</view>
<textarea class="" v-model="form.opening_line" maxlength="20" @input="openingRemarksNum"
placeholder="说点什么来开启聊天吧" placeholder-class="list_textarea" />
<view class="list_count">{{ openingRemarksNumber }}/20</view>
</view>
<view class="list_content">
<view class="list_title">兴趣标签</view>
<view class="list_detail fa">
<view class="list_text f1 fa wp">
<text class="faj" v-for="(item, index) in hobbyOptions" :key="index"
@click="hobbyClick(index)" :class="hobbyIndex.includes(index) ? 'list_actives' : ''">{{
item.name }}</text>
</view>
</view>
</view>
<view class="list_content fa">
<view class="list_title">音色</view>
<view class="list_timbre f1 fa sb" @click="timbreClick">
<text class="f1">{{ currentVoice.name || voicesInfo || '请选择音色' }}</text>
<image src="/static/images/more.png" mode="widthFix"></image>
</view>
</view>
</view>
</view>
<view class="opt">
<view class="opt_module">
<view class="opt_data">
<view class="opt_btn faj" @click="submit">
保存形象
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
GetLoverConfig,
LoverConfig,
GetLoverOptions,
} from '@/utils/api.js'
import {
isPhone
} from '@/utils/utils.js'
import notHave from '@/components/not-have.vue';
import topSafety from '@/components/top-safety.vue';
// 导入Pinia store
import { useVoiceStore } from '@/store/index.js'
export default {
components: {
notHave,
topSafety,
},
data() {
return {
form: {
gender: '',
name: '',
intro: '',
personality_tag: '',
story_background: '',
opening_line: '',
interest_tags: [],
},
storyBackgroundNumber: 0,
openingRemarksNumber: 0,
openingIntroNumber: 0,
genderList: [{
name: '男生',
image: 'https://nvlovers.oss-cn-qingdao.aliyuncs.com/uploads/20251226/e90acc9a7675bb463188a8ecf8f46054.png',
id: 'male',
},
{
name: '女生',
image: 'https://nvlovers.oss-cn-qingdao.aliyuncs.com/uploads/20251231/a8b27c789ba9515ac0d07f77a3913d0b.png',
id: 'female',
},],
genderIndex: 0,
getLoverConfigList: '',
personalityOptions: [],
personalityIndex: -1,
getLoverOptionsList: '',
hobbyOptions: [], // 添加兴趣标签选项数据
hobbyIndex: [], // 添加兴趣标签选中索引
voicesInfo: '', // 添加音色信息
timbre: '',
loverBasicList: '',
}
},
computed: {
// 计算属性从Pinia store获取当前音色
currentVoice() {
const voiceStore = useVoiceStore()
return voiceStore.currentVoice
}
},
onLoad() {
this.getLoverConfig()
},
onShow() {
// 页面显示时从Pinia store获取最新的音色信息
const voiceStore = useVoiceStore()
if (voiceStore.selectedVoiceId) {
this.voicesInfo = voiceStore.selectedVoiceName
this.timbre = voiceStore.selectedVoiceId
}
if (uni.getStorageSync('loverBasicList')) {
this.loverBasicList = uni.getStorageSync('loverBasicList')
}
},
methods: {
getLoverConfig() {
GetLoverConfig({}).then(res => {
if (res.code == 1) {
this.getLoverConfigList = res.data
this.genderIndex = this.getLoverConfigList.gender == 'male' ? 0 : 1//0:男生 1:女生,默认根据接口选择男女
this.form.gender = this.getLoverConfigList.gender//默认根据接口获取性别
this.personalityOptions = this.getLoverConfigList.personality_options // 默认从总接口获取性格模板
this.form.personality_tag = this.personalityOptions[0].id // 默认选择第一个性格模板
this.hobbyOptions = this.getLoverConfigList.hobby_options // 获取兴趣标签选项
if (this.getLoverConfigList.lover.voice_id != null) {
for (let i = 0; i < this.getLoverConfigList.voices.length; i++) {
if (this.getLoverConfigList.voices[i].id == this.getLoverConfigList.lover.voice_id) {
this.voicesInfo = this.getLoverConfigList.voices[i].name
this.timbre = this.getLoverConfigList.voices[i].id
}
}
} else {
for (let i = 0; i < this.getLoverConfigList.voices.length; i++) {
if (this.getLoverConfigList.voices[i].id == this.getLoverConfigList.default_voice_id) {
this.voicesInfo = this.getLoverConfigList.voices[i].name
this.timbre = this.getLoverConfigList.voices[i].id
}
}
}
const voiceStore = useVoiceStore()
voiceStore.setVoice(this.timbre, this.voicesInfo)
} else {
uni.showToast({
title: res.msg,
icon: 'none',
position: 'top'
})
}
})
},
LoverConfig() {
LoverConfig(this.form).then(res => {
if (res.code == 1) {
uni.showToast({
title: '保存成功',
icon: 'none',
position: 'top'
})
setTimeout(() => {
uni.navigateBack({
delta: 1,
});
}, 500);
} else {
uni.showToast({
title: res.msg,
icon: 'none',
position: 'top'
})
}
})
},
getLoverOptions() {
GetLoverOptions(
{ gender: this.form.gender }
).then(res => {
if (res.code == 1) {
this.getLoverOptionsList = res.data
this.personalityOptions = this.getLoverOptionsList.personality_options
this.form.personality_tag = this.personalityOptions[0].id // 默认选择第一个性格模板的id
this.personalityIndex = 0// 默认选择第一个性格模板
this.form.interest_tags = []// 默认兴趣标签为空
this.hobbyIndex = []// 默认兴趣标签选中索引为空
for (let i = 0; i < this.getLoverOptionsList.voices.length; i++) {
if (this.getLoverOptionsList.voices[i].id == this.getLoverOptionsList.default_voice_id) {
this.voicesInfo = this.getLoverOptionsList.voices[i].name
this.timbre = this.getLoverOptionsList.voices[i].id
break;
}
}
const voiceStore = useVoiceStore()
voiceStore.setVoice(this.timbre, this.voicesInfo)
} else {
uni.showToast({
title: res.msg,
icon: 'none',
position: 'top'
})
}
})
},
genderClick(index) {
this.genderIndex = index
this.form.gender = this.genderList[index].id
this.form.name = ''
this.form.intro = ''
this.form.personality_tag = ''
this.form.story_background = ''
this.form.opening_line = ''
this.form.interest_tags = []
this.getLoverOptions()
},
personalityClick(index) {
this.personalityIndex = index
this.form.personality_tag = this.personalityOptions[index].id
},
hobbyClick(index) {
const currentIndex = this.hobbyIndex.indexOf(index);
if (currentIndex > -1) {
// 如果已选中,则取消选中
this.hobbyIndex.splice(currentIndex, 1);
this.form.interest_tags.splice(currentIndex, 1);
} else {
// 如果未选中,先检查是否已达到最大选择数
if (this.hobbyIndex.length >= 3) {
uni.showToast({
title: '最多只能选择3个兴趣标签',
icon: 'none',
position: 'top'
});
return; // 不做任何操作
}
// 未达到最大选择数,添加选中
this.hobbyIndex.push(index);
this.form.interest_tags.push(this.hobbyOptions[index].id);
}
},
storyBackgroundNum(e) {
this.storyBackgroundNumber = e.detail.value.length;
},
openingRemarksNum(e) {
this.openingRemarksNumber = e.detail.value.length;
},
openingIntroNumber(e) {
this.openingIntroNumber = e.detail.value.length;
},
submit() {
console.log(this.form)
if (this.form.name == '') {
uni.showToast({
title: "请输入昵称",
icon: 'none',
position: 'top'
})
} else if (this.form.intro == '') {
uni.showToast({
title: "请输入人物简介",
icon: 'none',
position: 'top'
})
} else if (this.form.personality_tag == '') {
uni.showToast({
title: "请选择性格模板",
icon: 'none',
position: 'top'
})
} else if (this.form.story_background == '') {
uni.showToast({
title: "请输入故事背景",
icon: 'none',
position: 'top'
})
} else if (this.form.opening_line == '') {
uni.showToast({
title: "请输入开场白",
icon: 'none',
position: 'top'
})
} else if (this.form.interest_tags.length == 0) {
uni.showToast({
title: "请选择兴趣标签",
icon: 'none',
position: 'top'
})
} else {
console.log(this.form)
this.LoverConfig()
}
},
imageClick() {
uni.navigateTo({
url: '/pages/create/image'
})
},
timbreClick() {
uni.navigateTo({
url: '/pages/create/timbre?sex=' + this.form.gender
})
},
}
}
</script>
<style>
page {
background: #F6F8FA;
}
</style>
<style>
.body {
position: relative;
padding: 0 50rpx 50rpx 50rpx;
}
.list {
position: relative;
margin: 54rpx 0 0 0;
}
.list_create {
position: relative;
margin: 0 0 70rpx 0;
}
.list_create text {
padding: 20rpx 58rpx;
font-weight: 400;
font-size: 30rpx;
color: #222222;
line-height: 50rpx;
background: #FFFFFF;
border-radius: 254rpx;
}
.list_content {
position: relative;
margin: 0 0 30rpx 0;
padding: 30rpx 40rpx;
background: #FFFFFF;
border-radius: 12rpx;
box-sizing: border-box;
}
.list_title {
margin: 0 80rpx 0 0;
font-weight: 500;
font-size: 32rpx;
color: #222222;
line-height: 50rpx;
}
.list_title text {
color: #817EFE;
}
.list_item {
position: relative;
margin: 30rpx 0 0 0;
}
.list_table {
position: relative;
margin: 0 32rpx 0 0;
padding: 8rpx 6rpx;
width: 168rpx;
background: #FAFAFA;
border-radius: 12rpx;
border: 2rpx solid #FAFAFA;
}
.list_sexImage {
width: 100%;
height: 136rpx;
display: block;
}
.list_name {
font-weight: 400;
font-size: 30rpx;
color: #333333;
line-height: 50rpx;
text-align: center;
}
.list_active {
color: #817EFE;
border: 2rpx solid #817EFE;
}
.list_tag {
position: absolute;
right: 0;
top: 0;
width: 42rpx;
height: 32rpx;
}
.list_content input {
font-weight: 400;
font-size: 30rpx;
color: #333;
line-height: 50rpx;
}
.list_input {
color: #D3D3D3;
}
.list_contentCharacter {
position: relative;
margin: 0 0 30rpx 0;
padding: 30rpx 40rpx 60rpx 40rpx;
background: #FFFFFF;
border-radius: 12rpx;
box-sizing: border-box;
}
.list_contentCharacter textarea {
margin: 22rpx 0 0 0;
height: 70rpx;
font-weight: 400;
font-size: 30rpx;
color: #333;
line-height: 50rpx;
}
.list_contents {
position: relative;
margin: 0 0 30rpx 0;
padding: 30rpx 40rpx 60rpx 40rpx;
background: #FFFFFF;
border-radius: 12rpx;
box-sizing: border-box;
}
.list_contents textarea {
margin: 22rpx 0 0 0;
height: 125rpx;
font-weight: 400;
font-size: 30rpx;
color: #333;
line-height: 50rpx;
}
.list_textarea {
color: #ADADAD;
}
.list_count {
position: absolute;
right: 30rpx;
bottom: 14rpx;
font-weight: 400;
font-size: 26rpx;
color: #ADADAD;
line-height: 50rpx;
}
.list_timbre {
position: relative;
}
.list_timbre text {
width: 148rpx;
height: 50rpx;
font-family: Alibaba PuHuiTi 3.0, Alibaba PuHuiTi 30;
font-weight: 400;
font-size: 30rpx;
color: #ADADAD;
line-height: 50rpx;
text-align: left;
font-style: normal;
text-transform: none;
}
.list_timbre image {
width: 8rpx;
height: 8rpx;
}
.list_detail {
position: relative;
margin: 20rpx 0 0 0;
}
.list_detail image {
width: 8rpx;
height: 8rpx;
}
.list_text {
position: relative;
}
.list_text text {
margin: 0 30rpx 30rpx 0;
padding: 0 26rpx;
font-weight: 400;
font-size: 28rpx;
color: #9E9E9E;
line-height: 50rpx;
background: #F6F8FA;
border-radius: 12rpx;
}
.list_actives {
color: #FF51B3 !important;
background: #FCE6F3 !important;
}
.opt {
position: relative;
height: 150rpx;
}
.opt_module {
position: fixed;
padding: 5rpx 0 70rpx 0;
height: 85rpx;
width: 100%;
background: #F6F8FA;
bottom: 0;
left: 0;
box-sizing: content-box;
border-top: 1px solid #f0f0f0;
z-index: 2;
}
.opt_data {
padding: 5rpx 50rpx;
font-size: 28rpx;
}
.opt_btn {
padding: 24rpx 0;
font-weight: 400;
font-size: 32rpx;
color: #FFFFFF;
line-height: 50rpx;
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%);
border-radius: 12rpx;
}
</style>