抖音小程序端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

786 lines
22 KiB

<template>
<view class="container">
<uni-forms :modelValue="formData" ref="form" validate-trigger='blur'>
<!-- 提示词 -->
<view class="promptText">
<view class="head">
<view class="left">
<view class="title">绘画关键词</view>
</view>
</view>
<view>
<uni-easyinput type="textarea" autoHeight v-model="formData.promptText" placeholder="请输入想生成画的关键词" class="promptInput" @blur="checkPrompt(formData.promptText)"></uni-easyinput>
</view>
<view class="checkPromptText" v-if="checkData.checkPrompt == false">
<text>请输入关键词!</text>
</view>
</view>
<view class="keywords">
<view class="head">
<view class="left">
<view class="title">提示词示例</view>
</view>
<view class="right" @click="getRandPrompt">
<view class="title">换一批</view>
<view class="icon">
<uni-icons type="refreshempty" size="14" :color="primaryColor"></uni-icons>
</view>
</view>
</view>
<view class="lists">
<view @click="onClickPrompt(index)" :class="index == prompt_active?'item active':'item'"
v-for="(item,index) in promptList" :key="index">{{ item.text }}</view>
</view>
</view>
<!-- 创作风格 -->
<view class="style">
<view class="head">
<view class="left">
<view class="title">选择创作风格</view>
</view>
</view>
</view>
<scroll-view scroll-x="true" class="styleBox">
<block v-for="(item,index) in paintStyle" :key="index">
<view class="styleItem" :class="style_active == item.id?'styleItem styleActive':'styleItem'" @click="onClickStyle(item.id,item.modelName,item.name)" @touchend="checkStyle()">
<image :src="item.imgUrl" class="styleCover" mode="aspectFill"></image>
<text class="styleName">{{item.name}}</text>
</view>
</block>
</scroll-view>
<view class="checkStyleBox" v-if="checkData.checkStyleBox == false">
<text>请选择创作风格!</text>
</view>
<!-- 尺寸 -->
<view class="size">
<view class="head">
<view class="left">
<view class="title">选择画布大小</view>
</view>
</view>
<view class="lists">
<view :class="size_active==item.id?'item active':'item'" @click="onClickSize(item.id,item.height,item.width)"
v-for="(item,index) in size" :key="index" @touchend="checkSize()">{{ item.text }}</view>
</view>
<view class="checkSize" v-if="checkData.checkSize == false">
<text>请选择画布大小!</text>
</view>
</view>
<view>
<view class="head">
<view class="left">
<view class="title">高级设置<uni-icons class="tip-vip-icon" custom-prefix="iconfont" type="icon-tipvip" size="14" color="#f3a73f"/></view>
</view>
<view class="right">
<switch :checked="advancedSetting" :color="primaryColor" style="transform:scale(0.7)" @change="openAdvancedSetting"/>
</view>
</view>
<view class="advanced-setting" v-if="advancedSetting">
<view class="form-item">
<view class="form-label">反向词</view>
<uni-easyinput type="textarea" autoHeight v-model="formData.negativePrompt" placeholder="请输入我不想生成的词" class="promptInput" ></uni-easyinput>
</view>
<view class="form-item">
<view class="form-label">种子(随机种子为-1)</view>
<input class="uni-input" v-model="formData.seed" type="number" placeholder="请输入种子" />
</view>
<view class="form-item">
<view class="form-label">生成数量</view>
<uni-number-box v-model="formData.batchSize" :step="1" :min="1" :max="4" />
</view>
<view class="form-item">
<view class="form-label display-flex-sb">
<view class="left-title">关键词相关性</view>
<view class="right-title">{{formData.sfgScale ?? 7}}</view>
</view>
<slider :step="1" :min="0" :max="80" :block-size="12" :activeColor="primaryColor"
@change="(e) => {this.formData.sfgScale = (e.detail.value * 0.1 + 7).toFixed(1)}"
@changing="(e) => {this.formData.sfgScale = (e.detail.value * 0.1 + 7).toFixed(1)}"
/>
</view>
<view class="form-item">
<view class="form-label display-flex-sb">
<view class="left-title">绘画步骤</view>
<view class="right-title">{{formData.steps ?? 20}}</view>
</view>
<slider :step="1" :min="20" :max="30" :block-size="12" :activeColor="primaryColor"
@change="(e) => {this.formData.steps = e.detail.value}"
@changing="(e) => {this.formData.steps = e.detail.value}"
/>
</view>
<view class="form-item">
<view class="form-label display-flex-sb">
<view class="left-title">差异强度</view>
<view class="right-title">{{formData.eta ?? 0}}</view>
</view>
<slider :step="1" :min="0" :max="10" :block-size="12" :activeColor="primaryColor"
@change="(e) => {this.formData.eta = (e.detail.value * 0.1).toFixed(1)}"
@changing="(e) => {this.formData.eta = (e.detail.value * 0.1).toFixed(1)}"
/>
</view>
<view class="form-item">
<view class="form-label">采样方法</view>
<uni-data-checkbox mode="button" v-model="formData.samplerIndex" :localdata="samplerIndexArr" :selectedColor="primaryColor" :selectedTextColor="primaryColor"></uni-data-checkbox>
</view>
</view>
</view>
<view class="bottom">
<view>
<button type="default" @click="$noMultipleClicks(startPaint)" class="startPaint">开始创作</button>
</view>
</view>
</uni-forms>
</view>
</template>
<script>
import base64ToImg from '@/utils/base64Utils';
import {getPaintStyle, getPrompt, textToImg, checkUserCanAiPaint} from '@/api/paint.js';
import {checkVip} from "@/api/paint";
export default {
data() {
return {
primaryColor: "#1a94bc",
formData:{
height: undefined,
width: undefined,
modelName: undefined,
styleName: undefined,
promptText: undefined,
negativePrompt: undefined, //反向词
seed: -1, //种子
batchSize: 1, //批量数量
sfgScale: 7, //精细度
steps: 20, //采样步骤
eta: 0, //差异强度
samplerIndex: "Euler a", //采样器
},
checkData:{
checkPrompt: undefined, //true填了内容;false未填内容
checkStyleBox: undefined, //true选了创作风格;false未选创作风格
checkSize: undefined, //true选了画布大小;false未选画布大小
checkCanPaint: false, //true已达到最大绘画上限;false未达最高上限
},
userInfo: {},
noClick:true, //防止重复提交
promptList: [],
paintStyle:[],
size_active: 0,
prompt_active: 0,
style_active: 0,
size: [
{
id: 1,
text: '正方形',
height: 512,
width: 512
},
{
id: 2,
text: '宽屏',
height: 512,
width: 1024
},
{
id: 3,
text: '竖屏',
height: 1024,
width: 512
}
],
advancedSetting: false,
samplerIndexArr: [
{text:"Euler a", value:"Euler a"},
{text:"Euler", value:"Euler"},
{text:"LMS", value:"LMS"},
{text:"Heun", value:"Heun"},
{text:"DPM2", value:"DPM2"},
{text:"DPM2 a", value:"DPM2 a"},
{text:"DPM++ 2S a", value:"DPM++ 2S a"},
{text:"DPM++ 2M", value:"DPM++ 2M"},
{text:"DPM++ SDE", value:"DPM++ SDE"},
{text:"DPM fast", value:"DPM fast"},
{text:"DPM adaptive", value:"DPM adaptive"},
{text:"LMS Karras", value:"LMS Karras"},
{text:"DPM2 Karras", value:"DPM2 Karras"},
{text:"DPM2 a Karras", value:"DPM2 a Karras"},
{text:"DPM++ 2S a Karras", value:"DPM++ 2S a Karras"},
{text:"DPM++ 2M Karras", value:"DPM++ 2M Karras"},
{text:"DPM++ SDE Karras", value:"DPM++ SDE Karras"},
{text:"DDIM", value:"DDIM"},
{text:"PLMS", value:"PLMS"}
],
}
},
created() {
//this.base64ToPath();
},
onLoad() {
this.getPaintStyleList();
this.getPrompt();
},
onShow() {
//进入页面清空原始属性
this.formData.height = undefined;
this.formData.width = undefined;
this.formData.modelName = undefined;
this.formData.styleName = undefined;
this.formData.promptText = undefined;
this.advancedSetting = false;
this.formData.sfgScale = undefined;
this.formData.negativePrompt = undefined;
this.formData.seed = -1;
this.formData.batchSize = 1;
this.formData.sfgScale = 7;
this.formData.steps = 20;
this.formData.eta = 0;
this.formData.samplerIndex = "Euler a";
this.size_active = 0;
this.style_active = 0;
this.prompt_active = 0;
this.checkLogin();
this.checkUserCanAiPaint();
},
methods: {
openAdvancedSetting(e) {
if (e.detail.value) {
checkVip({userId: this.userInfo.id, userClientType: "10"}).then(res => {
if (res.data.code === 200) {
if (res.data.data.isVip === "1") {
this.advancedSetting = e.detail.value;
} else {
this.advancedSetting = !e.detail.value;
uni.showToast({
title: '还不是会员,开通会员后再尝试',
icon: 'none'
})
}
}
})
} else {
this.advancedSetting = e.detail.value;
// this.formData.sfgScale = undefined;
// this.formData.negativePrompt = undefined;
// this.formData.seed = -1;
// this.formData.batchSize = 1;
// this.formData.sfgScale = 7;
// this.formData.steps = 20;
// this.formData.eta = 0;
// this.formData.samplerIndex = `Euler a`;
}
},
//翻译
//判断是否登录
checkLogin(){
let that = this;
that.userInfo = uni.getStorageSync('userInfo');
console.log('userInfo:',that.userInfo)
let token = uni.getStorageSync('token');
if((Object.keys(that.userInfo).length==0) && (Object.keys(token).length==0)){
console.error('尚未登录!');
uni.showModal({
title:'提示',
content:'您还没有登录!点击确定跳转登录界面以体验服务',
success(res) {
if (res.confirm) {
//跳转登录界面
uni.switchTab({
url: '/pages/userInfo/userInfo'
});
}else if(res.cancel){
uni.showToast({
title:'登录获取更好的服务体验哟!',
duration: 2000
});
}
}
});
}
},
//传递参数到下个界面开始绘图
startPaint(){
const that = this;
//console.log('that.checkData.checkCanPaint',that.checkData.checkCanPaint)
//判断是否可进行ai绘画 TODO 暂时关闭校验
if(that.checkData.checkCanPaint === true){
return uni.showToast({
title: '次数已用完,关注次元意境官方账号获得更多次数!',
icon: 'none'
})
}
//判断必填项是否都填了
//console.log('创作prompt为:',that.formData.promptText)
// console.log('创作尺寸高度为:',that.formData.height)
// console.log('创作尺寸宽度为:',that.formData.width)
//console.log('创作风格为:',that.formData.styleName)
if(that.formData.promptText == undefined){
uni.showToast({
title: '请输入提示词!',
duration: 1000,
icon: 'fail'
});
}else if(that.formData.styleName == undefined){
uni.showToast({
title: '请选择创作风格!',
duration: 1000,
icon: 'fail'
});
}else if(that.formData.height == undefined || that.formData.width == undefined){
uni.showToast({
title: '请选择画布大小!',
duration: 1000,
icon: 'fail'
});
}else{
//跳转详情页生成图片
uni.showModal({
title: '温馨提示',
content: '任务创建完成,点击跳转生成内容!',
success(res) {
if(res.confirm){
const data = {
width: that.formData.width,
height: that.formData.height,
prompt: that.formData.promptText,
modelName: that.formData.modelName,
styleName: that.formData.styleName,
negativePrompt: that.formData.negativePrompt, //反向词
seed: that.formData.seed, //种子
batchSize: that.formData.batchSize, //批量数量
sfgScale: that.formData.sfgScale, //精细度
steps: that.formData.steps, //采样步骤
eta: that.formData.eta, //差异强度
samplerIndex: that.formData.samplerIndex, //采样器
painterId: that.userInfo.id,
painterName: that.userInfo.username,
appType: 0,
platform: 1
}
uni.navigateTo({
url: './paintDetail?data='+JSON.stringify(data)
})
}
}
});
}
},
//检查是否输入提示词
checkPrompt(value){
//console.log('校验提示词',value);
if(value == "" || value == null || value == undefined){
this.checkData.checkPrompt = false;
}else{
this.checkData.checkPrompt = true;
}
//console.log('this.checkData.checkPrompt',this.checkData.checkPrompt)
},
//检查是否选择创作风格
checkStyle(){
//console.log('校验创作风格');
//console.log('滑动后选泽风格为',this.formData.styleName)
if(this.formData.styleName == "" || this.formData.styleName == null || this.formData.styleName == undefined){
this.checkData.checkStyleBox = false;
}else{
this.checkData.checkStyleBox = true;
}
//console.log('this.checkData.checkStyleBox',this.checkData.checkStyleBox)
},
//检查是否选择画布大小
checkSize(){
//console.log('校验画布大小');
if(this.formData.height == "" || this.formData.height == null || this.formData.height == undefined ||
this.formData.width == "" || this.formData.width == null || this.formData.width == undefined){
this.checkData.checkSize = false;
}else{
this.checkData.checkSize = true;
}
//console.log('this.checkData.checkSize',this.checkData.checkSize)
},
//画布大小
onClickSize(id,height,width) {
this.size_active = id
this.formData.height = height
this.formData.width = width
//拖底消除校验状态
if(this.checkData.checkSize === false){
this.checkData.checkSize = true;
}
//console.log('所选尺寸id为:',this.size_active)
//console.log('所选尺寸高度为:',this.formData.height)
//console.log('所选尺寸宽度为:',this.formData.width)
},
//提示词
onClickPrompt(index) {
this.prompt_active = index
this.formData.promptText = this.promptList[index].text
//拖底消除校验状态
if(this.checkData.checkPrompt === false){
this.checkData.checkPrompt = true;
}
//console.log('this.prompt_active',this.prompt_active)
},
//创作风格
onClickStyle(id,modelName,styleName) {
this.style_active = id
this.formData.modelName = modelName
this.formData.styleName = styleName
//拖底消除校验状态
if(this.checkData.checkStyleBox === false){
this.checkData.checkStyleBox = true;
}
//console.log('所选风格id为',this.style_active)
//console.log('所选模型为',this.formData.modelName)
//console.log('所选风格为',this.formData.styleName)
},
//随机选取提示词
getRandPrompt() {
this.promptList = this.getRandomArrayElements(this.promptList, 10)
this.promptText = this.promptList[this.prompt_active].text
},
//判断是否达到免费AI绘画次数上限
async checkUserCanAiPaint(){
let that = this;
const data = {
userId: that.userInfo.id,
platform: 1,
appType: 0
}
const res = await checkUserCanAiPaint(data);
//console.log('res绘画',res)
if(res.data.code === 200){
if(res.data.data === true){
that.checkData.checkCanPaint = true;
}else{
that.checkData.checkCanPaint = false;
}
}else{
return uni.showModal({
content: '检查绘画上限失败!',
showCancel: false
});
}
},
//获取绘画风格
async getPaintStyleList() {
const res = await getPaintStyle();
if (res.data.code === 200) {
this.paintStyle = res.data.data
//console.log('this.paintStyle',this.paintStyle)
}else {
uni.showModal({
content: '绘画风格加载失败!',
showCancel: false
});
}
},
//获取提示词列表
async getPrompt() {
const res = await getPrompt();
if (res.data.code === 200) {
this.promptList = res.data.data
//console.log('this.promptList',this.promptList)
}else {
uni.showModal({
content: '提示词列表加载失败!',
showCancel: false
});
}
},
getRandomArrayElements(arr, count) {
var shuffled = arr.slice(0),
i = arr.length,
min = i - count,
temp, index;
while (i-- > min) {
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
}
return shuffled.slice(min);
},
}
}
</script>
<style lang="scss" scoped>
.container {
padding: 0 10px;
}
.head {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-bottom: 15rpx;
.left {
display: flex;
flex-direction: row;
align-items: center;
.title {
font-size: 28rpx;
.tip-vip-icon {
margin-left: 20rpx;
}
}
}
.right {
display: flex;
flex-direction: row;
align-items: center;
.title {
margin-right: 15rpx;
font-size: 24rpx;
line-height: 48rpx;
color: $uni-primary;
}
.icon {
line-height: 48rpx;
}
}
}
.size {
width: 100%;
.lists {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
.item {
background-color: $uni-white;
padding: 10rpx 20rpx;
border-radius: 10rpx;
color: $uni-base-color;
border: 1rpx solid $uni-border-4;
margin-bottom: 10rpx;
font-size: 24rpx;
margin-right: 20rpx;
}
.active {
color: $uni-white;
border: 1rpx solid $uni-primary;
background-color: $uni-primary-60; //# FFDEE0
}
}
}
.style {
width: 100%;
.lists {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
.item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 30rpx;
.title {
margin-top: 15rpx;
}
}
.active {
position: relative;
}
}
}
.keywords {
width: 100%;
margin: 15rpx auto;
.lists {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
.item {
background-color: $uni-white;
padding: 10rpx 15rpx;
border-radius: 10rpx;
color: $uni-base-color;
border: 1rpx solid $uni-border-4;
max-width: 128rpx;
margin-bottom: 10rpx;
font-size: 24rpx;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.active {
color: $uni-white;
border: 1rpx solid $uni-primary;
background-color: $uni-primary-50;
}
}
}
.styleBox{
white-space: nowrap; // 滚动必须加的属性
width: 700rpx;
margin-right: 30rpx;
//padding-right: 20rpx;
.styleItem{
width: 166rpx;
height: 170rpx;
margin-right: 20rpx;
display: inline-flex; // item的外层定义成行内元素才可进行滚动 inline-block / inline-flex 均可
flex-direction: column;
align-items: center;
border: 5rpx solid #fff;
border-radius: 10rpx;
overflow: hidden;
position: relative;
}
.styleActive {
color: $uni-primary;
border: 2rpx solid $uni-primary;
.styleName {
background-color: $uni-primary-60;
opacity: 0.9 !important;
color: $uni-white;
}
}
.styleCover{
width: 165rpx;
height: 165rpx;
}
.styleName{
font-size: 28rpx;
color: #000000;
line-height: 42rpx;
padding: 0;
width: 100%;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
position: absolute;
background-color: #FFF;
opacity: 0.5;
bottom: 0;
}
}
.advanced-setting {
margin-top: 20rpx;
padding-bottom: 100rpx;
.form-item {
input {
color: rgb(51, 51, 51);
}
.uni-input {
border: 2rpx solid $uni-border-1;
border-radius: 10rpx;
border-color: rgb(229, 229, 229);
font-size: 28rpx;
padding: 10rpx 20rpx;
}
.form-label {
font-size: 28rpx;
margin: 10rpx 0;
line-height: 38rpx;
}
.display-flex-sb {
display: flex;
justify-content: space-between;
.right-title {
color: $uni-primary;
}
}
}
}
.bottom {
width: calc(100% - 40rpx);
position: fixed;
bottom: 20rpx;
}
.startPaint{
width: 300rpx;
background-color: $uni-primary;
border: 1px solid $uni-primary;
border-radius: 40rpx;
color: $uni-white;
}
.startPaint::after {
border: 0!important;
}
.checkPromptText{
font-size: 24rpx;
color: $uni-primary;
margin-left: 36rpx;
}
.checkStyleBox{
font-size: 24rpx;
color: $uni-primary;
//margin-left: 36rpx;
}
.checkSize{
font-size: 24rpx;
color: $uni-primary;
//margin-left: 36rpx;
}
</style>