PixelAI-mobile/pages/mobile_web/workshops/index.vue
2025-02-18 11:53:32 +08:00

1400 lines
39 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>
<!-- #ifdef APP -->
<view class="mobile-workshops" :style="{ backgroundImage: `url(${myFileUrl+background})`,paddingTop: CustomBar+'rpx' }">
<view class="app-top" :style="{ height: CustomBar+'rpx',
background: topLevel===0? '#ffffff00' : `rgba(255, 255, 255,${topLevel})` }"></view>
<!-- #endif -->
<!-- #ifndef APP -->
<view class="mobile-workshops" :style="{ backgroundImage: `url(${myFileUrl+background})` }">
<!-- #endif -->
<view class="mwt-top">
<!-- #ifdef MP -->
<view class="app-top" :style="{height: `${StatusBar}px`,background: topLevel===0? '#ffffff00' : `rgba(255, 255, 255,${topLevel})`}"></view>
<view :style="{height: `${StatusBar}px`}"></view>
<view class="mobile-logo" :style="{height: `${CustomBarHeight}px`,backgroundColor: `rgba(255, 255, 255,${topLevel})`}">
<!-- #endif -->
<!-- #ifndef MP -->
<view class="mobile-logo" :style="{backgroundColor: `rgba(255, 255, 255,${topLevel})`}">
<!-- #endif -->
<image :src="myFileUrl+logo"></image>
</view>
<view class="mw-title">
<u-icon name="arrow-left" size="40" color="#fff" class="back" @click="back"></u-icon>
{{ form.name }}
</view>
<view class="mw-upload" v-if="form.type!==4 || (form.type === 4 && resultFile)">
<!-- 文生图-空格位 -->
<view v-if="form.type === 1 && !resultFile"></view>
<!-- 未有结果+类型为文生图可选options -->
<view class="mwu-promt" v-else-if="form.type===3 && !resultFile">
<u-input :customStyle="{color:'#dcf1fc',fontSize:'50rpx'}" v-model="form.text"
placeholder="请输入需要生成的文字" trim inputAlign="center" :clearable="false" :maxlength="6"/>
</view>
<!-- 类型为图生图类 -->
<view class="mwu-cover" v-else-if="uploadFile==''&&form.type!==3&&form.type!==1" @click="selectImage">
<u-icon name="plus-circle" size="100" color="#fff" label="上传图片" labelSize="40"
labelColor="#fff" labelPos="bottom" marginTop="25"></u-icon>
<view class="mwuc-tips">
请上传大小为<text>5KB~5MB</text>的图片
</view>
</view>
<!-- 上传了需修改图 -->
<view class="center-image" v-else-if="resultFile===''">
<image mode="widthFix" :src="uploadFile" @click="selectImage"></image>
</view>
<!-- 结果图 -->
<view class="center-image" v-else>
<image mode="widthFix" :src="getResultImagePath(resultFile)" @click="previewImage"></image>
</view>
<!-- 其他-涂抹重绘 -->
<view class="selections" v-if="!resultFile && form.type===-1">
<view class="selections-item" :style="[getSelectionsStyle(index)]"
v-for="(item,index) in selections" :key="index" @click="currentSelect=index">
{{ item }}
</view>
</view>
</view>
<!-- -->
<view class="mw-editor" v-if="!resultFile && form.type===-1">
<EditorBox :icon="fileUrl+editorIcon" @strengthenTip="strengthenTip"
placeholder="如: 衣服/鞋子/头发或者英文:clothes and shose">
<template #title>
<text class="slot">需<text style="color: #d8fa35;">替换</text>的元素</text>
</template>
</EditorBox>
<EditorBox :icon="fileUrl+editorIcon" @strengthenTip="strengthenTip"
placeholder="如: 衣服/鞋子/头发或者英文:clothes and shose">
<template #title>
<text class="slot"><text style="color: #d8fa35;">替换后</text>的图像</text>
</template>
</EditorBox>
</view>
<view class="workshops-tip" v-if="(form.type !== 4 || (form.type === 4 && resultFile)) && (form.type !== 1 || (form.type === 1 && resultFile))">
<view @click="showTutorial" class="tip-content" v-if="asyncPollTime === -1" :style="{color: errorTips?'#e0584b' : '#d5ff00'}">
<u-icon name="question-circle" size="35" :color="errorTips?'#e0584b' : '#c2fc3b'" />
Tips{{resultFile ? errorTips || '点击预览图片效果~' : form.tips||'智能创作~'}}
</view>
<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="#2d3240" round/>
<text class="progress-deal">{{ dealPercent }}%</text>
</view>
</view>
<!-- 文生图 -->
<view class="mw-editor" v-if="!resultFile && form.type===1">
<EditorBox :height="200" :icon="fileUrl+editorIcon" title="提示词"
v-model="form.text" placeholder="请输入描述的提示词(限制300词)~~" rightIcon="question-circle"
rightTip="使用教程" @rightIconClick="showTutorial" @strengthenTip="strengthenTip"/>
</view>
<view class="mw-editor" v-if="!resultFile && form.type===1">
<u-section title="尺寸选择" color="#fff" :right="false" lineColor="#c2ea04" fontSize="34" />
<scroll-view scroll-x>
<view class="dimensional-drawing">
<view class="dimensional-item" v-for="(item,index) in (form.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>
</scroll-view>
</view>
<!-- 提示文字 -->
<view class="mw-editor" v-if="!resultFile && form.type===3">
<EditorBox :icon="fileUrl+editorIcon" title="提示词" v-model="form.promt"
placeholder="请输入描述的提示词(限制300词)~~" rightIcon="question-circle"
rightTip="使用教程" @rightIconClick="showTutorial" @strengthenTip="strengthenTip"/>
</view>
<!-- 选项生图 -->
<view class="mw-editor" v-if="!resultFile && (form.type===2||form.type===3 || form.type === 1)">
<u-section title="类型选择" color="#fff" :right="form.options.length>8" lineColor="#c2ea04" fontSize="34" @click="showMoreOptions = true"
subTitle="更多" :subColor="selectElementIndex>=getOptions.length ? '#b3a0da' : '#eee'"></u-section>
<view class="section-options">
<view class="section-tags" v-for="(item,index) in getOptions" :key="item.id"
:class="selectElementIndex===index?'section-tags-select':''" @click="selectElement(index)">
<image :src="getTypeImage(item.path)"></image>
<text>{{ item.optionName }}</text>
</view>
<!-- <u-tag v-for="(item,index) in getOptions" :key="item.id" :index="index"
:text="item.optionName" @click="selectElement" :class="selectElementIndex===index?'u-tag-select':''"></u-tag>
<u-tag v-if="form.options.length>9" :index="-1" :class="selectElementIndex>=getOptions.length?'u-tag-select':''"
text="更多" @click="showMoreOptions = true"></u-tag> -->
</view>
</view>
<!-- 换衣选择 -->
<view class="mw-editor" style="margin-left: 0;margin-right: 0;" v-if="!resultFile && form.type===4">
<DressSelect ref="dressRef" @previewMannequin="previewMannequin"/>
</view>
</view>
<view class="workshops-btn">
<view class="price-tips" v-if="resultFile===''">钻石 :<text>¥{{ form.price }}</text>颗 / 次</view>
<u-button class="wbu-btn" @click="startDeal" v-if="resultFile===''" :disabled="functionDisable"
:style="{opacity: functionDisable?'0.6':'1'}"
ripple :hairLine="false" shape="circle" rippleBgColor="#f0fdbf" :loading='dotLoading'>
<u-icon name="edit-pen" size="42"></u-icon>开启魔法
</u-button>
<view class="workshops-btn" :style="{flexDirection: 'row'}" v-else>
<u-button :loading="functionLoading" class="wbu-dbtn" ripple :hairLine="false"
shape="circle" rippleBgColor="#f0fdbf" @click="download" :class="transition?'transition':''">
<u-icon name="download" size="32"></u-icon>保存作品
</u-button>
<view class="wbu-dbtn wbu-odbtn">
<u-button class="wbud-btn" ripple :hairLine="false" shape="circle"
rippleBgColor="#f0fdbf" @click="resultFunction['reUpload'].fun" :class="transition?'transition':''">
<u-icon name="edit-pen" color="#8fb4e6" size="32"></u-icon>
<text>重新绘制</text>
</u-button>
</view>
</view>
<!-- <u-button :loading="functionLoading" class="wbu-btn" v-else ripple :hairLine="false"
shape="circle" rippleBgColor="#f0fdbf" @click="resultFunction[currentType].fun"
:style="{backgroundImage: resultFunction[currentType].background}" :class="transition?'transition':''">
<u-icon :name="resultFunction[currentType].icon" size="42"></u-icon>
{{ resultFunction[currentType].name }}
</u-button>
<view class="wb-change" v-if="resultFile!==''">
<u-icon :name="fileUrl+'change.png'" size="50" @click="changeFunction"></u-icon>
</view> -->
</view>
<!-- 更多类型 -->
<u-popup class="options-popup" v-model="showMoreOptions" mode="bottom" border-radius="30"
closeable close-icon="arrow-down" close-icon-color="#fff">
<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 form.options" :key="item.id"
:class="selectElementIndex===index?'section-tags-select':''" @click="selectElement(index)">
<image :src="getTypeImage(item.path)"></image>
<text>{{ item.optionName }}</text>
</view>
<!-- <u-tag v-for="(item,index) in form.options" :key="item.id" :index="index"
:text="item.optionName" @click="selectElement" :class="selectElementIndex===index?'u-tag-select':''"></u-tag> -->
</view>
</scroll-view>
</view>
</u-popup>
<u-toast ref="uToast"></u-toast>
<DotLoading :show="dotLoading" />
<Loading :show="loading"></Loading>
</view>
</template>
<script>
import configService from '@/common/config.service.js';
import { tools } from '@/utils/utils.js';
import EditorBox from './components/editor.vue';
import DressSelect from './components/dress_select.vue';
import { ossUpload } from '@/common/ossutil/ossWebUpload.js';
export default {
// #ifdef MP
options: {
styleIsolation: 'shared'
},
// #endif
components: {
EditorBox, DressSelect
},
data(){
return{
// #ifdef MP
// 微信小程序自定义导航栏参数
StatusBar: this.StatusBar || 0,
CustomBarHeight: this.Custom.height+(this.Custom.top-this.StatusBar)*2 || 0,
// #endif
// 全加载
loading: false,
// 顶部距离等级
topLevel: 0,
// 基础路径
ip: configService.ip,
aliIp: configService.aliUrl,
otherAliIp: configService.otherAliUrl,
anotherAliIp: configService.anotherAliUrl,
aliAsyncIp: configService.aliAsyncUrl,
myFileUrl: configService.fileUrl + 'pixel/my/',
fileUrl: configService.fileUrl + 'pixel/workshops/',
// 上传图片
// http://8.138.171.103/upload%5CAttachment%5C20241127%5Caa73abfb8b3a433292c94de57aef0a35.png
uploadFile: '',
// 结果图
// upload%5CAttachment%5C20241127%5Caa73abfb8b3a433292c94de57aef0a35.png
resultFile: '',
// logo图标
logo: 'logo-new.png',
// 我的页面背景
background: 'background.png',
// 数据
form: {
id: ''//id
},
// 模式选择
selections:["保留模式","替换模式"],
// 模式选择下标
currentSelect: 0,
// 模式选择背景
selectBackground: 'selectedBd.png',
// 未选择背景
noSelectBackground: 'noSelectedBd.png',
// 编辑图标
editorIcon: 'editor.png',
// 提示语列表
// placeholderList: {
// stylereplace: '上传图片后,选择更换不同风格~',
// animeization: '上传人像图快进入anime的世界吧~',
// oldrepair: '上传黑白旧照片,焕发色彩~'
// },
// 创作之后的操作按钮
resultFunction: {
download: {
name: '下载',
icon: 'download',
background: 'linear-gradient(to right, #56ab2f 0%, #96fe11 51%, #56ab2f 100%)',
fun: ()=>{this.download()}
},
reUpload: {
name: '重新制图',
icon: 'camera',
background: 'linear-gradient(to right, #c2fc3b 0%, #c2ffd8 51%, #c2fc3b 100%)',
fun: ()=>{this.redraw()}
},
// saveWork: {
// name: '保存作品',
// icon: 'bookmark',
// background: 'linear-gradient(to right, #4AC29A 0%, #BDFFF3 51%, #4AC29A 100%)',
// fun: ()=>{}
// }
},
// 当前功能按钮
currentType: 'download',
// 当前功能下标
index: 0,
// 下载加载
functionLoading: false,
// 过渡动画
transition: false,
// 图片处理加载动画
dotLoading: false,
// 元素选择下标
selectElementIndex: '',
// 尺寸选择下标
selectSizeIndex: '',
// 弹窗显示更多选项
showMoreOptions: false,
// 按钮禁用
functionDisable: false,
// 轮询次数——不轮询-1
asyncPollTime: -1,
// 异步结果——成功true失败false
asyncResult: false,
// 加载中随机图片
rangeImageList: [],
// 进度条
dealPercent: 20,
// 进度条计时器
dealPercentTimer: 1,
// 生成失败提示词
errorTips: '',
// 火山尺寸列表——文生图
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" },
]
}
},
// #ifndef H5
onPageScroll(e) {
const level = e.scrollTop/60;
if(level<=1) this.topLevel = level;
else this.topLevel = 1;
},
// #endif
// #ifdef H5
mounted(){
let that = this;
window.onscroll = function () {
//为了保证兼容性,这里取三个值,哪个有值取哪一个
//scrollTop就是触发滚轮事件时滚轮的高度
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
const level = scrollTop/60;
if(level<=1) that.topLevel = level;
else that.topLevel = 1;
}
},
onHide() {
window.onscroll = null;
},
// #endif
onLoad(options) {
this.form.id = options.id;
this.getForm();
this.getRangeImages();
},
computed: {
// 获取一般展示页选项——8个最多
getOptions(){
let options = this.form.options;
const length = this.form.options.length;
return length > 8 ? options.slice(0,8) : options;
},
// 获取涂抹重绘选中样式
getSelectionsStyle(index){
return (index) => {
return this.currentSelect===index?{ backgroundImage: `url(${this.fileUrl+this.selectBackground})` }:
{ color: '#000', backgroundImage: `url(${this.fileUrl+this.noSelectBackground})` }
}
},
},
methods: {
// 获取ai功能详情
async getForm(){
this.loading = true;
try{
let res = await this.$api.singleServices(this.form.id);
if(res.success){
res.data.type = Number(res.data.type);
this.form = res.data;
}else{
this.functionDisable = true;
this.$refs.uToast.show({type:'error',title: "ai功能暂未开放!"});
}
}catch(e){}
finally{
this.loading = false;
}
},
// 获取加载中图片
async getRangeImages(){
let res = await this.$api.getCpPhotoById({labelId: 6});
if(res?.success){
this.rangeImageList = res.data;
}else{
this.$refs.uToast.show({type:'error',title: "随机加载图片获取失败!"});
}
},
// 图片格式化
getTypeImage(path){
if(path === null || path === ''){
return '/static/default-select.png';
}else if(path.startsWith("http")){
return path;
}else if(path.startsWith("/")){
// #ifdef H5
return encodeURI(path);
// #endif
// #ifndef H5
return encodeURI(this.ip+path);
// #endif
}else{
return encodeURI(this.ip+path);
}
},
// 返回
back(){
// #ifdef MP || APP
uni.navigateBack();
// #endif
// #ifndef MP || APP
uni.redirectTo({
url: '/pages/mobile_web/index/index'
})
// #endif
},
// 上传图片
selectImage(){
let that = this;
uni.chooseImage({
count: 1, // 默认9
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: (res) => {
// #ifdef H5
if (res.tempFiles[0].type.indexOf('image') === -1) {
that.$refs.uToast.show({
type: 'warning',
title: "图片上传格式错误!"
});
return;
}
// #endif
const size = res.tempFiles[0].size / 1024; // 计算文件大小
if(size<5 || (size/1024)>5){
that.$refs.uToast.show({
type: 'warning',
title: "图片大小不符合规范!"
});
return;
}
if(that.resultFile!=='') that.resultFile = '';
that.uploadFile = res.tempFilePaths[0];
}
});
},
// ai试衣模特预选
previewMannequin(model){
this.uploadFile = model;
},
// 预览图片
previewImage(){
if(this.asyncPollTime !== -1){
this.setResultFile();
}else{
const previewImages = [this.getResultImagePath(this.resultFile)];
if(this.uploadFile) previewImages.push(this.uploadFile);
tools.methods.lookImage(0,previewImages);
}
},
// 开始处理图片
async startDeal(){
try{
let that = this;
// 判断图片是否符合规范
if(!this.legalJudge()) return;
that.dotLoading = true;
let mannequinIndex = that.form.type === 4 ? that.$refs.dressRef.form.mannequinIndex : '';
if(that.uploadFile && (mannequinIndex === '' || mannequinIndex === -1)){
// 上传图片
ossUpload(that,that.uploadFile,(path)=>{
if(!path) return;
that.uploadFile = path;
// 再实际处理
that.realUpload();
});
}else{
// 再实际处理
that.realUpload();
}
}catch(e){
this.dotLoading = false;
}finally{
}
},
// 真正处理方法
async realUpload(){
let that = this;
let resp = await that.$api.generateImages(that.getParams(that.form));
if(resp?.success){
that.setResultFile(resp.data.path);
console.log('that.resultFile',that.resultFile);
that.$refs.uToast.show({type:'success',title:
'等待ai生成中......点击先看临时工表演',duration: 3000});
that.dotLoading = false;
// 开启轮询
that.delayLoadImage(resp.data.id);
}else{
that.$refs.uToast.show({type:'error',title: `${that.form.name}失败!`});
that.dotLoading = false;
}
},
// 设置结果图
setResultFile(path = ''){
// if(this.form.id > 3){
const length = this.rangeImageList.length;
// 获取随机下标
let num = Math.floor(Math.random() * length);
let image = this.rangeImageList[num]?.path;
this.resultFile = length>0 ?
(image.startsWith("http") ? image : encodeURI(this.ip+image)) : path;
// } else {
// this.resultFile = path;
// }
},
// 开启轮询查询结果图片
delayLoadImage(id){
// if(this.form.id > 3&&id){
if(id){
this.dealPercent = 0;
this.asyncPollTime = 0;
this.startDealPercent();
this.asyncPoll(id);
}
},
// 结果图格式化
getResultImagePath(path){
if(!path) return;
let index = path?.indexOf('?');
let judge = path?.includes(configService.anotherAliUrl);
return path?.includes('://') ? path.substring(0,(judge||!index||index===-1) ? path.length : index) : encodeURI(this.ip+path);
},
// 轮询
async asyncPoll(id) {
if(this.asyncPollTime === -1) return;
// 超13次轮询结束
if(this.asyncPollTime > 13) {
this.asyncPollTime = -1;
this.$refs.uToast.show({type:'warning',title:'生成时间过长,请移步作品栏目查看图片'});
return;
}
if(this.asyncPollTime === 3){
this.$refs.uToast.show({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.resultFile = res.data?.path;
setTimeout(()=>{this.asyncPollTime = -1;},100);
// 结果判断
this.asyncResult = res.data?.creationState === 't';
this.errorTips = this.asyncResult ? '' : res.data?.reason;
this.$refs.uToast.show({type:this.asyncResult?'success':'error',title: `${this.form.name}${this.asyncResult?'成功':'失败'}`});
return;
}
this.asyncPollTime++;
console.log('轮询次数:',this.asyncPollTime);
} catch (error) {
return;
}
setTimeout(() => this.asyncPoll(id), 5000);
},
// 设置进度条——最多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);
},
// 表单合法判断
legalJudge(){
const currentType = this.form.type;
if(currentType !== 3 && currentType !== 1 && this.uploadFile===''){
this.$refs.uToast.show({type:'error',title: currentType === 4 ? "请选择模特" : "请上传图片!"});
// this.dotLoading = false;
return false;
}
if(currentType === 1){
if(this.selectElementIndex === '' || !this.form.text){
this.$refs.uToast.show({type:'error',title: "请完善信息!"});
// this.dotLoading = false;
return false;
}
}
if(currentType === 2 && this.selectElementIndex === ''){
this.$refs.uToast.show({type:'error',title: "请选择图片元素!"});
// this.dotLoading = false;
return false;
}
if(currentType === 3){
if(this.selectElementIndex === '' || !this.form.text || !this.form.promt){
this.$refs.uToast.show({type:'error',title: "请完善信息!"});
// this.dotLoading = false;
return false;
}
}
if(currentType === 4){
const { bottomImageUrl, topImageUrl } = this.$refs.dressRef.form;
if(topImageUrl===''){
this.$refs.uToast.show({type:'error',title: "请选择更换上衣!"});
// this.dotLoading = false;
return false;
}
}
return true;
},
// 获取参数值
getParams({id, type, options, text, promt}){
let result,that = this;
switch(type){
case 0 :
result = {
serviceId: id,
imageUrl: that.uploadFile,
}
break;
case 1 :
result = {
serviceId: id,
option: options[that.selectElementIndex].optionKey,
text: text,
}
if(this.selectSizeIndex !== '') result.size = that.form.id === 4 ? that.aliDimensions[that.selectSizeIndex].name : that.volcengineDimensions[that.selectSizeIndex].name;
break;
case 2 :
result = {
serviceId: id,
imageUrl: that.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 { bottomImageUrl, topImageUrl } = this.$refs.dressRef.form;
result = {
serviceId: id,
bottomImageUrl: bottomImageUrl,
topImageUrl: topImageUrl,
imageUrl: that.getImagePath(that.uploadFile),
};
if(bottomImageUrl === '') delete result.bottomImageUrl;
else result.bottomImageUrl = that.getImagePath(bottomImageUrl);
if(topImageUrl === '') delete result.topImageUrl;
else result.topImageUrl = that.getImagePath(topImageUrl);
break;
}
return result;
},
// 获取图片格式化路径
getImagePath(path){
return path?.includes('://') ? path : encodeURI(this.ip+path);
},
// 判断是否在微信内置浏览器打开
// #ifndef APP || MP
isMpWeb(){
if(navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){
this.$refs.uToast.show({type:'warning',title: "请在浏览器打开进行下载或长按图片保存到相册!"});
return true;
}else{
return false;
}
},
// #endif
// 图片下载
async download(){
let that = this;
// #ifndef APP || MP
if(this.isMpWeb()) return;
// #endif
this.functionLoading = true;
if(this.resultFile==='') {
this.$refs.uToast.show({type:'error',title: "暂无结果图片可下载!"});
this.functionLoading = false;
return;
}
// 判断是否为异步生图 ×
// 现在均为异步的均作以下判断
if(this.asyncPollTime !== -1){
this.$refs.uToast.show({type:'warning',title: "图片生成中请前往我的作品查看下载!"});
this.functionLoading = false;
return;
} else if(!this.asyncResult){
this.$refs.uToast.show({type:'error',title: "图片生成失败请重试!"});
this.functionLoading = false;
return;
}
// 下载地址
// #ifdef H5
let downloadUrl = await that.resultFile.replace(that.aliIp, "/ossUpload");
downloadUrl = await downloadUrl.replace(that.otherAliIp, "/otherOssUpload");
downloadUrl = await downloadUrl.replace(that.anotherAliIp, "/anotherOssUpload");
// #endif
// #ifndef H5
let downloadUrl = that.resultFile;
// #endif
// #ifdef H5
uni.request({
url: downloadUrl,
method: 'GET',
header: { 'token' : that.$store.state.vuex_token },
responseType: 'arraybuffer',
success(res) {
const arrayBuffer = res.data;
const blob = new Blob([arrayBuffer], {type: 'image/png'}); // 创建 Blob 对象
const imageUrl = URL.createObjectURL(blob); // 通过 Blob 对象创建图片 URL
let a = document.createElement('a'); //创建一个 a 标签
a.href = imageUrl; //把路径赋到a标签的href上
a.download = 'pixel.png';
a.click();
URL.revokeObjectURL(imageUrl);
a = null;
that.$refs.uToast.show({type:'success',title: "图片下载成功!"});
},
fail() {
that.$refs.uToast.show({type:'error',title: "图片下载失败请重试!"});
},
complete() {
that.functionLoading = false;
}
});
// #endif
// #ifndef H5
uni.downloadFile({
url: downloadUrl,
header: { 'token': that.$store.state.vuex_token },
success: (res) => {
if (res.statusCode === 200) {
//文件保存到本地
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath, //临时路径
success: function(resp) {
that.$refs.uToast.show({type:'success',title: "下载成功,请前往手机相册查看!"});
},
fail: function(err) {
that.$refs.uToast.show({type:'error',title: "暂不支持下载,请长按保存!"});
}
});
}else{
that.$refs.uToast.show({type:'error',title: "下载失败,请重试!"});
}
},
fail() {
that.$refs.uToast.show({type:'error',title: "暂不支持下载,请长按保存!"});
},
complete() {
that.functionLoading = false;
}
});
// #endif
},
// 重新绘制
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(){
if(this.form.type===0){
this.selectImage();
}else if(this.form.type){
this.resultFile = '';
this.uploadFile = '';
}else if(this.form.type === 4){
this.resultFile = '';
this.uploadFile = '';
this.$refs.dressRef.resetForm();
};
this.errorTips = '';
this.asyncPollTime = -1;
setTimeout(()=>{this.dealPercent = 100;});
},
// 使用教程
showTutorial(){
if(this.form.exampleUrl){
if(this.UniPlatform === 'web'){
window.open(encodeURI(this.form.exampleUrl));
}else{
uni.navigateTo({
url: `/pages/index/webview?src=${encodeURI(this.form.exampleUrl)}`
})
}
}else{
this.$refs.uToast.show({type:'warning',title: "暂无使用教程,请自求多福!"});
}
},
// 切换操作按钮
changeFunction(){
this.transition = true;
const keys = Object.keys(this.resultFunction);
this.index = (this.index+1) % keys.length;
this.currentType = keys[this.index];
setTimeout(()=>{
this.transition = false;
},500)
},
// 增强提示词
async strengthenTip({input, deal}){
if(input === null || input === ''){
this.$refs.uToast.show({type:'warning',title: "请提供部分词句!"});
deal();
return;
}else{
let res = await this.$api.createTip(input);
if(res.success){
deal(res.data);
}else{
this.$refs.uToast.show({type:'error',title: "提示词强化失败!"});
deal();
return;
}
}
},
// 元素选择
selectElement(index){
this.selectElementIndex = this.selectElementIndex === index ? '' : index;
},
// 尺寸选择
selectSize(index){
this.selectSizeIndex = this.selectSizeIndex === index ? '' : index;
},
}
}
</script>
<style scoped lang="scss">
.mobile-workshops{
display: flex;
flex-direction: column;
justify-content: space-between;
min-height: 100vh;
background-size: cover;
// #ifdef APP || MP
.app-top{
width: 100%;
position: fixed;
z-index: 81;
top: 0;
}
// #endif
.mwt-top{
// #ifdef APP || MP
.app-top{
width: 100%;
position: fixed;
z-index: 81;
top: 0;
}
// #endif
.mobile-logo{
width: 100%;
display: flex;
justify-content: center;
position: fixed;
z-index: 81;
padding: 15rpx 0;
image{
width: 200rpx;
height: 45rpx;
}
}
.mw-title{
color: #fff;
font-size: 35rpx;
line-height: 35rpx;
font-weight: bold;
position: relative;
display: flex;
align-items: center;
justify-content: center;
margin: 80rpx 40rpx 32rpx;
height: 40rpx;
.back{
position: absolute;
left: 0;
&:active{
filter: opacity(0.8);
}
}
}
.mw-upload{
display: flex;
flex-direction: column;
margin: 15rpx 100rpx;
.mwu-promt{
height: 100rpx;
margin-top: 120rpx;
display: flex;
align-items: center;
width: calc(100% + 100rpx);
margin-left: -50rpx;
border-radius: 20rpx;
box-shadow: 0 0 10rpx #eee;
border: 2rpx solid #858585;
}
.mwu-cover{
width: 100%;
height: 550rpx;
background-color: #626262;
border-radius: 35rpx;
border: 2rpx solid #858585;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
&:active{
filter: opacity(0.8);
}
.mwuc-tips{
font-size: 28rpx;
margin: 30rpx 0 -70rpx;
color: #f9f9f9;
text{
color: rgba(229, 64, 70, 1);
}
}
}
.center-image{
border-radius: 35rpx;
width: 100%;
min-height: 650rpx;
display: flex;
align-items: center;
image{
width: 100%;
border-radius: 35rpx;
border: 2rpx solid #858585;
}
}
.selections{
margin-top: 20rpx;
width: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
.selections-item{
margin-left: 20rpx;
width: 150rpx;
height: 48rpx;
line-height: 50rpx;
border: 56rpx;
color: #fff;
font-weight: bold;
font-size: 20rpx;
display: flex;
align-items: center;
justify-content: center;
background-size: cover;
}
}
}
.mw-editor{
margin: 50rpx 46rpx 12rpx;
display: flex;
flex-direction: column;
.slot{
color: #fff;
font-size: 32rpx;
font-weight: bold;
}
.section-options{
// margin-top: 40rpx;
display: grid;
grid-gap: 26rpx;
grid-template-columns: repeat(4,1fr);
.section-tags{
height: 200rpx;
width: 150rpx;
background-color: #2a243d;
border-radius: 20rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
color: #b3a0da;
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;
}
}
.section-tags-select{
border: 2rpx solid #ff55f5;
image{
opacity: 1;
}
}
.u-tag{
width: 200rpx;
height: 80rpx;
font-size: 28rpx;
display: flex;
color: rgba(41,121,255,0.6);
background-color: rgba(236,245,255,0.8);
align-items: center;
justify-content: center;
&:active{
opacity: 0.8;
}
}
.u-tag-select{
box-shadow: 0 0 15rpx #eee;
color: #2979ff;
background-color: rgba(236,245,255,1);
}
}
/deep/.u-section{
margin-bottom: 40rpx;
}
.dimensional-drawing{
height: 180rpx;
// margin-top: 40rpx;
display: flex;
.dimensional-item{
min-width: 160rpx;
height: 100%;
padding: 0 20rpx 18rpx;
background-color: #2a243d;
border-radius: 20rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
color: #b3a0da;
margin-right: 30rpx;
&:nth-last-child(1){
margin-right: 0;
}
text{
width: 100%;
text-align: center;
margin-top: 20rpx;
}
view{
opacity: 0.7;
border-radius: 10rpx;
width: 60rpx;
border: 4rpx solid #aea4ee;
aspect-ratio: 1/1;
}
}
.dimensional-item-select{
border: 2rpx solid #ff55f5;
view{
opacity: 1;
box-shadow: 0 0 10rpx #aea4ee;
}
text{
text-shadow: 0 0 2rpx #aea4ee;
}
}
}
}
.workshops-tip{
margin-top: 50rpx;
justify-content: center;
align-items: center;
display: flex;
font-size: 28rpx;
color: #c2fc3b;
.tip-content{
justify-content: center;
align-items: center;
display: flex;
.u-icon{
margin-right: 15rpx;
}
}
.tip-progress{
display: flex;
align-items: center;
width: calc(100% - 200rpx);
.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;
}
// #ifdef MP
.uline-progress{
width: 100%;
}
// #endif
::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%);
}
}
}
}
.workshops-btn{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin: 80rpx 0 40rpx;
// 价格提示
.price-tips{
text-align: center;
font-size: 24rpx;
color: #b2d210;
width: 65%;
margin-bottom: 6rpx;
text{
margin: 0 10rpx;
color: red;
}
}
// 保存图片
.wbu-dbtn{
margin: 0 10rpx;
// #ifndef MP
padding: 50rpx 70rpx;
// #endif
border: none;
height: 100rpx;
color: rgba(42, 35, 61, 0.9);
font-size: 32rpx;
font-weight: bold;
background-size: 200% auto;
transition: 0.5s;
animation-duration: 1s;
animation-fill-mode: both;
background-image: linear-gradient(to right, #c2fc3b 0%, #c2ffd8 51%, #c2fc3b 100%);
&:active {
background-position: right center;
color: #fff;
text-decoration: none;
// #ifdef MP
/deep/.u-btn--default{
color: #fff;
}
// #endif
}
// #ifdef MP
border-radius: 56rpx;
/deep/.u-btn--default{
padding: 50rpx 70rpx;
background-color: #ffffff00;
border: none;
color: rgba(42, 35, 61, 0.9);
width: 100%;
height: 100rpx;
border-radius: 56rpx;
}
// #endif
/deep/.u-icon{
margin-right: 10rpx;
}
}
// 重新制图
.wbu-odbtn{
padding: 4rpx;
background: #1a1929;
display: flex;
justify-content: center;
align-items: center;
border-radius: 56rpx;
overflow: hidden;
box-sizing: border-box;
background: linear-gradient(90deg, #2dc5da, #e313ee) !important;
.wbud-btn{
width: 100%;
height: 92rpx;
// #ifndef MP
padding: 0 70rpx;
// #endif
background: #1a1929;
border: none;
/deep/.u-icon{
margin-right: 10rpx;
}
text{
background-image: linear-gradient(to right, #aea4ee 0%, #e26afd 100%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
// #ifdef MP
border-radius: 56rpx;
/deep/.u-btn--default{
background-color: #ffffff00;
border: none;
// color: rgba(42, 35, 61, 0.9);
width: 100%;
height: 92rpx;
border-radius: 56rpx;
}
// #endif
}
}
.wbu-btn{
margin: 0;
border: none;
width: 70%;
height: 100rpx;
color: rgba(42, 35, 61, 0.9);
font-size: 35rpx;
font-weight: bold;
background-size: 200% auto;
transition: 0.5s;
animation-duration: 1s;
animation-fill-mode: both;
background-image: linear-gradient(to right, #c2fc3b 0%, #c2ffd8 51%, #c2fc3b 100%);
&:active {
background-position: right center;
color: #fff;
text-decoration: none;
// #ifdef MP
/deep/.u-btn--default{
color: #fff;
}
// #endif
}
/deep/.u-icon{
margin-right: 10rpx;
}
// #ifdef MP
border-radius: 56rpx;
/deep/.u-btn--default{
background-color: #ffffff00;
border: none;
color: rgba(42, 35, 61, 0.9);
width: 100%;
height: 100rpx;
border-radius: 56rpx;
}
// #endif
}
.transition{
animation-name: fadeIn;
}
.wb-change{
color: #fff;
margin-left: 20rpx;
margin-right: -70rpx;
&:active{
filter: opacity(0.6);
}
}
}
}
.options-popup{
.op-content{
background-color: #2D3240;
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: #2a243d;
border-radius: 20rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
color: #b3a0da;
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;
}
}
.section-tags-select{
border: 2rpx solid #ff55f5;
image{
opacity: 1;
}
}
.u-tag{
width: 200rpx;
height: 80rpx;
font-size: 28rpx;
display: flex;
color: rgba(41,121,255,0.6);
background-color: rgba(236,245,255,0.8);
align-items: center;
justify-content: center;
&:active{
opacity: 0.8;
}
}
.u-tag-select{
box-shadow: 0 0 15rpx #eee;
color: #2979ff;
background-color: rgba(236,245,255,1);
}
}
}
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>