抖音小程序端
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.

845 lines
23 KiB

<template>
<view class="container">
<uni-forms :modelValue="formData" ref="form" validate-trigger='blur'>
<!-- 提示词 -->
3 years ago
<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>
3 years ago
<view>
<view class="head">
<view class="left">
<view class="title">高级设置<uni-icons class="tip-vip-icon" custom-prefix="iconfont" type="icon-tipvip" size="26" color="#f3a73f"/></view>
3 years ago
</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>
3 years ago
<!-- <view class="form-item">
3 years ago
<view class="form-label">生成数量</view>
<uni-number-box v-model="formData.batchSize" :step="1" :min="1" :max="4" />
3 years ago
</view> -->
3 years ago
<view class="form-item">
<view class="form-label display-flex-sb">
<view class="left-title">关键词相关性</view>
<view class="right-title">{{formData.sfgScale || 7}}</view>
3 years ago
</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>
3 years ago
</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>
3 years ago
</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">开始创作<br/>消耗{{formData.goldNum}}点画意值</button>
</view> -->
<view class="startPaint" @click="$noMultipleClicks(startPaint)">
3 years ago
开始创作<br/><span :style="{fontSize: '12px'}">消耗({{formData.goldNum}}点画意值)</span>
</view>
</view>
</uni-forms>
</view>
</template>
<script>
import base64ToImg from '@/utils/base64Utils';
import {getPaintStyle, getPrompt, textToImg} from '@/api/paint.js';
3 years ago
import {checkVip} from "@/api/paint";
export default {
data() {
return {
primaryColor: "#1a94bc",
formData:{
height: undefined,
width: undefined,
modelName: undefined,
styleName: undefined,
promptText: undefined,
3 years ago
negativePrompt: undefined, //反向词
seed: -1, //种子
batchSize: 1, //批量数量
sfgScale: 7, //精细度
steps: 20, //采样步骤
eta: 0, //差异强度
samplerIndex: "DPM++ SDE Karras", //采样器
goldNum: 2, //画意值
},
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,
3 years ago
text: '正方形',
height: 512,
width: 512
},
{
id: 2,
3 years ago
text: '宽屏',
height: 512,
width: 1024
},
{
id: 3,
3 years ago
text: '竖屏',
height: 1024,
width: 512
}
],
3 years ago
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() {
console.log('show')
//进入页面清空原始属性
this.formData.height = undefined;
this.formData.width = undefined;
this.formData.modelName = undefined;
this.formData.styleName = undefined;
this.formData.promptText = undefined;
3 years ago
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 = "DPM++ 2S a Karras";
this.size_active = 0;
this.style_active = 0;
this.prompt_active = 0;
this.checkLogin();
//this.checkUserCanAiPaint();
this.$forceUpdate();
},
onShareAppMessage(res) {
if (res.from === 'button') { // 来自页面内分享按钮
// console.log(res)
}
return {
title: '来[次元意境]获取好看的图纸头像吧!',
path: `/pages/ai/paint/paint`
}
},
methods: {
//高级绘画开关控制
3 years ago
openAdvancedSetting(e) {
3 years ago
console.log('e',e)
let that = this;
3 years ago
if (e.detail.value) {
checkVip({userId: that.userInfo.id, userClientType: 10}).then(res => {
3 years ago
if (res && res.data.code === 200) {
3 years ago
if (res.data.data.isVip === "1") {
that.advancedSetting = e.detail.value;
3 years ago
} else {
that.advancedSetting = !e.detail.value;
3 years ago
uni.showModal({
title: '你还不是VIP',
content: '点击确定解锁更多权益哟~',
cancelText: '狠心拒绝',
cancelColor: '#ff0000',
3 years ago
confirmColor: '#1a94bc',
confirmText: '立刻前往',
3 years ago
success(res){
if (res.confirm) {
//跳转vip界面
3 years ago
uni.navigateTo({
url:'/pages/userInfo/vip/vip'
})
}else if(res.cancel){
uni.showToast({
title:'开通会员享受更多高级功能哟!',
icon: 'none',
duration: 2000,
success() {
that.advancedSetting = false;
3 years ago
}
});
}
},
});
}
}
// else {
// uni.showModal({
// content: '网络错误,请稍后再试~',
// showCancel: false
// });
// }
3 years ago
});
3 years ago
} 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`;
}
3 years ago
},
//翻译
//判断是否登录
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:'您还没有登录!点击确定跳转登录界面以体验服务',
3 years ago
showCancel: false,
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)
3 years ago
//判断是否可进行ai绘画 TODO 暂时关闭校验
if(that.checkData.checkCanPaint === true){
return uni.showToast({
title: '画意值不足!请充值或完成相应任务获取更多次数!',
icon: 'none'
})
}
3 years ago
//判断必填项是否都填了
//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,
3 years ago
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, //此处1代表抖音
goldNum: that.formData.goldNum
}
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();
3 years ago
if (res && res.data.code === 200) {
this.paintStyle = res.data.data
//console.log('this.paintStyle',this.paintStyle)
}else {
uni.showModal({
content: '绘画风格加载失败!',
showCancel: false
});
}
},
//获取提示词列表
async getPrompt() {
3 years ago
const res = await getPrompt("0");
3 years ago
if (res && 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;
}
3 years ago
.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;
}
}
}
3 years ago
.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;
}
}
3 years ago
.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;
left: 25%;
}
.startPaint{
width: 400rpx;
height: 100rpx;
bottom: 50rpx;
background-color: $uni-primary;
// border: 1px solid $uni-primary;
border-radius: 50rpx;
padding-bottom: 50 rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #fff;
font-size: 16px;
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>