1231 lines
35 KiB
Vue
1231 lines
35 KiB
Vue
<template>
|
||
<view class="pc-workshops" :style="windowHeight>1000?{}:{ minHeight: windowHeight+'px'}">
|
||
<!-- 左侧控制台 -->
|
||
<view class="workshops-controls" v-loading="loading">
|
||
<!-- 控制台——服务列表 -->
|
||
<view class="controls-left">
|
||
<view class="cl-title">
|
||
AI创作
|
||
</view>
|
||
<view class="cl-item" :title="item.name" v-for="(item,index) in serviceList"
|
||
:key="index" :class="item.id === serviceId ? 'cl-item-selected' : ''" @click="changeWork(item,index)">
|
||
{{ item.name }}
|
||
</view>
|
||
</view>
|
||
<!-- 控制台——服务详情 -->
|
||
<view class="controls-right">
|
||
<!-- 服务顶栏 -->
|
||
<view class="control-top">
|
||
<view class="ct-title">{{ serviceItem.name }}</view>
|
||
<u-icon name="question-circle" size="35" label="宝典" color="#d2686b"
|
||
label-size="34" label-color="#d2686b" margin-left="10" @click="showTutorial" />
|
||
</view>
|
||
<!-- 服务中心 -->
|
||
<view class="control-center">
|
||
<view class="control-center-scroll">
|
||
<!-- 文生图 -->
|
||
<view class="cc-edit" v-if="serviceItem.type===1">
|
||
<EditorBox :height="200" :icon="ip+editorIcon" title="提示词"
|
||
v-model="serviceItem.text" placeholder="请输入描述的提示词(限制300词)~~" rightIcon="question-circle"
|
||
rightTip="使用教程" :rightIconClick="showTutorial" @strengthenTip="strengthenTip"/>
|
||
</view>
|
||
<!-- 生成艺术字 -->
|
||
<view class="cc-edit" v-if="serviceItem.type===3">
|
||
<u-section title="艺术字" color="#84878c" :right="false" lineColor="#c2ea04" fontSize="34" />
|
||
<u-input :customStyle="{color:'#333',fontSize:'50rpx',height:'100rpx'}" v-model="serviceItem.text"
|
||
placeholder="请输入需要生成的文字" trim inputAlign="center" :clearable="false" :maxlength="6" class="art-input"/>
|
||
</view>
|
||
<view class="cc-edit" v-if="serviceItem.type===3">
|
||
<EditorBox :height="200" :icon="ip+editorIcon" title="提示词"
|
||
v-model="serviceItem.promt" placeholder="请输入描述的提示词(限制300词)~~" rightIcon="question-circle"
|
||
rightTip="使用教程" :rightIconClick="showTutorial" @strengthenTip="strengthenTip"/>
|
||
</view>
|
||
<view class="cc-edit" v-if="serviceItem.type===1">
|
||
<u-section title="尺寸选择" color="#84878c" :right="false" lineColor="#c2ea04" fontSize="34" />
|
||
<view class="dimensional-drawing">
|
||
<view class="dimensional-item" v-for="(item,index) in (serviceItem.id === 4 ? aliDimensions : volcengineDimensions)" :key="index"
|
||
:class="selectSizeIndex===index?'dimensional-item-select':''" @click="selectSize(index)">
|
||
<view :style="{ aspectRatio: item.value }"></view>
|
||
<text>{{ item.name }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 选项生图 -->
|
||
<view class="cc-edit" v-if="serviceItem.type===2||serviceItem.type===3 || serviceItem.type === 1">
|
||
<u-section title="类型选择" color="#84878c" :right="serviceItem.options.length>8" lineColor="#c2ea04" fontSize="34" @click="showMoreOptions = true"
|
||
subTitle="更多" :subColor="selectElementIndex>=getOptions.length ? '#b3a0da' : '#84878c'"></u-section>
|
||
<view class="section-options">
|
||
<view class="section-tags" v-for="(item,index) in getOptions" :key="item.id" :title="item.optionName"
|
||
:class="selectElementIndex===index?'section-tags-select':''" @click="selectElement(index)">
|
||
<image :src="getTypeImage(item.path)"></image>
|
||
<text>{{ item.optionName }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 换衣选择 -->
|
||
<view class="cc-edit" v-if="serviceItem.type===4">
|
||
<DressSelect ref="dressRef" @previewMannequin="previewMannequin" />
|
||
</view>
|
||
<view class="use-tips">Tips:<view class="uset-content">{{ serviceItem.tips || '智能创作~' }}</view></view>
|
||
</view>
|
||
<!-- 更多类型 -->
|
||
<u-popup z-index="90" class="options-popup" v-model="showMoreOptions" mode="bottom" border-radius="30"
|
||
closeable close-icon="arrow-down" close-icon-color="#a7b6b8" :maskCustomStyle="{position: 'absolute'}">
|
||
<view class="op-content">
|
||
<view class="op-top">
|
||
<u-icon name="tags" size="42" label="更多类型" color="#a7b6b8"
|
||
label-size="35" label-color="#a7b6b8" margin-left="20"></u-icon>
|
||
</view>
|
||
<scroll-view :scrollY="true" class="options-list">
|
||
<view class="section-options">
|
||
<view class="section-tags" v-for="(item,index) in serviceItem.options" :key="item.id" :title="item.optionName"
|
||
:class="selectElementIndex===index?'section-tags-select':''" @click="selectElement(index)">
|
||
<image :src="getTypeImage(item.path)"></image>
|
||
<text>{{ item.optionName }}</text>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
</u-popup>
|
||
</view>
|
||
<!-- 服务底栏 -->
|
||
<view class="control-bottom">
|
||
<view class="cb-left">
|
||
实付:<view>{{ serviceItem.price }}<u-icon :name="fileUrl+diamondIcon" size="40" /></view>
|
||
</view>
|
||
<view class="cb-right">
|
||
<el-popover :append-to-body='false' placement="top" title="收费明细" trigger="click"
|
||
:content="`${serviceItem.name}\t1张——${serviceItem.price}💎`" v-model="detailShow">
|
||
<view slot="reference" class="popover-detail">
|
||
明细<u-icon :name="detailShow?'arrow-down':'arrow-up'" />
|
||
</view>
|
||
</el-popover>
|
||
<u-button class="cb-btn" @click="startDeal" v-if="formData.resultFile===''" :disabled="functionDisable"
|
||
:style="{opacity: functionDisable?'0.6':'1'}"
|
||
ripple :hairLine="false" shape="circle" rippleBgColor="#f0fdbf" :loading='dotLoading'>
|
||
<u-icon name="edit-pen" size="32"></u-icon>开启魔法
|
||
</u-button>
|
||
<u-button class="cb-btn cbu-btn" ripple :hairLine="false" shape="circle" v-else
|
||
rippleBgColor="#f0fdbf" @click="redraw" :class="transition?'transition':''">
|
||
<u-icon name="edit-pen" size="32"></u-icon>
|
||
<text>重新绘制</text>
|
||
</u-button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 图片上传框 -->
|
||
<view class="workshops-upload">
|
||
<el-upload class="upload-view" drag action="#" :auto-upload="false" ref="uploadCover"
|
||
:multiple="false" accept="image/*" list-type="picture-card" :class="{disabled:uploadDisabled}"
|
||
:on-change="selectImage" :file-list="formData.fileList" :disabled="formData.resultFile===''&&(serviceItem.type===3||serviceItem.type===1)">
|
||
<view class="ulview-block" v-show="formData.uploadFile === ''&&formData.resultFile===''"
|
||
:style="formData.resultFile===''&&(serviceItem.type===3||serviceItem.type===1)?{opacity:0.6,cursor: 'default'}:{}">
|
||
<image class="upload-gif" :src="fileUrl+uploadCenter"></image>
|
||
<view class="upload-title">点击 / 拖拽上传图片</view>
|
||
<view class="upload-tips">请上传大小为<text>5KB~5MB</text>的图片</view>
|
||
</view>
|
||
<template slot="file" slot-scope="{file}">
|
||
<view class="upload-preview">
|
||
<image class="up-image el-upload-list__item-thumbnail" :src="file.url" mode="aspectFit"
|
||
@click="changeLoadingImage"></image>
|
||
<view class="el-upload-list__item-actions" v-show="asyncPollTime === -1">
|
||
<span class="upload-icon el-upload-list__item-preview" @click="handlePreview()">
|
||
<u-icon size="90" :name="fileUrl+previewIcon"></u-icon>
|
||
</span>
|
||
<span class="upload-icon el-upload-list__item-delete" v-if="formData.resultFile" @click="download">
|
||
<u-icon size="90" :name="fileUrl+downloadIcon"></u-icon>
|
||
</span>
|
||
<span class="upload-icon el-upload-list__item-delete" v-else>
|
||
<u-icon size="90" :name="fileUrl+deleteIcon" @click="handleDelete(file)"></u-icon>
|
||
</span>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
</el-upload>
|
||
<view class="tip-progress" v-if="asyncPollTime !== -1">
|
||
<text class="progress-title">进度</text>
|
||
<u-line-progress class="uline-progress" :percent="dealPercent" :show-percent="false" inactive-color="#ebecef" round/>
|
||
<text class="progress-deal">{{ dealPercent }}%</text>
|
||
</view>
|
||
<view class="error-tips" v-if="errorTips">失败原因:{{ errorTips }}</view>
|
||
</view>
|
||
<!-- <Loading :show="loading"></Loading> -->
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import configService from '@/common/config.service.js';
|
||
import { ossUpload } from '@/common/ossutil/ossWebUpload.js';
|
||
import EditorBox from './components/editor.vue';
|
||
import DressSelect from './components/dress_select.vue';
|
||
import { tools } from '@/utils/utils.js';
|
||
export default {
|
||
components: { EditorBox, DressSelect },
|
||
props:{
|
||
sid: {
|
||
type: [Number,String],
|
||
default: ''
|
||
}
|
||
},
|
||
data(){
|
||
return{
|
||
// 基础路径
|
||
ip: configService.ip,
|
||
fileUrl: configService.fileUrl + 'pixel/pc/workshops/',
|
||
// 下载图标
|
||
downloadIcon: 'download.png',
|
||
// 删除图标
|
||
deleteIcon: 'delete.png',
|
||
// 预览图标
|
||
previewIcon: 'preview.png',
|
||
// 钻石图标
|
||
diamondIcon: 'diamond.png',
|
||
// 编辑图标
|
||
editorIcon: 'static/pixel/workshops/editor.png',
|
||
// 上传图片图标
|
||
uploadCenter: 'upload-center.gif',
|
||
// 屏幕高度
|
||
windowHeight: 0,
|
||
// 服务列表
|
||
serviceList: [],
|
||
// 服务id
|
||
serviceId: '',
|
||
// 当前服务
|
||
serviceItem: {},
|
||
// 全加载
|
||
loading: false,
|
||
// 明细显示
|
||
detailShow: false,
|
||
// 图片处理加载动画
|
||
dotLoading: false,
|
||
// 过渡动画
|
||
transition: false,
|
||
// 按钮禁用
|
||
functionDisable: false,
|
||
// 上传禁用
|
||
uploadDisabled: false,
|
||
// 加载中随机图片
|
||
rangeImageList: [],
|
||
// 图片上传表单存储
|
||
formData: {
|
||
fileList: [],
|
||
uploadFile: '',// 上传图片
|
||
resultFile: '',// 结果图
|
||
},
|
||
// 元素选择下标
|
||
selectElementIndex: '',
|
||
// 弹窗显示更多选项
|
||
showMoreOptions: false,
|
||
// 进度条
|
||
dealPercent: 0,
|
||
// 进度条计时器
|
||
dealPercentTimer: 1,
|
||
// 轮询次数——不轮询-1
|
||
asyncPollTime: -1,
|
||
// 异步结果——成功true,失败false
|
||
asyncResult: false,
|
||
// 生成失败提示词
|
||
errorTips: '',
|
||
// 尺寸选择下标
|
||
selectSizeIndex: '',
|
||
// 火山尺寸列表——文生图
|
||
volcengineDimensions: [
|
||
{ name: "512*512", value: "1/1" },
|
||
{ name: "512*384", value: "4/3" },
|
||
{ name: "384*512", value: "3/4" },
|
||
{ name: "512*341", value: "3/2" },
|
||
{ name: "341*512", value: "2/3" },
|
||
{ name: "512*288", value: "16/9" },
|
||
{ name: "288*512", value: "9/16" },
|
||
],
|
||
// 阿里尺寸列表——文生图
|
||
aliDimensions: [
|
||
{ name: "1024*1024", value: "1/1" },
|
||
{ name: "720*1280", value: "9/16" },
|
||
{ name: "768*1152", value: "2/3" },
|
||
{ name: "1280*720", value: "16/9" },
|
||
]
|
||
}
|
||
},
|
||
beforeMount() {
|
||
// 计算当前窗口高度
|
||
this.windowHeight = window.screen.height;
|
||
if(this.sid){
|
||
this.serviceId = Number(this.sid);
|
||
this.singleService();
|
||
}
|
||
this.getRangeImages();
|
||
this.getServices();
|
||
},
|
||
computed: {
|
||
// 获取一般展示页选项——8个最多
|
||
getOptions(){
|
||
let options = this.serviceItem.options;
|
||
const length = this.serviceItem.options.length;
|
||
return length > 8 ? options.slice(0,8) : options;
|
||
},
|
||
},
|
||
methods: {
|
||
// 获取服务筛选列表
|
||
async getServices(){
|
||
try{
|
||
this.loading = true;
|
||
let res = await this.$api.allServices();
|
||
if(res.success){
|
||
this.serviceList = res.data;
|
||
if(!this.serviceId){
|
||
this.serviceId = this.serviceList[0]?.id;
|
||
this.serviceItem = this.serviceList[0];
|
||
this.serviceItem.type = Number(this.serviceItem.type);
|
||
}
|
||
}else{
|
||
this.$emit('toast',{type:'error',title: "服务列表获取失败!"});
|
||
}
|
||
}catch(e){
|
||
this.$emit('toast',{type:'error',title: "服务列表获取失败!"});
|
||
}finally{
|
||
this.loading = false;
|
||
}
|
||
},
|
||
// 获取加载中图片
|
||
async getRangeImages(){
|
||
let res = await this.$api.getCpPhotoById({labelId: 6});
|
||
if(res?.success){
|
||
this.rangeImageList = res.data;
|
||
}else{
|
||
this.$emit('toast',{type:'error',title: "随机加载图片获取失败!"});
|
||
}
|
||
},
|
||
// 获取单个服务内容
|
||
async singleService(){
|
||
let res = await this.$api.singleServices(this.serviceId);
|
||
if(res.success){
|
||
this.serviceItem = res.data;
|
||
this.serviceItem.type = Number(this.serviceItem.type);
|
||
}else{
|
||
this.$emit('toast',{type:'error',title: "ai功能暂未开放!"});
|
||
}
|
||
},
|
||
// 更换服务
|
||
changeWork(item,index){
|
||
let that = this;
|
||
// 判断是否正在生成图片
|
||
if(this.asyncPollTime !== -1){
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: `图片生成中,是否确认进行其他服务?`,
|
||
confirmColor: '#94d500',
|
||
success: (res) => {
|
||
if (res.confirm){
|
||
that.realRedraw();
|
||
that.realChangeWork(item, index);
|
||
}
|
||
}
|
||
});
|
||
// 这里如果存在结果图才执行重绘清除
|
||
} else if(this.formData.resultFile || Number(item.type) === this.serviceItem.type){
|
||
this.realRedraw();
|
||
this.realChangeWork(item, index);
|
||
} else {
|
||
this.realRedraw();
|
||
this.realChangeWork(item, index);
|
||
}
|
||
},
|
||
// 真正执行更换服务操作
|
||
realChangeWork(item,index){
|
||
if(this.serviceId === item.id) return;
|
||
this.serviceId = item.id;
|
||
this.$emit('changeService',item.id);
|
||
this.serviceItem = this.serviceList[index];
|
||
this.serviceItem.type = Number(this.serviceItem.type);
|
||
if(this.serviceItem.type===3||this.serviceItem.type===1) this.handleDelete();
|
||
},
|
||
// 宝典
|
||
showTutorial(){
|
||
if(this.serviceItem.exampleUrl){
|
||
window.open(encodeURI(this.serviceItem.exampleUrl));
|
||
}else{
|
||
this.$emit('toast',{type:'warning',title: "暂无使用教程,请自求多福!"});
|
||
}
|
||
},
|
||
// 增强提示词
|
||
async strengthenTip({input, deal}){
|
||
if(input === ''){
|
||
this.$emit('toast',{type:'warning',title: "请提供部分词句!"});
|
||
deal();
|
||
return;
|
||
}else{
|
||
let res = await this.$api.createTip(input);
|
||
if(res.success){
|
||
deal(res.data);
|
||
}else{
|
||
this.$emit('toast',{type:'error',title: "提示词强化失败!"});
|
||
deal();
|
||
return;
|
||
}
|
||
}
|
||
},
|
||
// 图片格式化
|
||
getTypeImage(path){
|
||
if(path === null || path === ''){
|
||
return '/static/default-select.png';
|
||
}else if(path.startsWith("http")){
|
||
return path;
|
||
}else if(path.startsWith("/")){
|
||
return encodeURI(path);
|
||
}else{
|
||
return encodeURI(this.ip+path);
|
||
}
|
||
},
|
||
// 上传图片
|
||
selectImage(file,uploadFiles){
|
||
let that = this;
|
||
if (file.raw.type.indexOf('image/') === -1) {
|
||
that.$refs.uploadCover.clearFiles();
|
||
that.$emit('toast',{type: 'warning',title: "图片上传格式错误!"});
|
||
return;
|
||
}
|
||
|
||
const size = file.raw.size / 1024; // 计算文件大小
|
||
if(size<5 || (size/1024)>5){
|
||
that.$refs.uploadCover.clearFiles();
|
||
that.$emit('toast',{type: 'warning',title: "图片大小不符合规范!"});
|
||
return;
|
||
}
|
||
that.uploadDisabled = true;
|
||
that.formData.fileList = uploadFiles;
|
||
that.formData.uploadFile = uploadFiles[0]?.url;
|
||
},
|
||
// 表单合法判断
|
||
legalJudge(){
|
||
const currentType = this.serviceItem.type;
|
||
if(currentType !== 3 && currentType !== 1 && this.formData.uploadFile === ''){
|
||
this.$emit('toast',{type:'error',title: currentType === 4 ? "请选择模特!" : "请上传图片!"});
|
||
return false;
|
||
}
|
||
if(currentType === 1){
|
||
if(this.selectElementIndex === '' || !this.serviceItem.text){
|
||
this.$emit('toast',{type:'error',title: "请完善信息!"});
|
||
return false;
|
||
}
|
||
}
|
||
if(currentType === 2 && this.selectElementIndex === ''){
|
||
this.$emit('toast',{type:'error',title: "请选择图片元素!"});
|
||
return false;
|
||
}
|
||
if(currentType === 3){
|
||
if(this.selectElementIndex === '' || !this.serviceItem.text || !this.serviceItem.promt){
|
||
this.$emit('toast',{type:'error',title: "请完善信息!"});
|
||
return false;
|
||
}
|
||
}
|
||
if(currentType === 4){
|
||
const { bottomsUrl, coatUrl } = this.$refs.dressRef.form;
|
||
if(coatUrl===''){
|
||
this.$emit('toast',{type:'error',title: "请选择更换上衣!"});
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
},
|
||
// 开始处理图片
|
||
async startDeal(){
|
||
try{
|
||
let that = this;
|
||
// 判断图片是否符合规范
|
||
if(!this.legalJudge()) return;
|
||
that.dotLoading = true;
|
||
let mannequinIndex = that.serviceItem.type === 4 ? that.$refs.dressRef.form.mannequinIndex : '';
|
||
if(mannequinIndex === '' && that.formData.fileList.length > 0){
|
||
// 上传图片
|
||
ossUpload(that,that.formData.uploadFile,(path)=>{
|
||
if(!path) return;
|
||
that.formData.uploadFile = path;
|
||
that.formData.fileList[0].url = path;
|
||
// 再实际处理
|
||
that.realUpload();
|
||
});
|
||
}else{
|
||
// 再实际处理
|
||
that.realUpload();
|
||
}
|
||
}catch(e){
|
||
this.dotLoading = false;
|
||
}finally{
|
||
}
|
||
},
|
||
// 真正处理方法
|
||
async realUpload(){
|
||
let that = this;
|
||
// 钻石余额-1
|
||
uni.$emit('deleteDiamond');
|
||
let resp = await that.$api.generateImages(that.getParams(that.serviceItem));
|
||
if(resp?.success){
|
||
that.setResultFile(resp.data.path);
|
||
that.$emit('toast',{type:'success',title:
|
||
'等待ai生成中......点击先看临时工表演',duration: 3000});
|
||
that.dotLoading = false;
|
||
// 开启轮询
|
||
that.delayLoadImage(resp.data.id);
|
||
}else{
|
||
that.$emit('toast',{type:'error',title: `${that.serviceItem.name}失败!`});
|
||
that.dotLoading = false;
|
||
}
|
||
},
|
||
// 开启轮询查询结果图片
|
||
delayLoadImage(id){
|
||
if(id){
|
||
this.dealPercent = 0;
|
||
this.asyncPollTime = 0;
|
||
this.startDealPercent();
|
||
this.asyncPoll(id);
|
||
}
|
||
},
|
||
// 设置结果图
|
||
setResultFile(path = ''){
|
||
const length = this.rangeImageList.length;
|
||
// 获取随机下标
|
||
let num = Math.floor(Math.random() * length);
|
||
let image = this.rangeImageList[num]?.path;
|
||
this.formData.resultFile = length>0 ?
|
||
(image.startsWith("http") ? image : encodeURI(this.ip+image)) : path;
|
||
if(this.formData.fileList[0])
|
||
this.formData.fileList[0].url = this.formData.resultFile;
|
||
else this.formData.fileList = [{url: this.formData.resultFile}];
|
||
this.uploadDisabled = true;
|
||
},
|
||
// 获取参数值
|
||
getParams({id, type, options, text, promt}){
|
||
let result,that = this;
|
||
switch(Number(type)){
|
||
case 0 :
|
||
result = {
|
||
serviceId: id,
|
||
imageUrl: that.formData.uploadFile,
|
||
}
|
||
break;
|
||
case 1 :
|
||
result = {
|
||
serviceId: id,
|
||
option: options[that.selectElementIndex].optionKey,
|
||
text: text,
|
||
}
|
||
if(this.selectSizeIndex !== '') result.size = that.serviceId === 4 ? that.aliDimensions[that.selectSizeIndex].name : that.volcengineDimensions[that.selectSizeIndex].name;
|
||
break;
|
||
case 2 :
|
||
result = {
|
||
serviceId: id,
|
||
imageUrl: that.formData.uploadFile,
|
||
option: options[that.selectElementIndex].optionKey
|
||
}
|
||
break;
|
||
case 3 :
|
||
result = {
|
||
serviceId: id,
|
||
option: options[that.selectElementIndex].optionKey,
|
||
text: text,
|
||
promt: promt
|
||
}
|
||
break;
|
||
case 4 :
|
||
const { bottomsUrl, coatUrl } = this.$refs.dressRef.form;
|
||
result = {
|
||
serviceId: id,
|
||
bottomImageUrl: bottomsUrl,
|
||
topImageUrl: coatUrl,
|
||
imageUrl: that.formData.uploadFile,
|
||
};
|
||
if(bottomsUrl === '') delete result.bottomImageUrl;
|
||
else result.bottomImageUrl = that.getImagePath(bottomsUrl);
|
||
if(coatUrl === '') delete result.topImageUrl;
|
||
else result.topImageUrl = that.getImagePath(coatUrl);
|
||
break;
|
||
}
|
||
return result;
|
||
},
|
||
// 获取图片格式化路径
|
||
getImagePath(path){
|
||
return path?.includes('://') ? path : encodeURI(this.ip+path);
|
||
},
|
||
// 设置进度条——最多15秒
|
||
startDealPercent(){
|
||
let that = this;
|
||
let timerx = 1;
|
||
let timer = function(){
|
||
let random = Math.floor(Math.random()*3.5);
|
||
let num = timerx === 75 ? 99 : that.dealPercent + random;
|
||
if(num<99){
|
||
that.dealPercent = num;
|
||
timerx++;
|
||
}else{
|
||
that.dealPercent = 99;
|
||
clearInterval(that.dealPercentTimer);
|
||
}
|
||
}
|
||
this.dealPercentTimer = setInterval(timer,200);
|
||
},
|
||
// 轮询
|
||
async asyncPoll(id) {
|
||
if(this.asyncPollTime === -1) return;
|
||
// 超13次轮询结束
|
||
if(this.asyncPollTime > 13) {
|
||
this.asyncPollTime = -1;
|
||
this.$emit('toast',{type:'warning',title:'生成时间过长,请移步作品栏目查看图片'});
|
||
return;
|
||
}
|
||
if(this.asyncPollTime === 3){
|
||
this.$emit('toast',{type:'warning',title:'火速插队中......客官可稍后移步作品栏目查看图片',
|
||
duration: 3000});
|
||
}
|
||
try {
|
||
let res = await this.$api.singlePhotoById(id);
|
||
if(res?.success && res.data !== null && res.data?.creationState !== "create"){
|
||
this.dealPercent = 100;
|
||
this.formData.resultFile = res.data?.path;
|
||
this.formData.fileList[0].url = res.data?.path;
|
||
setTimeout(()=>{this.asyncPollTime = -1;},100);
|
||
// 结果判断
|
||
this.asyncResult = res.data?.creationState === 't';
|
||
this.errorTips = this.asyncResult ? '' : res.data?.reason;
|
||
this.$emit('toast',{type:this.asyncResult?'success':'error',title: `${this.serviceItem.name}${this.asyncResult?'成功':'失败'}`});
|
||
return;
|
||
}
|
||
this.asyncPollTime++;
|
||
console.log('轮询次数:',this.asyncPollTime);
|
||
} catch (error) {
|
||
return;
|
||
}
|
||
setTimeout(() => this.asyncPoll(id), 5000);
|
||
},
|
||
// 图片预览
|
||
handlePreview(){
|
||
let files = [this.formData.uploadFile];
|
||
if(this.formData.resultFile !== '') files.push(this.formData.resultFile);
|
||
if(!files || files?.length === 0) return;
|
||
tools.methods.lookImage(files.length-1,files);
|
||
},
|
||
// 图片删除
|
||
handleDelete(){
|
||
this.$refs.uploadCover.clearFiles();
|
||
this.formData.fileList = [];
|
||
this.formData.uploadFile = '';
|
||
// 试衣换衣服务删除图片,需要取消模特选择,进行联调
|
||
if(this.serviceItem.type === 4)
|
||
this.$refs.dressRef.form.mannequinIndex = '';
|
||
setTimeout(()=>{
|
||
this.uploadDisabled = false;
|
||
},400);
|
||
},
|
||
// 下载图片
|
||
download(){
|
||
if(!this.asyncResult){
|
||
this.$emit('toast',{type:'error',title: "图片生成失败,请重试!"});
|
||
return;
|
||
}
|
||
window.open(this.formData.resultFile);
|
||
},
|
||
// 重新绘制
|
||
redraw(){
|
||
let that = this;
|
||
// 判断是否为异步生图
|
||
if(this.asyncPollTime !== -1){
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: `图片生成中,是否确认重新绘制?`,
|
||
confirmColor: '#94d500',
|
||
success: (res) => {if (res.confirm) that.realRedraw();}
|
||
});
|
||
} else this.realRedraw();
|
||
},
|
||
// 真正重绘方法
|
||
realRedraw(){
|
||
this.handleDelete();
|
||
this.formData.resultFile = '';
|
||
this.formData.uploadFile = '';
|
||
delete this.serviceItem.text;
|
||
delete this.serviceItem.promt;
|
||
this.showMoreOptions = false;
|
||
this.selectElementIndex = '';
|
||
this.selectSizeIndex = '';
|
||
if(this.serviceItem.type === 4) this.$refs.dressRef.resetForm();
|
||
this.errorTips = '';
|
||
this.asyncPollTime = -1;
|
||
setTimeout(()=>{this.dealPercent = 100;});
|
||
},
|
||
// 切换加载图片
|
||
changeLoadingImage(){
|
||
if(this.asyncPollTime !== -1){
|
||
this.setResultFile();
|
||
}
|
||
},
|
||
// ai试衣模特预选
|
||
previewMannequin(model){
|
||
this.formData.uploadFile = model;
|
||
if(model === ''){
|
||
this.formData.fileList = [];
|
||
this.uploadDisabled = false;
|
||
}else{
|
||
if(this.formData.fileList[0]) this.formData.fileList[0].url = model;
|
||
else this.formData.fileList = [{url: model}];
|
||
this.uploadDisabled = true;
|
||
}
|
||
},
|
||
// 元素选择
|
||
selectElement(index){
|
||
this.selectElementIndex = this.selectElementIndex === index ? '' : index;
|
||
},
|
||
// 尺寸选择
|
||
selectSize(index){
|
||
this.selectSizeIndex = this.selectSizeIndex === index ? '' : index;
|
||
},
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.pc-workshops{
|
||
background-image: linear-gradient(to left top, #ffffff, #fcfbfc, #f8f8f9, #f5f4f7, #f1f1f4, #eef0f6, #eaeff7, #e5eff8, #ddf3f9, #d9f6f2, #def7e6, #eef6d9);
|
||
margin-top: 20rpx;
|
||
min-height: 2050rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 40rpx 50rpx;
|
||
.workshops-controls{
|
||
width: 1070rpx;
|
||
height: 1620rpx;
|
||
background-color: #fff;
|
||
border-radius: 40rpx;
|
||
transition: 0.3s;
|
||
display: flex;
|
||
overflow: hidden;
|
||
border: 2rpx solid #d5d5d5;
|
||
.controls-left{
|
||
width: 276rpx;
|
||
height: 100%;
|
||
background-color: #fefefe;
|
||
border-right: 2rpx solid #d5d5d5;
|
||
overflow-y: scroll;
|
||
color: #c0c0c0;
|
||
font-size: 30rpx;
|
||
.cl-title{
|
||
padding: 24rpx 40rpx;
|
||
color: #6b6b6b;
|
||
}
|
||
.cl-item{
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
padding: 14rpx 50rpx;
|
||
cursor: pointer;
|
||
margin-left: 10rpx;
|
||
margin-bottom: 28rpx;
|
||
&:nth-last-child(1){
|
||
margin-bottom: 0;
|
||
}
|
||
&:hover{
|
||
color: #a3d4fe;
|
||
margin-left: 0;
|
||
border-left: 8rpx solid #a3d4fe;
|
||
}
|
||
}
|
||
.cl-item-selected{
|
||
color: #99d7ff;
|
||
margin-left: 0;
|
||
border-left: 8rpx solid #99d7ff;
|
||
background-image: linear-gradient(to right, rgba(139, 243, 254, 0.3) 0%, rgba(248,248,248,0.7) 100%);
|
||
}
|
||
}
|
||
.controls-right{
|
||
flex: 1;
|
||
height: 100%;
|
||
// background-color: rgba(248,248,248,0.7);
|
||
display: flex;
|
||
flex-direction: column;
|
||
.control-top{
|
||
padding: 20rpx 40rpx;
|
||
display: flex;
|
||
align-items: flex-end;
|
||
justify-content: space-between;
|
||
border-bottom: 2rpx solid rgba(224, 224, 224, 0.5);
|
||
.ct-title{
|
||
font-weight: bold;
|
||
color: #6b6b6b;
|
||
font-size: 38rpx;
|
||
}
|
||
.u-icon{
|
||
cursor: pointer;
|
||
&:hover{
|
||
opacity: 0.8;
|
||
}
|
||
&:active{
|
||
opacity: 0.6;
|
||
}
|
||
}
|
||
}
|
||
.control-center{
|
||
flex: 1;
|
||
overflow-y: hidden;
|
||
background-color: rgba(248,248,248,0.7);
|
||
display: flex;
|
||
flex-direction: column;
|
||
position: relative;
|
||
.control-center-scroll{
|
||
overflow-y: scroll;
|
||
padding: 40rpx;
|
||
.cc-edit{
|
||
margin-bottom: 40rpx;
|
||
.art-input{
|
||
margin: 20rpx 0 10rpx;
|
||
border-radius: 20rpx;
|
||
box-shadow: 0 0 10rpx #d0d6dd;
|
||
border: 2rpx solid #bcc1c8;
|
||
&:hover{
|
||
box-shadow: 0 0 10rpx #b4b9bf;
|
||
}
|
||
}
|
||
.dimensional-drawing{
|
||
width: 710rpx;
|
||
height: 180rpx;
|
||
margin-top: 20rpx;
|
||
margin-bottom: 30rpx;
|
||
display: flex;
|
||
padding: 0 10rpx 0 0;
|
||
overflow-x: scroll;
|
||
.dimensional-item{
|
||
min-width: 160rpx;
|
||
height: 100%;
|
||
padding: 0 0 18rpx;
|
||
background-color: #eff0f4;
|
||
border-radius: 20rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
color: #b3a0da;
|
||
margin-right: 30rpx;
|
||
cursor: pointer;
|
||
|
||
&:nth-last-child(1){
|
||
margin-right: 0;
|
||
}
|
||
|
||
text{
|
||
width: 100%;
|
||
text-align: center;
|
||
margin-top: 20rpx;
|
||
}
|
||
|
||
view{
|
||
opacity: 0.7;
|
||
border-radius: 10rpx;
|
||
width: 54rpx;
|
||
border: 6rpx solid #aea4ee;
|
||
aspect-ratio: 1/1;
|
||
}
|
||
|
||
&:hover{
|
||
border: 2rpx solid #b3a0da;
|
||
view{
|
||
opacity: 1;
|
||
box-shadow: 0 0 8rpx #aea4ee;
|
||
}
|
||
text{
|
||
text-shadow: 0 0 2rpx #aea4ee;
|
||
}
|
||
}
|
||
}
|
||
.dimensional-item-select{
|
||
border: 2rpx solid #b3a0da;
|
||
view{
|
||
opacity: 1;
|
||
box-shadow: 0 0 8rpx #aea4ee;
|
||
}
|
||
text{
|
||
text-shadow: 0 0 2rpx #aea4ee;
|
||
}
|
||
}
|
||
}
|
||
.section-options{
|
||
// margin-top: 40rpx;
|
||
display: grid;
|
||
grid-gap: 26rpx;
|
||
grid-template-columns: repeat(4,1fr);
|
||
margin-top: 20rpx;
|
||
margin-bottom: 30rpx;
|
||
|
||
.section-tags{
|
||
height: 200rpx;
|
||
width: 150rpx;
|
||
background-color: #ebecef;
|
||
border-radius: 20rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: space-evenly;
|
||
color: #b3a0da;
|
||
cursor: pointer;
|
||
|
||
text{
|
||
width: 90%;
|
||
text-align: center;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
}
|
||
|
||
image{
|
||
opacity: 0.7;
|
||
border-radius: 20rpx;
|
||
width: 130rpx;
|
||
height: 130rpx;
|
||
}
|
||
|
||
&:hover{
|
||
border: 2rpx solid #b3a0da;
|
||
image{
|
||
opacity: 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
.section-tags-select{
|
||
border: 2rpx solid #b3a0da;
|
||
image{
|
||
opacity: 1;
|
||
}
|
||
}
|
||
}
|
||
::v-deep .u-section__right-info{
|
||
cursor: pointer;
|
||
&:hover{
|
||
opacity: 0.8;
|
||
}
|
||
&:active{
|
||
opacity: 0.6;
|
||
}
|
||
}
|
||
}
|
||
.use-tips{
|
||
width: 100%;
|
||
border-radius: 20rpx;
|
||
font-size: 30rpx;
|
||
color: #101010;
|
||
background-color: #eff0f4;
|
||
padding: 30rpx;
|
||
font-weight: bold;
|
||
transition: 0.3s;
|
||
.uset-content{
|
||
color: #6b6b6b;
|
||
font-weight: normal;
|
||
margin-top: 20rpx;
|
||
padding-left: 20rpx;
|
||
}
|
||
&:hover{
|
||
box-shadow: 0 0 10rpx #b3b4b6;
|
||
}
|
||
}
|
||
}
|
||
.options-popup{
|
||
position: absolute;
|
||
.op-content{
|
||
background-color: #ffffff;
|
||
padding: 10rpx 25rpx 20rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
.op-top{
|
||
height: 80rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.options-list{
|
||
height: 800rpx;
|
||
color: #a7b6b8;
|
||
width: 100%;
|
||
margin-top: 10rpx;
|
||
.section-options{
|
||
display: grid;
|
||
grid-gap: 26rpx;
|
||
grid-template-columns: repeat(4,1fr);
|
||
|
||
.section-tags{
|
||
height: 200rpx;
|
||
width: 150rpx;
|
||
background-color: #ebecef;
|
||
border-radius: 20rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: space-evenly;
|
||
color: #b3a0da;
|
||
cursor: pointer;
|
||
|
||
text{
|
||
width: 90%;
|
||
text-align: center;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
}
|
||
|
||
image{
|
||
opacity: 0.7;
|
||
border-radius: 20rpx;
|
||
width: 130rpx;
|
||
height: 130rpx;
|
||
}
|
||
|
||
&:hover{
|
||
border: 2rpx solid #b3a0da;
|
||
image{
|
||
opacity: 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
.section-tags-select{
|
||
border: 2rpx solid #b3a0da;
|
||
image{
|
||
opacity: 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
::v-deep .u-close{
|
||
cursor: pointer;
|
||
&:hover{
|
||
opacity: 0.8;
|
||
}
|
||
&:active{
|
||
opacity: 0.6;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.control-bottom{
|
||
min-height: 140rpx;
|
||
height: 140rpx;
|
||
border-top: 2rpx solid #d5d5d5;
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 0 34rpx;
|
||
color: #6b6b6b;
|
||
.cb-left{
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 32rpx;
|
||
height: 100%;
|
||
view{
|
||
height: 33%;
|
||
color: #b2d210;
|
||
display: flex;
|
||
align-items: flex-end;
|
||
.u-icon{
|
||
margin-left: 10rpx;
|
||
}
|
||
}
|
||
}
|
||
.cb-right{
|
||
display: flex;
|
||
align-items: center;
|
||
height: 100%;
|
||
position: relative;
|
||
.popover-detail{
|
||
cursor: pointer;
|
||
.u-icon{
|
||
margin-left: 10rpx;
|
||
}
|
||
&:hover{
|
||
opacity: 0.8;
|
||
}
|
||
&:active{
|
||
opacity: 0.6;
|
||
}
|
||
}
|
||
.cb-btn{
|
||
// color: rgba(42, 35, 61, 0.9);
|
||
margin-left: 30rpx;
|
||
height: 60%;
|
||
min-width: 240rpx;
|
||
border: none;
|
||
font-size: 30rpx;
|
||
font-weight: bold;
|
||
background-size: 200% auto;
|
||
transition: 0.5s;
|
||
animation-duration: 1s;
|
||
animation-fill-mode: both;
|
||
box-shadow: 0 0 10rpx #99d7ff;
|
||
background-image: linear-gradient(to right, #c2fc3b 0%, #c2ffd8 51%, #c2fc3b 100%);
|
||
&:hover {
|
||
background-position: right center;
|
||
color: #fff;
|
||
text-decoration: none;
|
||
}
|
||
&:active{
|
||
filter: opacity(0.6);
|
||
}
|
||
.u-icon{
|
||
margin-right: 10rpx;
|
||
}
|
||
.transition{
|
||
animation-name: fadeIn;
|
||
}
|
||
}
|
||
.cbu-btn{
|
||
background-image: linear-gradient(to right, #4AC29A 0%, #BDFFF3 51%, #4AC29A 100%);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
&:hover{
|
||
box-shadow: 0 0 14rpx #c6c6c6;
|
||
}
|
||
}
|
||
.workshops-upload{
|
||
flex: 1;
|
||
height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-direction: column;
|
||
.upload-view{
|
||
border: 4rpx dashed #99d7ff;
|
||
border-radius: 40rpx;
|
||
width: 1350rpx;
|
||
height: 1350rpx;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
overflow: hidden;
|
||
&:hover{
|
||
border: 4rpx dashed #6ec0ff;
|
||
}
|
||
&::v-deep .el-upload,&::v-deep .el-upload-dragger{
|
||
width: 100%;
|
||
border: none;
|
||
min-height: 1350rpx;
|
||
border-radius: 40rpx;
|
||
}
|
||
&::v-deep .el-upload--picture-card{
|
||
line-height: 46rpx;
|
||
}
|
||
&::v-deep .el-upload-list--picture-card{
|
||
display: none;
|
||
}
|
||
.ulview-block{
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-direction: column;
|
||
.upload-gif{
|
||
margin-top: -100rpx;
|
||
}
|
||
.upload-title{
|
||
background-image: linear-gradient(to right, #a3d4ff 0%, #bee7df 100%);
|
||
background-clip: text;
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
font-size: 40rpx;
|
||
font-weight: bold;
|
||
}
|
||
.upload-tips{
|
||
margin-top: 34rpx;
|
||
font-size: 30rpx;
|
||
color: #aaafb8;
|
||
text{
|
||
margin: 0 10rpx;
|
||
color: rgba(229, 64, 70, 1);
|
||
}
|
||
}
|
||
}
|
||
.upload-preview{
|
||
width: 100%;
|
||
height: 100%;
|
||
.up-image{
|
||
width: 100%;
|
||
height: 100%;
|
||
border-radius: 40rpx;
|
||
cursor: pointer;
|
||
img{
|
||
border-radius: 40rpx !important;
|
||
}
|
||
}
|
||
.upload-icon{
|
||
margin: 0 50rpx;
|
||
&:hover{
|
||
opacity: 0.8;
|
||
}
|
||
&:active{
|
||
opacity: 0.6;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.tip-progress{
|
||
margin: 20rpx 0 -50rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
width: 50%;
|
||
.progress-title{
|
||
margin-right: 20rpx;
|
||
white-space: nowrap;
|
||
}
|
||
.progress-deal{
|
||
margin-left: 20rpx;
|
||
}
|
||
text{
|
||
background-image: linear-gradient(to right, #d3e7e7 0%, #a7b6b8 100%);
|
||
background-clip: text;
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
}
|
||
::v-deep .u-active{
|
||
border-top-right-radius: 100rpx;
|
||
border-bottom-right-radius: 100rpx;
|
||
box-shadow: 0 0 20rpx #d3e7e7;
|
||
background: linear-gradient(to right, #96a3a5 0%, #d3e7e7 100%);
|
||
}
|
||
}
|
||
.error-tips{
|
||
font-size: 30rpx;
|
||
color: rgba(229, 64, 70, 1);
|
||
margin: 20rpx 0 -50rpx;
|
||
}
|
||
}
|
||
}
|
||
::v-deep .el-popper[x-placement^=top]{
|
||
top: 0;
|
||
}
|
||
@keyframes fadeIn {
|
||
from {
|
||
opacity: 0;
|
||
}
|
||
|
||
to {
|
||
opacity: 1;
|
||
}
|
||
}
|
||
::v-deep .disabled{
|
||
border: none !important;
|
||
.el-upload-list--picture-card{
|
||
display: block !important;
|
||
width: 100% !important;
|
||
height: 100% !important;
|
||
.el-upload-list__item{
|
||
border-radius: 40rpx;
|
||
width: 100% !important;
|
||
height: 100% !important;
|
||
background-color: #ffffff00 !important;
|
||
border: none;
|
||
}
|
||
}
|
||
.el-upload,.el-upload-dragger{
|
||
display: none;
|
||
}
|
||
}
|
||
</style> |