Files
msh-system/msh_single_uniapp/pages/ai-generate/inspiration.vue

1093 lines
29 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="inspiration-container">
<!-- 顶部导航 -->
<view class="nav-bar" :style="{ paddingTop: statusBarHeight + 'px' }">
<view class="nav-content">
<text class="nav-title">发现</text>
</view>
<!-- 分类标签 -->
<scroll-view scroll-x class="category-tabs" :show-scrollbar="false">
<view
v-for="(cat, index) in categories"
:key="index"
:class="['tab-item', selectedCategory === cat.value ? 'active' : '']"
@click="selectCategory(cat.value)"
>
<text class="tab-text">{{ cat.label }}</text>
</view>
</scroll-view>
</view>
<!-- 瀑布流内容 -->
<scroll-view
scroll-y
class="content-scroll"
:style="{ top: scrollViewTop, bottom: scrollViewBottom, height: scrollViewHeight }"
@scrolltolower="loadMore"
@scroll="onScroll"
>
<!-- AI生成内容标识 -->
<view class="ai-notice">
<text class="ai-notice-text">内容由AI生成</text>
</view>
<!-- 骨架屏加载 -->
<view class="skeleton-container" v-if="loading && leftColumnData.length === 0">
<view class="skeleton-waterfall">
<!-- 左列骨架 -->
<view class="skeleton-column">
<view class="skeleton-card" v-for="n in 3" :key="'left-' + n">
<view class="skeleton-image"></view>
<view class="skeleton-info">
<view class="skeleton-title"></view>
<view class="skeleton-meta">
<view class="skeleton-avatar"></view>
<view class="skeleton-text"></view>
</view>
</view>
</view>
</view>
<!-- 右列骨架 -->
<view class="skeleton-column">
<view class="skeleton-card" v-for="n in 3" :key="'right-' + n">
<view class="skeleton-image" :style="{ height: (n % 2 === 0 ? '200' : '150') + 'px' }"></view>
<view class="skeleton-info">
<view class="skeleton-title"></view>
<view class="skeleton-meta">
<view class="skeleton-avatar"></view>
<view class="skeleton-text"></view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 实际内容 -->
<view class="waterfall-container" v-else>
<!-- 左列 -->
<view class="waterfall-column">
<view
v-for="(item, index) in leftColumnData"
:key="item.id"
class="inspiration-card"
@click="viewDetail(item)"
>
<!-- 图片 -->
<view class="card-image-wrapper">
<image
:src="item.image"
mode="widthFix"
class="card-image"
lazy-load
></image>
<view class="type-tag" :class="item.type === 'video' ? 'video' : 'image'">
{{ item.type === 'video' ? '视频' : '图文' }}
</view>
</view>
<!-- 信息 -->
<view class="card-info">
<text class="card-title">{{ item.title }}</text>
<view class="card-meta">
<view class="author-info">
<image
:src="item.author.avatar || item.authorAvatar || '/static/images/avatar-default.png'"
class="author-avatar"
mode="aspectFill"
@error="handleAvatarError($event, item)"
></image>
<text class="author-name">{{ item.author.name }}</text>
</view>
<view class="card-stats">
<text class="iconfont icon-aixin"></text>
<text class="stat-text">{{ formatNumber(item.likeCount) }}</text>
</view>
</view>
</view>
<!-- 对比按钮 -->
<view class="card-action" v-if="selectedCategory === 'comparison'">
<button class="action-btn" @click.stop="goToEffect(item)">对比</button>
</view>
</view>
</view>
<!-- 右列 -->
<view class="waterfall-column">
<view
v-for="(item, index) in rightColumnData"
:key="item.id"
class="inspiration-card"
@click="viewDetail(item)"
>
<!-- 图片 -->
<view class="card-image-wrapper">
<image
:src="item.image"
mode="widthFix"
class="card-image"
lazy-load
></image>
<view class="type-tag" :class="item.type === 'video' ? 'video' : 'image'">
{{ item.type === 'video' ? '视频' : '图文' }}
</view>
</view>
<!-- 信息 -->
<view class="card-info">
<text class="card-title">{{ item.title }}</text>
<view class="card-meta">
<view class="author-info">
<image
:src="item.author.avatar || item.authorAvatar || '/static/images/avatar-default.png'"
class="author-avatar"
mode="aspectFill"
@error="handleAvatarError($event, item)"
></image>
<text class="author-name">{{ item.author.name }}</text>
</view>
<view class="card-stats">
<text class="iconfont icon-aixin"></text>
<text class="stat-text">{{ formatNumber(item.likeCount) }}</text>
</view>
</view>
</view>
<!-- 对比按钮 -->
<view class="card-action" v-if="selectedCategory === 'comparison'">
<button class="action-btn" @click.stop="goToEffect(item)">对比</button>
</view>
</view>
</view>
</view>
<!-- 加载更多 -->
<view class="loading-more" v-if="loading">
<view class="loading-spinner"></view>
<text class="loading-text">加载中...</text>
</view>
<!-- 没有更多 -->
<view class="no-more" v-if="noMore">
<text class="no-more-text">没有更多了</text>
</view>
</scroll-view>
<!-- 底部导航栏 -->
<view class="bottom-tabbar">
<view
v-for="(tab, index) in tabBar"
:key="index"
:class="['tab-item', tab.active ? 'active' : '']"
@click="switchTab(tab.path)"
>
<!-- 想象图标 - 使用纯CSS绘制 -->
<view v-if="tab.label === '想象'" class="tab-icon-imagine">
<view class="snowflake">
<view class="snowflake-line snowflake-line-1"></view>
<view class="snowflake-line snowflake-line-2"></view>
<view class="snowflake-line snowflake-line-3"></view>
</view>
</view>
<!-- 字体图标 -->
<text v-else class="iconfont" :class="tab.icon"></text>
<text class="tab-label">{{ tab.label }}</text>
</view>
</view>
</view>
</template>
<script>
import api from '@/api/models-api.js'
export default {
data() {
return {
statusBarHeight: 0,
scrollViewHeight: '100vh',
scrollViewTop: '0px',
scrollViewBottom: '0px',
// 分类
selectedCategory: 'hot',
categories: [
{ label: '热门模版', value: 'hot', icon: '🔥' },
{ label: '设计案例', value: 'cases', icon: '✨' },
{ label: '装修前后', value: 'comparison', icon: '📷' },
{ label: '视频案例', value: 'videocases', icon: '' },
{ label: '营销活动', value: 'activity', icon: '' }
],
// 瀑布流数据
allData: [],
leftColumnData: [],
rightColumnData: [],
// 加载状态
loading: false,
noMore: false,
page: 1,
pageSize: 20,
// 底部导航
tabBar: [
{ label: '推荐', icon: 'icon-shouye', path: '/pages/index/index', active: false },
{ label: '想象', path: '/pages/ai-generate/index', active: true },
{ label: '智能体', icon: 'icon-kefujiedai', path: '/pages/ai-generate/agent', active: false },
{ label: '我的', icon: 'icon-wode', path: '/pages/user/index', active: false }
]
};
},
onLoad() {
this.initPage();
this.loadData();
},
methods: {
initPage() {
const systemInfo = uni.getSystemInfoSync();
this.statusBarHeight = systemInfo.statusBarHeight || 0;
// 计算滚动区域位置和高度
const navHeight = 44 + 50; // 导航(44px) + 分类标签(50px)
const tabbarHeight = 50; // 底部导航栏
// 设置 scroll-view 的位置
this.scrollViewTop = `${this.statusBarHeight + navHeight}px`;
this.scrollViewBottom = `${tabbarHeight}px`;
// 计算高度
const totalHeight = this.statusBarHeight + navHeight + tabbarHeight;
this.scrollViewHeight = `calc(100vh - ${totalHeight}px)`;
},
// 判断URL是否为图片格式
isImageUrl(url) {
if (!url) return false;
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg'];
const lowerUrl = (url.split('?')[0].split('#')[0] || '').toLowerCase();
return imageExtensions.some(ext => lowerUrl.endsWith(ext));
},
// 处理头像URL添加前缀
getAvatarUrl(avatarUrl) {
if (!avatarUrl || avatarUrl === '/static/images/avatar-default.png') {
return '/static/images/avatar-default.png';
}
// 如果已经是完整URL直接返回
if (avatarUrl.startsWith('http://') || avatarUrl.startsWith('https://')) {
return avatarUrl;
}
// 如果是相对路径,添加前缀
const prefix = 'https://uthink2025.oss-cn-shanghai.aliyuncs.com/';
// 如果URL已经以/开头,去掉开头的/
const cleanUrl = avatarUrl.startsWith('/') ? avatarUrl.substring(1) : avatarUrl;
return prefix + cleanUrl;
},
isVideoUrl(url) {
if (!url) return false;
const videoExtensions = ['.mp4', '.mov', '.m3u8', '.webm', '.avi', '.wmv', '.flv', '.mkv'];
const lowerUrl = (url.split('?')[0].split('#')[0] || '').toLowerCase();
return videoExtensions.some(ext => lowerUrl.endsWith(ext));
},
getArticleType(article) {
const url = article.videoUrl || '';
return this.isVideoUrl(url) ? 'video' : 'image';
},
// 加载数据
async loadData() {
if (this.loading || this.noMore) return;
this.loading = true;
try {
const params = {
page: this.page,
size: this.pageSize,
statusTask:1
};
// 如果是装修前后分类添加type参数
if (this.selectedCategory === 'comparison') {
params.type = 1;
} else if (this.selectedCategory === 'videocases') {
// 如果是视频案例分类添加type参数
params.type = 2;
}
const response = await api.searchArticles(params);
if (response.code === 200 && response.data) {
const articles = response.data.records || [];
// 转换文章数据为瀑布流数据格式
const newData = articles.map(article => {
// 先获取类型
const articleType = this.getArticleType(article);
return {
id: article.id,
title: article.title || '未命名作品',
// 如果类型为image使用videoUrl否则使用imageInput
image: articleType === 'image'
? (article.videoUrl || '/static/images/placeholder.png')
: (article.imageInput || '/static/images/placeholder.png'),
type: articleType, // 根据videoUrl后缀智能判断类型
articleType: article.type,
template: true, // 所有文章都可以作为模板使用
likeCount: parseInt(article.visit) || 0,
author: {
name: article.authorName || '创作者',
avatar: this.getAvatarUrl(article.authorAvatar) || '/static/images/avatar-default.png'
},
// 保留原始 authorAvatar 属性,方便直接访问(已处理前缀)
authorAvatar: this.getAvatarUrl(article.authorAvatar) || '/static/images/avatar-default.png',
// 额外的文章信息
imageInput: article.imageInput, // 添加 imageInput
prompt: article.prompt,
synopsis: article.synopsis,
videoUrl: article.videoUrl,
taskId: article.taskId,
aspectRatio: article.aspectRatio,
createTime: article.createTime
};
});
// 分配数据到瀑布流
this.distributeData(newData);
// 更新分页状态
if (newData.length < this.pageSize) {
this.noMore = true;
}
this.page++;
} else {
uni.showToast({
title: '加载失败',
icon: 'none'
});
}
} catch (error) {
console.error('加载文章列表失败:', error);
uni.showToast({
title: '网络错误,请重试',
icon: 'none'
});
} finally {
this.loading = false;
}
},
// 分配数据到左右列(瀑布流)
distributeData(newData) {
newData.forEach(item => {
// 简化算法:交替分配
if (this.leftColumnData.length <= this.rightColumnData.length) {
this.leftColumnData.push(item);
} else {
this.rightColumnData.push(item);
}
});
},
// 选择分类
selectCategory(value) {
this.selectedCategory = value;
// 重置数据
this.leftColumnData = [];
this.rightColumnData = [];
this.page = 1;
this.noMore = false;
this.loadData();
},
// 滚动事件
onScroll(e) {
// 可以添加滚动逻辑,如返回顶部按钮显示等
},
// 加载更多
loadMore() {
this.loadData();
},
// 查看详情
viewDetail(item) {
console.log('点击文章详情:', item);
// 根据类型跳转到不同页面
if (item.type === 'video' && item.videoUrl) {
uni.navigateTo({
url: `/pages/ai-generate/video?id=${item.id}`
});
} else if (item.type === 'image') {
uni.navigateTo({
url: `/pages/ai-generate/image?id=${item.id}`
});
} else {
uni.showToast({
title: `查看${item.title}`,
icon: 'none'
});
}
},
// 跳转到对比效果页
goToEffect(item) {
const beforeImage = encodeURIComponent(item.imageInput || '');
const afterImage = encodeURIComponent(item.videoUrl || '');
const promptText = encodeURIComponent(item.prompt || item.synopsis || '');
uni.navigateTo({
url: `/pages/ai-generate/effect?id=${item.id}&beforeImage=${beforeImage}&afterImage=${afterImage}&promptText=${promptText}`
});
},
// 使用模板
useTemplate(item) {
uni.showModal({
title: '使用模板',
content: '是否使用此模板生成图片?',
success: (res) => {
if (res.confirm) {
// 跳转到生成页面,并传递模板信息
uni.navigateTo({
url: `/pages/ai-generate/index?templateId=${item.id}`
});
}
}
});
},
// 跳转搜索
goToSearch() {
uni.navigateTo({
url: '/pages/ai-generate/search'
});
},
// 切换Tab
switchTab(path) {
if (path === '/pages/ai-generate/inspiration') {
return; // 当前页面
}
// 推荐页首页和我的页使用switchTab
if (path === '/pages/index/index' || path === '/pages/user/index') {
this.tabBar = this.tabBar.map(t => ({ ...t, active: t.path === path }))
uni.switchTab({ url: path });
} else {
// 想象页AI生成使用navigateTo
this.tabBar = this.tabBar.map(t => ({ ...t, active: t.path === path }))
uni.navigateTo({ url: path });
}
},
// 格式化数字
formatNumber(num) {
if (num >= 10000) {
return (num / 10000).toFixed(1) + 'w';
} else if (num >= 1000) {
return (num / 1000).toFixed(1) + 'k';
}
return num.toString();
},
// 处理头像加载错误
handleAvatarError(e, item) {
console.log('头像加载失败,重置为默认头像:', e);
if (item) {
if (item.author) {
item.author.avatar = '/static/images/avatar-default.png';
}
item.authorAvatar = '/static/images/avatar-default.png';
}
}
}
};
</script>
<style lang="scss" scoped>
.inspiration-container {
width: 100%;
min-height: 100vh;
background: linear-gradient(180deg, #000000 0%, #1a1a1a 100%);
overflow-x: hidden;
}
// 顶部导航
.nav-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
background: rgba(10, 14, 26, 0.95);
backdrop-filter: blur(20px);
z-index: 999;
.nav-content {
display: flex;
align-items: center;
justify-content: center;
height: 44px;
padding: 0 16px;
position: relative;
.nav-title {
font-size: 16px;
font-weight: 600;
color: #ffffff;
text-align: center;
}
.nav-right {
position: absolute;
right: 16px;
.search-btn {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
.iconfont {
font-size: 20px;
color: #ffffff;
}
}
}
}
// 分类标签
.category-tabs {
position: relative;
white-space: nowrap;
padding: 0 16px 12px;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 0px;
background: linear-gradient(90deg, rgba(255,255,255,0.18), rgba(255,255,255,0.06), rgba(255,255,255,0.18));
opacity: 0.6;
pointer-events: none;
}
.tab-item {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 6px 16px;
margin-right: 12px; margin-top: 2px;
background: linear-gradient(180deg, rgba(50, 56, 72, 0.55) 0%, rgba(36, 40, 54, 0.65) 100%);
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.06);
box-shadow: inset 0 1px 2px rgba(255,255,255,0.12), 0 4px 8px rgba(0,0,0,0.25);
transition: all 180ms ease;
.tab-icon {
font-size: 14px;
}
.tab-text {
font-size: 14px;
color: #8f9bb3;
transition: color 180ms ease, text-shadow 180ms ease;
}
&.active {
background: radial-gradient(circle at 50% 20%, rgba(255,255,255,0.16) 0%, rgba(255,255,255,0.06) 45%, rgba(255,255,255,0) 62%), linear-gradient(180deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0.02) 100%);
border-color: #42ca4d;
box-shadow: inset 0 2px 6px rgba(255,255,255,0.12), 0 6px 12px rgba(0,0,0,0.35);
transform: translateY(-1px);
.tab-text {
color: #42ca4d;
text-shadow: 0 0 8px rgba(66, 202, 77, 0.45);
}
}
}
}
}
// 内容滚动区
.content-scroll {
position: fixed;
left: 0;
right: 0;
padding: 0px 12px;
box-sizing: border-box;
width: 100%;
overflow-x: hidden;
overflow-y: auto;
// AI生成内容标识 - 在滚动区域内
.ai-notice {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 6px 16px;
margin: 0 0 16px 0;
background: rgba(66, 202, 77, 0.1);
border: 1px solid rgba(66, 202, 77, 0.3);
border-radius: 8px;
backdrop-filter: blur(10px);
.ai-notice-icon {
font-size: 14px;
}
.ai-notice-text {
font-size: 11px;
color: #42ca4d;
line-height: 1.4;
}
}
}
// 骨架屏容器
.skeleton-container {
width: 100%;
padding: 0;
}
.skeleton-waterfall {
display: flex;
width: 100%;
gap: 12px;
.skeleton-column {
flex: 1;
display: flex;
flex-direction: column;
gap: 12px;
}
}
.skeleton-card {
width: 100%;
background: rgba(26, 31, 46, 0.8);
border-radius: 16px;
overflow: hidden;
.skeleton-image {
width: 100%;
height: 180px;
background: linear-gradient(90deg,
rgba(255, 255, 255, 0.05) 25%,
rgba(255, 255, 255, 0.1) 50%,
rgba(255, 255, 255, 0.05) 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}
.skeleton-info {
padding: 12px;
.skeleton-title {
width: 80%;
height: 16px;
background: linear-gradient(90deg,
rgba(255, 255, 255, 0.05) 25%,
rgba(255, 255, 255, 0.1) 50%,
rgba(255, 255, 255, 0.05) 75%);
background-size: 200% 100%;
border-radius: 4px;
margin-bottom: 12px;
animation: shimmer 1.5s infinite;
animation-delay: 0.1s;
}
.skeleton-meta {
display: flex;
align-items: center;
gap: 8px;
.skeleton-avatar {
width: 20px;
height: 20px;
border-radius: 50%;
background: linear-gradient(90deg,
rgba(255, 255, 255, 0.05) 25%,
rgba(255, 255, 255, 0.1) 50%,
rgba(255, 255, 255, 0.05) 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
animation-delay: 0.2s;
}
.skeleton-text {
flex: 1;
height: 12px;
background: linear-gradient(90deg,
rgba(255, 255, 255, 0.05) 25%,
rgba(255, 255, 255, 0.1) 50%,
rgba(255, 255, 255, 0.05) 75%);
background-size: 200% 100%;
border-radius: 4px;
animation: shimmer 1.5s infinite;
animation-delay: 0.3s;
}
}
}
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
// 瀑布流容器
.waterfall-container {
display: flex;
width: 100%; margin-top: 30rpx;
gap: 12px;
align-items: flex-start;
justify-content: space-between;
.waterfall-column {
flex: 1;
min-width: 0;
max-width: calc(50% - 6px);
display: flex;
flex-direction: column;
gap: 12px;
}
}
// 灵感卡片
.inspiration-card {
width: 100%;
background: rgba(26, 31, 46, 0.8);
border-radius: 6px;
overflow: hidden;
break-inside: avoid;
.card-image-wrapper {
position: relative;
width: 100%;
overflow: hidden;
background: rgba(0, 0, 0, 0.2);
.card-image {
width: 100%;
height: auto;
min-height: 100px;
display: block;
// border-radius: 16px 16px 0 0;
}
.media-tag {
position: absolute;
top: 8px;
right: 8px;
width: 28px;
height: 28px;
background: rgba(0, 0, 0, 0.6);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(10px);
.iconfont {
font-size: 14px;
color: #ffffff;
}
}
.type-tag {
position: absolute;
top: 8px;
left: 8px;
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
line-height: 18px;
color: #ffffff;
background: rgba(0,0,0,0.5);
border: 1px solid rgba(255,255,255,0.25);
backdrop-filter: blur(8px);
&.video {
border-color: rgba(33,150,243,0.5);
}
&.image {
border-color: rgba(66,202,77,0.5);
}
}
}
.card-info {
padding: 12px;
.card-title {
display: block;
font-size: 14px;
color: #ffffff;
margin-bottom: 8px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
line-clamp: 2;
word-break: break-all;
}
.card-meta {
display: flex;
align-items: center;
justify-content: space-between;
.author-info {
display: flex;
align-items: center;
gap: 6px;
flex: 1;
min-width: 0;
.author-avatar {
width: 20px;
height: 20px;
border-radius: 50%;
flex-shrink: 0;
}
.author-name {
font-size: 12px;
color: #8f9bb3;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.card-stats {
display: flex;
align-items: center;
gap: 4px;
flex-shrink: 0;
.iconfont {
font-size: 14px;
color: #8f9bb3;
}
.stat-text {
font-size: 12px;
color: #8f9bb3;
}
}
}
}
.card-action {
padding: 0 12px 12px;
.action-btn {
width: 100%;
height: 32px;
background: linear-gradient(135deg, #42ca4d 0%, #38b045 100%);
border-radius: 8px;
font-size: 13px;
color: #ffffff;
border: none;
line-height: 32px;
}
}
}
// 加载更多
.loading-more {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 20px;
width: 100%;
clear: both;
.loading-spinner {
width: 20px;
height: 20px;
border: 2px solid rgba(255, 255, 255, 0.2);
border-top-color: #42ca4d;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
.loading-text {
font-size: 13px;
color: #8f9bb3;
}
}
// 没有更多
.no-more {
padding: 20px;
text-align: center;
width: 100%;
clear: both;
.no-more-text {
font-size: 13px;
color: #8f9bb3;
}
}
// 底部导航栏
.bottom-tabbar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
height: calc(50px + env(safe-area-inset-bottom));
box-sizing: border-box;
align-items: center;
background: linear-gradient(180deg, rgba(20, 24, 34, 0.96) 0%, rgba(10, 12, 18, 0.98) 100%);
backdrop-filter: blur(20px);
border-top: 1px solid rgba(255, 255, 255, 0.06);
padding-bottom: env(safe-area-inset-bottom);
z-index: 999;
box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.35), 0 -12px 24px rgba(0, 0, 0, 0.25);
position: fixed;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, rgba(255,255,255,0.18), rgba(255,255,255,0.06), rgba(255,255,255,0.18));
opacity: 0.6;
pointer-events: none;
}
.tab-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2px;
border-radius: 12px;
padding: 2px 6px; margin:0px 20px;
transition: all 180ms ease;
position: relative;
.iconfont {
font-size: 22px;
color: #8f9bb3;
transition: color 180ms ease, transform 180ms ease, text-shadow 180ms ease;
}
.tab-icon-imagine {
width: 22px;
height: 22px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
.snowflake {
width: 22px;
height: 22px;
position: relative;
.snowflake-line {
position: absolute;
top: 50%;
left: 50%;
width: 18px;
height: 2px;
background: #8f9bb3;
transform-origin: center;
&::before,
&::after {
content: '';
position: absolute;
width: 6px;
height: 2px;
background: #8f9bb3;
}
&::before {
top: -4px;
left: 2px;
transform: rotate(-45deg);
}
&::after {
top: 4px;
left: 2px;
transform: rotate(45deg);
}
}
.snowflake-line-1 {
transform: translate(-50%, -50%) rotate(0deg);
}
.snowflake-line-2 {
transform: translate(-50%, -50%) rotate(60deg);
}
.snowflake-line-3 {
transform: translate(-50%, -50%) rotate(120deg);
}
}
}
.tab-label {
font-size: 10px;
color: #8f9bb3;
transition: color 180ms ease, text-shadow 180ms ease;
}
&.active {
background: radial-gradient(circle at 50% 20%, rgba(255,255,255,0.16) 0%, rgba(255,255,255,0.06) 42%, rgba(255,255,255,0) 60%),
linear-gradient(180deg, rgba(255,255,255,0.10) 0%, rgba(255,255,255,0.02) 100%);
box-shadow: inset 0 2px 6px rgba(255,255,255,0.12), 0 6px 12px rgba(0,0,0,0.35);
border: 1px solid rgba(255,255,255,0.08);
transform: translateY(-1px);
.iconfont,
.tab-label {
color: #42ca4d;
text-shadow: 0 0 8px rgba(66, 202, 77, 0.45);
}
.tab-icon-imagine {
.snowflake-line {
background: #42ca4d;
&::before,
&::after {
background: #42ca4d;
}
}
}
}
}
}
// 动画
@keyframes spin {
to {
transform: rotate(360deg);
}
}
</style>