PixelAI-mobile/pages/mobile_web/workshops/index.vue
2024-12-10 10:25:46 +08:00

741 lines
20 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">
<view class="mobile-logo" :style="{backgroundColor: `rgba(255, 255, 255,${topLevel})`}">
<!-- #ifdef H5 -->
<!-- <u-icon name="arrow-left" size="40" color="#c2ea04" class="back" @click="back"></u-icon> -->
<!-- #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">
<!-- 文生图-空格位 -->
<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>
<!-- 上传了需修改图 -->
<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="ip+resultFile" @click="previewImage"></image>
</view>
<!-- 其他-涂抹重绘 -->
<view class="selections" v-if="!resultFile && form.type===-1">
<view class="selections-item" :style="currentSelect===index?{ backgroundImage: `url(${fileUrl+selectBackground})` }:
{ color: '#000', backgroundImage: `url(${fileUrl+noSelectBackground})` }"
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"
placeholder="如: 衣服/鞋子/头发或者英文:clothes and shose">
<template #title>
<text class="slot">需<text style="color: #d8fa35;">替换</text>的元素</text>
</template>
</EditorBox>
<EditorBox :icon="fileUrl+editorIcon"
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 !== 1 || (form.type === 1 && resultFile)">
Tips{{ resultFile ? '点击预览图片效果~' : form.tips+"~" }}
</view>
<!-- 文生图 -->
<view class="mw-editor" v-if="!resultFile && form.type===1">
<EditorBox :height="200" :icon="fileUrl+editorIcon" title="提示词"
v-model="form.text" placeholder="请输入描述的提示词~~"/>
</view>
<!-- 提示文字 -->
<view class="mw-editor" v-if="!resultFile && form.type===3">
<EditorBox :icon="fileUrl+editorIcon" title="提示词" v-model="form.promt"
placeholder="请输入描述的提示词~~"/>
</view>
<!-- 选项生图 -->
<view class="mw-editor" v-if="!resultFile && (form.type===2||form.type===3 || form.type === 1)">
<u-section title="类型选择" color="#fff" :right="false" lineColor="#c2ea04" fontSize="40" @click="toList"></u-section>
<view class="section-options">
<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" v-if="!resultFile && form.type===4">
<DressSelect />
</view>
</view>
<view class="workshops-btn">
<u-button class="wbu-btn" @click="startDeal" v-if="resultFile===''"
ripple :hairLine="false" shape="circle" rippleBgColor="#f0fdbf" :loading='dotLoading'>
<u-icon name="edit-pen" size="42"></u-icon>开启魔法
</u-button>
<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">
<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 { selectDealFunction } from './common/imgDeal'
import { toList } from './common/functionalClassification'
export default {
components: {
EditorBox, DressSelect
},
data(){
return{
// 全加载
loading: false,
// 顶部距离等级
topLevel: 0,
// 基础路径
ip: configService.ip,
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.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: ()=>{
if(this.form.type===0)
this.selectImage();
else{
this.resultFile = '';
this.uploadFile = '';
}
}
},
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: '',
// 弹窗显示更多选项
showMoreOptions: false
}
},
// #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();
},
computed: {
getOptions(){
let options = this.form.options;
const length = this.form.options.length;
return length > 9 ? options.slice(0,8) : options;
}
},
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.$refs.uToast.show({type:'error',title: "ai功能暂未开放!"});
}
}catch(e){}
finally{
this.loading = false;
}
},
// 返回
back(){
uni.navigateBack();
},
// 上传图片
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
if(this.resultFile!=='') this.resultFile = '';
that.uploadFile = res.tempFilePaths[0];
}
});
},
// 预览图片
previewImage(){
const previewImages = [this.ip+this.resultFile];
if(this.uploadFile) previewImages.push(this.uploadFile);
tools.methods.lookImage(0,previewImages);
},
// 开始处理图片
async startDeal(){
try{
this.dotLoading = true;
let that = this;
if(!this.legalJudge()) return;
// 再实际处理
selectDealFunction(that,that.form.type,that.getParams(that.form),
(path)=>{
that.resultFile = path;
that.$refs.uToast.show({type:'success',title: `${that.form.name}成功!`});
this.dotLoading = false;
});
}catch(e){
this.dotLoading = false;
}finally{
}
},
// 表单合法判断
legalJudge(){
const currentType = this.form.type;
if(currentType !== 3 && currentType !== 1 && this.uploadFile===''){
this.$refs.uToast.show({type:'error',title: "请上传图片!"});
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;
}
}
return true;
},
// 获取参数值
getParams({id, type, options, text, promt}){
let result,that = this;
switch(type){
case 0 :
result = {
serviceId: id,
filePath: that.uploadFile,
}
break;
case 1 :
result = {
serviceId: id,
option: options[that.selectElementIndex].optionKey,
text: text,
}
break;
case 2 :
result = {
serviceId: id,
filePath: that.uploadFile,
option: options[that.selectElementIndex].optionKey
}
break;
case 3 :
result = {
serviceId: id,
option: options[that.selectElementIndex].optionKey,
text: text,
promt: promt
}
break;
}
return result;
},
// 判断是否在微信内置浏览器打开
// #ifndef APP
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
if(this.isMpWeb()) return;
// #endif
this.functionLoading = true;
if(this.resultFile==='') {
this.$refs.uToast.show({type:'error',title: "暂无结果图片可下载!"});
this.functionLoading = false;
return;
}
// #ifdef H5
uni.request({
url: '/'+that.resultFile,
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: that.ip+that.resultFile,
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: "下载成功,请前往手机相册查看!"});
}
});
}else{
that.$refs.uToast.show({type:'error',title: "下载失败,请重试!"});
}
},
fail() {
that.$refs.uToast.show({type:'error',title: "暂不支持下载,请长按保存!"});
},
complete() {
that.functionLoading = false;
}
});
// #endif
},
// 切换操作按钮
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)
},
// 元素选择
selectElement(index){
this.selectElementIndex = index;
// this.form.options[index];
},
// 导入的方法
toList,
}
}
</script>
<style scoped lang="scss">
.mobile-workshops{
display: flex;
flex-direction: column;
justify-content: space-between;
min-height: 100vh;
background-size: cover;
.mwt-top{
// #ifdef APP
.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;
}
.mwu-cover{
width: 100%;
height: 550rpx;
background-color: #626262;
border-radius: 35rpx;
border: 2rpx solid #858585;
display: flex;
align-items: center;
justify-content: center;
&:active{
filter: opacity(0.8);
}
}
.center-image{
border-radius: 35rpx;
width: 100%;
min-height: 650rpx;
display: flex;
align-items: center;
image{
width: 100%;
border-radius: 35rpx;
}
}
.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: 30rpx;
grid-template-columns: repeat(3,1fr);
.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);
}
}
}
.workshops-tip{
margin-top: 70rpx;
color: #d5ff00;
font-size: 28rpx;
text-align: center;
}
}
.workshops-btn{
display: flex;
align-items: center;
justify-content: center;
margin: 80rpx 0 40rpx;
.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;
}
.u-icon{
margin-right: 10rpx;
}
}
.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;
display: flex;
flex-direction: column;
.op-top{
height: 80rpx;
display: flex;
align-items: center;
}
.options-list{
height: 800rpx;
color: #a7b6b8;
width: 100%;
margin-top: 20rpx;
.section-options{
display: grid;
grid-gap: 30rpx;
grid-template-columns: repeat(3,1fr);
.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>