PixelAI-mobile/pages/pc_web/wall/wall.vue
2025-02-19 15:51:04 +08:00

608 lines
18 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-wall" :style="windowHeight>1000?{}:{ minHeight: windowHeight+'px'}">
<!-- 左侧图片列表 -->
<view class="wall-images" v-loading="loading" :style="{backgroundImage: getTip.backgroundImage}">
<view class="display-wall">
<view class="display-title">
<view class="display-title-left">
专题
<u-line class="display-line" direction="col" color="#000" length="42rpx" />
</view>
<text @click="showList = true">{{ form.name || '暂无' }}</text>
</view>
<view class="display-introduce">
<text class="introduce-author">pixel.ai制图社</text>
<text class="introduce-time">{{ dateFormat(photos[0] ? photos[0].createtime : form.createtime) }}</text>
<text>广州</text>
</view>
</view>
<view class="display-tips" :style="{color: getTip.color}">
<text>{{ getTip.emotion }}</text>
<text>{{ getTip.text }}</text>
</view>
<u-waterfall class="display-photos" v-model="photos" ref="uWaterfall">
<template v-slot:left="{leftList}">
<view class="photo-lam" @click="maskTouchend(item)" v-for="(item,index) in leftList" :key="item.id">
<u-lazy-load border-radius="30" class="display-photo"
:image="getImagePath(item.watermarkPath)"></u-lazy-load>
<view class="sign-text">{{ item.serviceName || '暂无' }}</view>
<image :lazy-load="true" class="sign" :src="fileUrl+sign"></image>
</view>
</template>
<template v-slot:right="{rightList}">
<view class="photo-lam" @click="maskTouchend(item)" v-for="(item,index) in rightList" :key="item.id">
<u-lazy-load border-radius="30" class="display-photo"
:image="getImagePath(item.watermarkPath)"></u-lazy-load>
<view class="sign-text">{{ item.serviceName || '暂无' }}</view>
<image :lazy-load="true" class="sign" :src="fileUrl+sign"></image>
</view>
</template>
</u-waterfall>
<view class="last-tip" :style="{color: getTip.color}">
~~ 持续更新中 ~~
</view>
</view>
<view class="work-big">
<view class="big-image" :class="Object.keys(selectItem).length !== 0 ? 'big-image-none' : ''">
<view v-if="Object.keys(selectItem).length !== 0" class="bi-show-image">
<view class="bi-hover">
<u-icon size="90" title="预览" :name="fileUrl+previewIcon" @click="handlePreview"></u-icon>
<u-icon size="90" title="做同款" :name="fileUrl+sameIcon" @click="toDeal"></u-icon>
<u-icon size="90" title="购买原图" :name="fileUrl+buyIcon" @click="buyOrdPicture"></u-icon>
</view>
<image :src="getImagePath(selectItem.watermarkPath)" mode="aspectFit" class="big-preview"></image>
</view>
<view class="big-image" v-else>
<image :src="fileUrl+sleep"></image>
<view class="none-tips">
暂无作品,敬请期待!
</view>
</view>
</view>
</view>
<view class="hide-view" v-show="showList" @click="hideList">
<view @click.stop class="hide-lam" :style="{backgroundImage: getTip.backgroundImage}"
:class="showHide ? 'hide-animation' : ''">
<view class="special-top">
专题栏
<image :src="fileUrl+blackStar"></image>
</view>
<view class="special-scroll">
<view class="special-item" v-for="(item,index) in labels"
:key="index" @click="navigateTo(item.id,index)">
<text :style="[getSelectionsStyle(item.id)]">{{ item.name }}</text>
<u-icon name="arrow-right" :color="item.id === labelId ? getTip.color : 'rgba(105, 105, 105, 0.5)'"></u-icon>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import configService from '@/common/config.service.js';
import { tools } from '@/utils/utils.js';
export default {
data(){
return{
// 基础地址
ip: configService.ip,
fileUrl: configService.fileUrl + 'pixel/',
// 标签图标
sign: 'home/typelam.png',
// 禁用pc端的缺省图
sleep: 'pc/sleep.png',
// 预览图标
previewIcon: 'pc/workshops/preview.png',
// 选择黑星图片
blackStar: 'work/black-star.png',
// 购买图标
buyIcon: 'pc/workshops/download.png',
// 做同款图标
sameIcon: 'pc/workshops/same.png',
// 屏幕高度
windowHeight: 0,
// 选中图片
selectItem:{},
// 专题信息
form: {},
// 照片墙
photos: [],
// 专题id
labelId: '',
// 类型列表
typeList: {
'0' : '图生图',
'1' : '文生图',
'2' : '选项+图片',
'3' : '选项+文字',
'4' : '换装',
},
// 操作提示
tipText: ["1、点击标题切换专题","2、双击图片可购买原图"],
// 提示语
tips: {
'0' : { color: '#3f5b9c', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(63, 91, 156, 0.3) 100%)', emotion: '( •̀ ω •́ )y', text: '智 / 能 / 创 / 作' },
'28' : { color: '#8ee200', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(142, 226, 0, 0.3) 100%)', emotion: '(o゜▽゜)o☆', text: '容 / 光 / 焕 / 发' },
'29' : { color: '#dd4747', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(221, 71, 71, 0.3) 100%)', emotion: '( ˘•ω•˘ )◞⁽˙³˙⁾', text: '多 / 样 / 颜 / 平 / 方' },
'31' : { color: '#f64e9c', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(246, 78, 156, 0.3) 100%)', emotion: '(*´∀`)~♥', text: '花 / 样 / 试 / 衣 / 间' },
'33' : { color: '#93931e', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(147, 147, 30, 0.3) 100%)', emotion: '(:3[___]=', text: '妄 / 想 / 时 / 间' },
'35' : { color: '#32bbff', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(50, 187, 255, 0.3) 100%)', emotion: '(☄◣ω◢)☄', text: '壁 / 纸 / 专 / 题 / 展' },
'2' : { color: '#8d5ff8', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(141, 95, 248, 0.3) 100%)', emotion: '(∩^o^)⊃━☆゚.*・。', text: '动 / 感 / 人 / 像' },
'4' : { color: '#fdc535', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(253, 197, 53, 0.3) 100%)', emotion: '(´◉‿◉`)', text: '幻 / 想 / 时 / 间' },
'7' : { color: '#52fec7', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(82, 254, 199, 0.3) 100%)', emotion: 'ヾ(´︶`*)ノ♬', text: '通 / 形 / 文 / 字 / 展' },
'9' : { color: '#0C5460', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(12, 84, 96, 0.3) 100%)', emotion: '(̿▀̿ ̿Ĺ̯̿̿▀̿ ̿)̄', text: '面 / 部 / 造 / 型 / 社' },
'10' : { color: '#0f93b6', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(15, 147, 182, 0.3) 100%)', emotion: 'ƪ(•̃͡ε•̃͡)∫', text: '高 / 端 / 发 / 廊 / 展' },
'11' : { color: '#606971', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(96, 105, 113, 0.3) 100%)', emotion: '∠( ᐛ 」∠)_', text: '岁 / 月 / 时 / 光 / 机' },
'12' : { color: '#b3a0da', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(179, 160, 218, 0.3) 100%)', emotion: '(੭ ᐕ)੭?', text: '棱 / 角 / 分 / 明' },
'13' : { color: '#fde46c', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(253, 228, 108, 0.3) 100%)', emotion: '(≖_≖)✧', text: '漫 / 画 / 世 / 界' },
'14' : { color: '#5dfec9', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(93, 254, 201, 0.3) 100%)', emotion: '-//(ǒ.ǒ)//-', text: '摄 / 像 / 牢 / 笼' },
'15' : { color: '#fb7bb2', backgroundImage: 'linear-gradient( to bottom, #ffffff 0%, rgba(251, 123, 178, 0.3) 100%)', emotion: '-`д´-', text: '人 / 像 / 抠 / 图 / ' },
// (σ′▽‵)′▽‵)σ
},
// 加载
loading: false,
// 专题列表
labels: [],
// 列表展开
showList: false,
// 列表关闭动画
showHide: false,
}
},
beforeMount() {
// 计算当前窗口高度
this.windowHeight = window.screen.height;
},
computed: {
// 获取提示语
getTip(){
return this.tips[this.labelId]||this.tips['0'];
},
// 获取专栏列表选中样式
getSelectionsStyle(id){
return (id) => {
return this.labelId===id?{ color: this.getTip.color} : {};
}
},
},
mounted() {
this.getLabels();
},
methods:{
// 获取标签
async getLabels(){
this.loading = true;
let res = await this.$api.getLabels(4);
if(res?.success){
this.labels = res.data;
if(!this.labelId){
this.labelId = this.labels[0]?.id;
this.form = this.labels.length > 0 ? this.labels[0] : {};
}
this.getPhotos();
}else{
this.loading = false;
this.$emit('toast',{type:'error',title: "专题列表获取失败!"});
}
},
// 获取作品墙
async getPhotos(){
try{
this.loading = true;
let that = this;
let res = await this.$api.allPictureWall({labelId: this.labelId});
if(res?.success){
this.photos = res.data;
this.selectItem = this.photos.length > 0 ? this.photos[0] : {};
}else{
this.$emit('toast',{type:'error',title: "作品墙内容获取失败!"});
}
}catch(e){this.loading = false;}
finally{this.loading = false;}
},
// 图片格式化
getImagePath(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);
},
// 图片点击事件
maskTouchend(item,index){
this.selectItem = item;
},
// 图片预览
handlePreview(){
let item = this.selectItem;
const array = [this.getImagePath(item.watermarkPath)];
tools.methods.lookImage(0,array);
},
// 时间格式化
dateFormat(time){
let date = time ? new Date(time) : new Date();
let month = date.getMonth()+1,
day = date.getDate(),
hour = date.getHours(),
minute = date.getMinutes(),
second = date.getSeconds();
return `${date.getFullYear()}年${month<10?'0':''}${month}月${day<10?'0':''}${day}日 ${hour<10?'0':''}${hour}:${minute<10?'0':''}${minute}`;
},
// 前往工作室——做同款
toDeal(){
let id = this.selectItem.serviceId;
if(id!==null&&id!=='')
this.$emit('changeService',id);
else this.$emit('toast',{type:'error',title: "暂未开放对应功能!"});
},
// 购买原图
buyOrdPicture(){
let that = this;
let item = this.selectItem;
uni.showModal({
title: '购买提示',
content: `该作品原图购买需支付${item.price}钻石,购买后将直接下载,若使用了微信内置浏览器,请点击右上角打开浏览器再进行购买,以免购买后下载失败!`,
confirmColor: this.getTip.color,
success: async (res) => {
if (res.confirm) {
let resp = await that.$api.buyOriginalPicture({id: item.id});
if(resp?.success){
await that.download(resp.data.originalPath);
}else{
that.$emit('toast',{type:'error',title: "购买失败,请检查余额是否充足!"});
}
}
}
});
},
// 图片下载
async download(path = ''){
let that = this;
if(this.path === '') {
this.$emit('toast',{type:'error',title: "暂无结果图片可下载!"});
return;
}
// 下载地址
let downloadUrl = encodeURI(path);
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.$emit('toast',{type:'success',title: "图片下载成功!"});
},
fail() {
that.$emit('toast',{type:'error',title: "图片下载失败,请重试!"});
},
complete() {
that.functionLoading = false;
}
});
},
// 跳转专栏
navigateTo(id, index){
if(this.labelId === id) return;
this.labelId = id;
this.form = this.labels[index];
this.$refs.uWaterfall.clear();
this.hideList();
this.getPhotos();
},
// 隐藏列表
hideList(){
this.showHide = true;
setTimeout(()=>{
this.showList = false;
this.showHide = false;
},300)
}
}
}
</script>
<style scoped lang="scss">
.pc-wall{
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;
position: relative;
overflow: hidden;
.wall-images{
margin-left: 200rpx;
width: 900rpx;
height: 1620rpx;
background-color: #fff;
border-radius: 40rpx;
transition: 0.3s;
display: flex;
flex-direction: column;
overflow: hidden;
border: 2rpx solid #d5d5d5;
box-shadow: 0 0 20rpx #c6c6c6;
.display-wall{
margin: 80rpx 44rpx 32rpx;
.display-title{
display: flex;
align-items: center;
font-size: 50rpx;
font-weight: 600;
.display-title-left{
min-width: 130rpx;
display: flex;
align-items: center;
.display-line{
margin: 0 16rpx !important;
border-width: 6rpx !important;
}
}
text{
font-weight: normal;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
color: #576ba3;
cursor: pointer;
&:hover{
opacity: 0.8;
}
&:active{
opacity: 0.6;
}
}
}
}
.display-introduce{
display: flex;
align-items: center;
margin: 30rpx 0 30rpx;
font-size: 32rpx;
color: #a8abb2;
.introduce-author{
color: #576ba3;
}
.introduce-time{
margin: 0 24rpx;
}
}
.display-tips{
margin-top: 60rpx;
display: flex;
flex-direction: column;
align-items: center;
font-size: 30rpx;
text{
margin: 10rpx 0;
}
}
.display-photos{
margin: 50rpx 50rpx 40rpx;
column-gap: 2.2em;
-moz-column-gap: 2.2em;
-webkit-column-gap: 2.2em;
.photo-lam{
-webkit-column-break-inside: avoid;
break-inside: avoid; /*防止断点*/
margin-bottom: 1em;
position: relative;
padding-top: 12rpx;
.display-photo{
border-radius: 30rpx;
// 骗系统开启硬件加速
transform: transition3d(0, 0, 0);
// 防止图片加载闪一下
will-change: transform;
box-shadow: 0 0 20rpx #696969;
cursor: pointer;
}
&:hover{
filter: opacity(0.8);
}
&:active{
filter: opacity(0.6);
}
.sign-text{
width: 140rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
color: #ffffff;
font-size: 28rpx;
position: absolute;
top: 0.85em;
left: 0.9em;
z-index: 1;
}
.sign{
border: none;
border-radius: 0;
position: absolute;
top: 0.8em;
left: 0.6em;
width: 170rpx;
height: 47rpx;
}
}
}
.last-tip{
color: rgb(63, 91, 156);
font-size: 30rpx;
text-align: center;
margin: 20rpx 0 40rpx;
}
&:hover{
box-shadow: 0 0 20rpx #8a8a8a;
}
}
.work-big{
flex: 1;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
border-radius: 40rpx;
.big-image{
width: 1350rpx;
height: 1350rpx;
background-color: #ffffff;
border: 4rpx dashed #99d7ff;
border-radius: 40rpx;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
transition: 0.3s;
overflow: hidden;
.bi-show-image{
width: 100%;
height: 100%;
position: relative;
.big-preview{
width: 100%;
height: 100%;
}
.bi-hover{
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0,0,0,0.5);
z-index: 1;
transition: 0.5s;
opacity: 0;
.u-icon{
margin: 0 30rpx;
cursor: pointer;
&:hover{
opacity: 0.8;
}
&:active{
opacity: 0.6;
}
}
}
}
.none-tips{
margin-top: 30rpx;
color: #9a702d;
font-size: 50rpx;
}
&:hover{
box-shadow: 0 0 20rpx #d3d3d3;
.bi-hover{
opacity: 1;
}
}
}
.big-image-none{
background-color: #ffffff00;
border: none;
}
}
.hide-view{
z-index: 2;
bottom: 0;
position: fixed;
left: 0;
width: 100%;
height: calc(100% - 110rpx);
background-color: rgba(0,0,0,0.5);
.hide-lam{
bottom: 0;
position: fixed;
left: 0;
height: calc(100% - 110rpx);
width: 400rpx;
display: flex;
flex-direction: column;
background-color: rgba(255, 255, 255, 0.9);
border-right: 4rpx solid #eee;
animation-duration: 0.5s;
animation-fill-mode: both;
animation-name: slideInLeft;
.special-top{
padding: 80rpx 40rpx 40rpx;
margin-left: 14rpx;
font-size: 46rpx;
font-weight: bold;
position: relative;
color: #222;
image{
position: absolute;
margin-top: -10rpx;
width: 30rpx;
height: 34rpx;
}
}
.special-scroll{
flex: 1;
overflow-y: scroll;
.special-item{
margin: 0 20rpx;
padding: 20rpx 30rpx;
color: #696969;
border-radius: 16rpx;
font-size: 36rpx;
border-top: 2rpx solid #eee;
// box-shadow: 0 0 10rpx #eee;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
.u-icon{
opacity: 0.6;
}
&:hover{
opacity: 0.8;
}
&:active{
opacity: 0.6;
}
&:nth-last-child(1){
border-bottom: 2rpx solid #eee;
}
}
}
}
.hide-animation{
animation-duration: 0.3s !important;
animation-name: slideOutLeft !important;
}
}
}
@keyframes slideInLeft {
from {
transform: translate3d(-100%, 0, 0);
visibility: visible;
}
to {
transform: translate3d(0, 0, 0);
}
}
@keyframes slideOutLeft {
from {
transform: translate3d(0, 0, 0);
}
to {
visibility: hidden;
transform: translate3d(-100%, 0, 0);
}
}
</style>