PixelAI-mobile/pages/pc_web/home/components/second.vue

571 lines
15 KiB
Vue
Raw Permalink 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="home-second">
<view class="hs-search-title">
<text @click="toWall">推荐作品</text>
<image :src="fileUrl+blackStar"></image>
</view>
<!-- 筛选项 -->
<scroll-view :scroll-x="true" class="hs-search">
<view class="hs-scroll">
<view v-for="(item,index) in serviceList" :key="index" class="search-tag"
:class="siftIndex===index ? 'search-tag-selected' : ''" @click="sift(item,index)">{{ item.name }}</view>
</view>
</scroll-view>
<!-- 第一栏——轮播图+服务 -->
<view class="hs-swiper">
<view class="hs-carousel">
<el-carousel>
<el-carousel-item v-for="(item,index) in swiperList" :key="index">
<image @click="linkTo(item.url)" class="swiper-image" :src="item.path"
:style="{cursor: item.url ? 'pointer' : 'default'}"></image>
</el-carousel-item>
</el-carousel>
</view>
<view class="hs-second">
<u-section class="hss-lam" title="AI工具" sub-title="更多"
font-size="50" @click="$emit('handleChangeService')"/>
<view class="hss-scroll">
<view class="hss-left" @click="scrollTo(0)" v-show="showScroll[0]">
<u-icon name="arrow-left" size="34"></u-icon>
</view>
<scroll-view class="hss-scroll-view" @scroll="scroller" ref="scrollView"
scroll-with-animation :scroll-left="scrollLeft" scroll-x>
<view class="hss-services">
<view class="hss-service" v-for="(item,index) in serviceList.slice(1)" :key="index" @click="$emit('handleChangeService', item.id)">
<image :src="encodeURI(staticIp+item.icon)"></image>
{{ item.name }}
</view>
</view>
</scroll-view>
<view class="hss-right" @click="scrollTo(1)" v-show="showScroll[1]">
<u-icon name="arrow-right" size="34"></u-icon>
</view>
</view>
</view>
</view>
<view class="hs-services">
<!-- 瀑布流布局图片 -->
<masonry :cols="7" gutter="1em">
<view class="hs-service" v-for="(item,index) in workList" :key="item.id">
<u-lazy-load @click="preview(item)" :title="item.serviceName||'暂无'" border-radius="30" class="hss-picture"
:image="getWorkPath(item.path)" v-loading="item.loading"></u-lazy-load>
<view class="sign-text">{{ item.serviceName || '暂无' }}</view>
<image :lazy-load="true" class="sign" :src="fileUrl+sign"></image>
<view class="work-todo">
<view class="wt-same" @click.stop="$emit('handleChangeService', item.serviceId)">
<image :src="fileUrl+magicWand"></image>
<text>做同款</text>
</view>
<view class="wt-same wt-download" @click="download(item)">
<u-icon name="download" size="36" color="#c9fe76" />
<text>下载 </text>
</view>
</view>
</view>
</masonry>
<!-- 下面这里等后端有了之后用isFinish判断 -->
<view class="last-tip" :class="recommendForm.isFinish?'':'clickable'" @click="getMore">
{{ recommendForm.isFinish ? '~~ 已加载全部 ~~' : '~~ 点击加载更多 ~~' }}
</view>
</view>
</view>
</template>
<script>
import configService from '@/common/config.service.js';
import { tools } from '@/utils/utils.js';
export default {
data(){
return{
// 基础地址
staticIp: configService.ip,
aliUrl: configService.aliUrl.split("://")[1],
fileUrl: configService.fileUrl + 'pixel/',
aliIp: configService.aliUrl,
otherAliIp: configService.otherAliUrl,
anotherAliIp: configService.anotherAliUrl,
// 选择黑星图片
blackStar: 'work/black-star.png',
// 魔术棒
magicWand: 'home/magic-wand.png',
// 标签图标
sign: 'home/typelam.png',
// 轮播图列表
swiperList: [],
// 服务列表
serviceList: [],
// 推荐作品列表
workList: [],
// 筛选项
siftIndex: 0,
// 滚动程度
scrollLeft: 0,
// 是否滚动到最左/右边
showScroll: [false,true],
// ai工具栏scroll宽度
scrollViewWidth: 0,
// 推荐作品表单
recommendForm: {
current: 1,
size: 20,
isFinish: true,
serviceId: '',
isBackend: 0
},
// 下载加载
downLoading: false,
}
},
mounted() {
// 获取ai工具栏宽度
this.scrollViewWidth = this.$refs.scrollView.$el.clientWidth;
this.getBanner();
this.getServices();
this.recommendForm = {current: 1,size: 20,isFinish: false,serviceId: '',isBackend: 0};
this.getWorkList();
},
methods:{
// 获取轮播图
async getBanner(){
let res = await this.$api.allBanners();
if(res?.success){
this.swiperList = res.data.map(item=>{
return {...item,path: encodeURI(this.staticIp+item.path)}
});
}else{
this.$emit('showToast',{type:'error',title: "轮播图获取失败!"});
}
},
// 获取服务筛选列表
async getServices(){
let res = await this.$api.allServices();
if(res.success){
const arr = res.data;
this.serviceList = [{id: -1,name:"全部"},...arr];
}else{
this.$emit('showToast',{type:'error',title: "筛选列表获取失败!"});
}
},
// 获取推荐作品列表
async getWorkList(){
if(this.recommendForm.isFinish) return;
let res = await this.$api.getRecommend(this.recommendForm);
if(res?.success){
const { records, total, current, size } = res.data;
const result = records;
if(current === 1){
this.workList = result;
}else{
this.workList.push(...result);
}
this.recommendForm.isFinish = current*size >= total;
this.$forceUpdate();
}else{
this.$emit('showToast',{type:'error',title: "推荐作品获取失败!"});
}
},
// 筛选
sift(item, index){
this.siftIndex = index;
this.recommendForm.serviceId = item.id === -1 ? '' : item.id;
this.recommendForm.current = 1;
this.recommendForm.isFinish = false;
this.getWorkList();
},
// 图片格式化
getWorkPath(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.staticIp+path);
},
// 轮播图跳转
linkTo(url){
if(url) window.open(encodeURI(url));
},
// 预览图片
preview(item){
const array = [this.getWorkPath(item.path)];
if(item.sourcePath) array.push(this.getWorkPath(item.sourcePath));
tools.methods.lookImage(0,array);
},
// ai工具栏滚动——0左滚、1右滚
scrollTo(type = 0){
let endo = 1000;
type === 0 ? this.scrollLeft -= endo : this.scrollLeft += endo;
},
// ai工具栏滚动监听
scroller({detail}){
const { scrollLeft, scrollWidth, deltaX } = detail;
this.showScroll[0] = scrollLeft !== 0;
this.showScroll[1] = (scrollLeft + this.scrollViewWidth - (deltaX || 0)) < scrollWidth;
this.$forceUpdate();
},
// 图片下载
async download(item){
let that = this;
let path = item.path;
item.loading = true;
if(!path || path==='') {
this.$emit('showToast',{type:'error',title: "该作品暂不可下载!"});
item.loading = false;
return;
}
// 下载地址
// let downloadUrl = await path.replace(that.aliIp, "/ossUpload");
let downloadUrl = path;
if(path.includes(that.aliIp)||path.includes(that.otherAliIp)||path.includes(that.anotherAliIp)){window.open(downloadUrl);item.loading = false;}
else
uni.request({
url: encodeURI(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('showToast',{type:'success',title: "图片下载成功!"});
},
fail() {
that.$emit('showToast',{type:'error',title: "图片下载失败,请重试!"});
},
complete() {
item.loading = false;
}
});
},
// 查看更多
getMore(){
if(this.recommendForm.isFinish) return;
this.recommendForm.current++;
this.getWorkList();
},
// 前往作品墙
toWall(){
this.$emit('toWall');
},
}
}
</script>
<style scoped lang="scss">
.home-second{
width: 100%;
min-height: 73.5em;
background-image: linear-gradient(to left top, #ffffff, #fcfbfc, #f8f8f9, #f5f4f7, #f1f1f4, #eef0f6, #eaeff7, #e5eff8, #ddf3f9, #d9f6f2, #def7e6, #eef6d9);
.hs-search-title{
padding: 100rpx 40rpx 40rpx;
margin-left: 14rpx;
font-size: 40rpx;
font-weight: bold;
position: relative;
text{
background-image: linear-gradient(to right, #222 , #999, #222, #999, #222);
background-clip: text;
-webkit-background-clip: text;
background-size: 200% 100%;
color: transparent;
animation: light 2s infinite linear;
cursor: pointer;
&:hover{
opacity: 0.8;
}
&:active{
opacity: 0.6;
}
}
image{
position: absolute;
top: 84rpx;
width: 30rpx;
height: 34rpx;
}
}
.hs-search{
padding: 0rpx 40rpx 40rpx;
.hs-scroll{
display: flex;
align-items: center;
.search-tag{
white-space: nowrap;
border: 2rpx solid #ebebec;
color: #909399;
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx 30rpx;
margin: 0 14rpx;
height: 74rpx;
border-radius: 16rpx;
background-color: #f4f4f5;
cursor: pointer;
&:hover{
border-color: #c2e7b0;
color: #49cc90;
background-color: #e8f6f0;
}
}
.search-tag-selected{
border-color: #c2e7b0;
color: #49cc90;
background-color: #e8f6f0;
}
}
}
.hs-swiper{
height: 600rpx;
display: flex;
margin: 40rpx 40rpx 2em;
.hs-carousel{
min-width: 1250rpx;
border-radius: 16rpx;
background-color: #e2fd7d;
.swiper-image{
width: 100%;
height: 100%;
border-radius: 16rpx;
}
}
.hs-second{
display: flex;
flex-direction: column;
width: 2460rpx;
margin: 0 0 0 2em;
background: red;
border-radius: 40rpx;
background-image: linear-gradient(0deg,#e1ecfd,#cee2ff);
padding: 50rpx;
.hss-lam{}
.hss-scroll{
flex: 1;
background-image: linear-gradient(235deg,#e1ecfd 31.76%,#cee2ff 86.2%);
margin-top: 30rpx;
border-radius: 30rpx;
padding: 50rpx;
position: relative;
display: flex;
align-items: center;
.hss-scroll-view{
.hss-services{
height: 100%;
display: flex;
white-space: nowrap;
// overflow-x: scroll;
align-items: center;
.hss-service{
display: flex;
flex-direction: column;
align-items: center;
margin: 0 40rpx 0 0;
cursor: pointer;
font-size: 30rpx;
&:nth-last-child(1){
margin-right: 0;
}
image{
width: 266rpx;
height: 260rpx;
border-radius: 32rpx;
border: 6rpx solid #eee;
margin-bottom: 10rpx;
}
&:hover{
color: #dcffe9;
image{
box-shadow: 0 0 20rpx #eee;
border-color: #daf6f3;
}
}
&:active{
opacity: 0.8;
}
}
}
}
.hss-left,.hss-right{
z-index: 1;
position: absolute;
border-radius: 100%;
display: flex;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
background-color: rgba(240,240,240,0.9);
cursor: pointer;
opacity: 0;
transition: 0.5s;
&:hover{
opacity: 0.9 !important;
}
&:active{
opacity: 0.6 !important;
}
}
.hss-left{
left: 30rpx;
}
.hss-right{
right: 30rpx;
}
&:hover{
.hss-left,.hss-right{
opacity: 0.6;
}
}
}
::v-deep .u-section__right-info{
cursor: pointer;
&:hover{
opacity: 0.8;
}
&:active{
opacity: 0.6;
}
}
}
}
.hs-services{
padding: 0rpx 40rpx 40rpx;
// column-count:5;
// -moz-column-count:5; /* Firefox */
// -webkit-column-count:5; /* Safari Chrome */
// column-gap: 2em;
// -moz-column-gap: 2em;
// -webkit-column-gap: 2em;
.hs-service{
-webkit-column-break-inside: avoid;
break-inside: avoid; /*防止断点*/
// width: 400rpx;
margin-bottom: 1em;
position: relative;
overflow: hidden;
border-radius: 30rpx;
.hss-picture{
cursor: pointer;
border: 2rpx solid #d5ff00;
border-radius: 30rpx;
// 骗系统开启硬件加速
transform: transition3d(0, 0, 0);
// 防止图片加载闪一下
will-change: transform;
}
.sign{
border: none;
border-radius: 0;
position: absolute;
top: 0.8em;
left: 0.6em;
width: 190rpx;
height: 54rpx;
}
.sign-text{
width: 160rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
color: #ffffff;
font-size: 30rpx;
position: absolute;
top: 0.9em;
left: 0.9em;
z-index: 1;
}
.work-todo{
width: 100%;
height: 100rpx;
position: absolute;
z-index: 1;
border-radius: 8rpx 8rpx 30rpx 30rpx;
bottom: -100rpx;
// bottom: 2rpx;
left: 0;
background-color: rgba(0, 0, 0, 0.3);
display: flex;
align-items: center;
justify-content: space-around;
font-size: 30rpx;
transition: 0.5s;
.wt-same{
width: 200rpx;
height: 70rpx;
border-radius: 56rpx;
border: 2rpx solid #a3d4ff;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(242, 245, 247, 0.2);
text{
font-weight: bold;
background-image: linear-gradient(to right, #cdfbf2 0%, #a3d4ff 100%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
image{
margin-right: 10rpx;
width: 34rpx;
height: 34rpx;
}
&:hover{
opacity: 0.8;
}
&:active{
opacity: 0.6;
}
}
.wt-download{
width: 180rpx;
border-color: #c5fe6e;
text{
background-image: linear-gradient(to right, #c9fe76 0%, #a5fe2f 100%);
}
}
}
&:hover{
.work-todo{
bottom: 2rpx;
}
}
}
.last-tip{
font-size: 36rpx;
text-align: center;
margin-top: 20rpx;
margin-bottom: 20rpx;
background-image: linear-gradient(to right, #a3d4ff 0%, #bee7df 100%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.clickable{
cursor: pointer;
&:hover{
opacity: 0.8;
}
&:active{
opacity: 0.6;
}
}
}
}
@keyframes light {
0% {
background-position: 0 0;
}
100% {
background-position: -100% 0;
}
}
</style>