PixelAI-mobile/pages/pc_web/workshops/workshops.vue

1232 lines
35 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>
<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> -->
<u-toast ref="uToast"></u-toast>
</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.$refs.uToast.show({type: 'error', title: '服务列表获取失败'});
}
}catch(e){
this.$refs.uToast.show({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.$refs.uToast.show({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.$refs.uToast.show({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.$refs.uToast.show({type:'warning',title: "暂无使用教程,请自求多福!"});
}
},
// 增强提示词
async strengthenTip({input, deal}){
if(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;
}
}
},
// 图片格式化
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) {
this.$refs.uploadCover.clearFiles();
that.$refs.uToast.show({type: 'warning',title: "图片上传格式错误!"});
return;
}
const size = file.raw.size / 1024; // 计算文件大小
if(size<5 || (size/1024)>5){
this.$refs.uploadCover.clearFiles();
that.$refs.uToast.show({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.$refs.uToast.show({type:'error',title: currentType === 4 ? "请选择模特!" : "请上传图片!"});
return false;
}
if(currentType === 1){
if(this.selectElementIndex === '' || !this.serviceItem.text){
this.$refs.uToast.show({type:'error',title: "请完善信息!"});
return false;
}
}
if(currentType === 2 && this.selectElementIndex === ''){
this.$refs.uToast.show({type:'error',title: "请选择图片元素!"});
return false;
}
if(currentType === 3){
if(this.selectElementIndex === '' || !this.serviceItem.text || !this.serviceItem.promt){
this.$refs.uToast.show({type:'error',title: "请完善信息!"});
return false;
}
}
if(currentType === 4){
const { bottomsUrl, coatUrl } = this.$refs.dressRef.form;
if(coatUrl===''){
this.$refs.uToast.show({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.$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.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.$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.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.$refs.uToast.show({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.$refs.uToast.show({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>