ai-clone/frontend-ai/pages/index/index.vue
2026-03-05 14:29:21 +08:00

532 lines
11 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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="memorial-bg">
<image class="bg-image" :src="`${apiBase}/static/bg.png`" mode="aspectFill"></image>
<view class="memorial-content">
<!-- 头部设计 -->
<view class="header">
<text class="logo">时光意境 · AI亲人重逢</text>
<text class="tagline">用科技温暖记忆让告别不留遗憾</text>
</view>
<!-- 缅怀引言 -->
<view class="memorial-quote">
<swiper
class="banner-swiper"
:circular="true"
:autoplay="true"
:interval="3500"
:duration="500"
:indicator-dots="true"
indicator-color="rgba(255,255,255,0.5)"
indicator-active-color="#8B7355"
>
<swiper-item v-for="(item, idx) in banners" :key="idx">
<view class="banner-item" @click="handleBannerClick(item)">
<image class="banner-image" :src="resolveUrl(item.url)" mode="aspectFill" />
</view>
</swiper-item>
</swiper>
</view>
<!-- 核心功能入口 -->
<view class="feature-grid">
<view class="feature-item" @click="goPlaza">
<view class="feature-icon">🖼</view>
<text class="feature-name">作品广场</text>
</view>
<view class="feature-item" @click="goPhotoRevival">
<view class="feature-icon">📸</view>
<text class="feature-name">照片复活</text>
</view>
<view class="feature-item" @click="goShortDrama">
<view class="feature-icon">🎬</view>
<text class="feature-name">看短剧</text>
</view>
<view class="feature-item" @click="goAICall">
<view class="feature-icon">📹</view>
<text class="feature-name">视频通话</text>
</view>
</view>
<!-- 视频通话按钮 -->
<view class="video-call-section">
<button class="video-call-btn" @click="startVideoCall">
<text class="btn-icon">📹</text>
<text class="btn-text">开始视频通话</text>
</button>
</view>
<!-- 行动号召 -->
<view class="cta-section">
<text class="cta-text">只需简单三步即可与记忆中的亲人温暖"重逢"</text>
</view>
</view>
<!-- 视频选择弹窗 -->
<VideoSelectModal
:show="showVideoSelect"
@close="showVideoSelect = false"
@confirm="handleVideoSelect"
/>
</view>
</template>
<script>
import VideoSelectModal from '@/components/VideoSelectModal.vue';
import { API_BASE } from '@/config/api.js';
import { request } from '@/config/api.js';
export default {
components: {
VideoSelectModal
},
data() {
return {
apiBase: API_BASE,
title: '时光意境 · AI亲人重逢',
showVideoSelect: false,
banners: []
};
},
onLoad() {
this.loadHomeBanners();
},
methods: {
resolveUrl(url) {
if (!url) return '';
if (url.startsWith('http://') || url.startsWith('https://')) return url;
return `${this.apiBase}${url}`;
},
async loadHomeBanners() {
try {
const res = await request({ url: '/api/system/home-banners', method: 'GET' });
const list = res && res.success ? res.data : [];
if (Array.isArray(list)) {
this.banners = list
.filter((x) => x && x.url && x.enabled !== false)
.sort((a, b) => (Number(a.sort) || 0) - (Number(b.sort) || 0));
} else {
this.banners = [];
}
} catch (e) {
this.banners = [];
}
},
handleBannerClick(item) {
if (!item) return;
if (item.link) {
if (String(item.link).startsWith('/pages/')) {
uni.navigateTo({ url: item.link });
return;
}
uni.setClipboardData({ data: String(item.link) });
uni.showToast({ title: '已复制链接', icon: 'none' });
}
},
// 检查登录状态
checkLogin() {
const token = uni.getStorageSync('token');
const userId = uni.getStorageSync('userId');
return !!(token && userId);
},
// 跳转:声音克隆
goVoiceClone() {
// 如果该页面在 tabbar优先 switchTab失败则降级 navigateTo
uni.switchTab({
url: '/pages/revival/revival',
fail: () => {
uni.navigateTo({ url: '/pages/revival/revival' });
}
});
},
// 跳转:照片复活
goPhotoRevival() {
uni.navigateTo({
url: '/pages/revival/revival-original'
});
},
// 跳转:作品广场
goPlaza() {
uni.navigateTo({
url: '/pages/plaza/plaza'
});
},
// 开始视频通话
startVideoCall() {
// 检查登录状态
if (!this.checkLogin()) {
uni.showModal({
title: '提示',
content: '请先登录后再使用此功能',
confirmText: '去登录',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/login/login'
});
}
}
});
return;
}
this.showVideoSelect = true;
},
// 跳转AI通话页面
goAICall() {
// 与声音克隆同理,优先 switchTab失败再 navigateTo
uni.switchTab({
url: '/pages/phone-call/phone-call',
fail: () => {
uni.navigateTo({ url: '/pages/phone-call/phone-call' });
}
});
},
// 处理视频选择
handleVideoSelect(video) {
console.log('[Index] 选择视频:', video);
// 直接跳转到通话页面
uni.navigateTo({
url: `/pages/video-call-new/video-call-new?videoId=${video.id}&videoName=${encodeURIComponent(video.name || '复活视频')}&videoUrl=${encodeURIComponent(video.videoUrl || video.local_video_path || video.video_url)}&voiceId=${video.voice_id || video.voiceId}`
});
},
// 跳转看短剧内嵌H5页面
goShortDrama() {
uni.navigateTo({
url: '/pages/short-drama/short-drama'
});
}
}
};
</script>
<style lang="scss" scoped>
.memorial-bg {
position: relative;
min-height: 100vh;
overflow: hidden;
}
.bg-image {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
.memorial-content {
position: relative;
z-index: 2;
padding: 60upx 30upx 100upx;
max-width: 1200upx;
margin: 0 auto;
}
/* 头部设计 */
.header {
background: transparent;
color: #2C2C2C;
padding: 40upx 0 50upx;
text-align: center;
position: relative;
margin-bottom: 20upx;
&::after {
content: "";
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 200upx;
height: 3upx;
background: linear-gradient(90deg, transparent, #8B7355, transparent);
}
.logo {
font-size: 64upx;
font-weight: 700;
margin-bottom: 24upx;
color: #8B7355;
letter-spacing: 2upx;
display: block;
line-height: 1.2;
}
.tagline {
font-size: 32upx;
color: #666;
font-weight: 300;
margin: 0 auto;
display: block;
line-height: 1.5;
}
}
/* 缅怀引言 */
.memorial-quote {
text-align: center;
margin: 30upx 0 70upx;
padding: 22upx;
background: rgba(255, 255, 255, 0.6);
border-radius: 30upx;
backdrop-filter: blur(10upx);
box-shadow: 0 8upx 30upx rgba(0, 0, 0, 0.06);
}
::v-deep .banner-swiper {
width: 100%;
height: 900upx;
border-radius: 22upx;
overflow: hidden;
}
::v-deep .banner-item {
width: 100%;
height: 100%;
}
::v-deep .banner-image {
width: 100%;
height: 100%;
display: block;
}
/* 功能网格 */
.feature-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12upx;
margin: 30upx 0;
align-items: stretch;
}
::v-deep .feature-item {
background: rgba(255, 255, 255, 0.9);
border-radius: 18upx;
padding: 10upx 8upx;
text-align: center;
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
box-shadow: 0 8upx 24upx rgba(0, 0, 0, 0.08);
backdrop-filter: blur(20upx);
border: 2upx solid rgba(255, 255, 255, 0.8);
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
aspect-ratio: 1;
min-height: 0;
&::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4upx;
background: linear-gradient(135deg, #8B7355 0%, #6D8B8B 100%);
transform: scaleX(0);
transition: transform 0.3s;
}
&:active {
transform: translateY(-8upx) scale(0.98);
box-shadow: 0 16upx 40upx rgba(0, 0, 0, 0.12);
}
&:active::before {
transform: scaleX(1);
}
.feature-icon {
font-size: 32upx;
margin-bottom: 8upx;
color: #8B7355;
height: 56upx;
width: 56upx;
line-height: 56upx;
border-radius: 50%;
background: rgba(139, 115, 85, 0.1);
display: inline-block;
transition: all 0.3s;
flex-shrink: 0;
}
&:active .feature-icon {
background: linear-gradient(135deg, #8B7355 0%, #6D8B8B 100%);
color: white;
transform: scale(1.1);
}
.feature-name {
font-size: 18upx;
font-weight: 600;
color: #2C2C2C;
display: block;
line-height: 1.3;
}
}
/* 视频通话按钮区域 */
.video-call-section {
margin: 50upx 0 40upx;
padding: 0 20upx;
}
.video-call-btn {
width: 100%;
padding: 36upx;
background: linear-gradient(135deg, #8B7355 0%, #6D8B8B 100%);
color: white;
border: none;
border-radius: 40upx;
font-size: 32upx;
font-weight: bold;
box-shadow: 0 16upx 40upx rgba(139, 115, 85, 0.3);
transition: all 0.3s;
position: relative;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
gap: 16upx;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.2) 0%, transparent 100%);
}
&:active {
transform: translateY(-4upx);
box-shadow: 0 20upx 50upx rgba(139, 115, 85, 0.4);
}
.btn-icon {
font-size: 40upx;
}
.btn-text {
font-size: 32upx;
font-weight: bold;
}
}
/* 行动号召 */
.cta-section {
text-align: center;
margin: 70upx 0 40upx;
padding: 40upx 30upx;
background: rgba(255, 255, 255, 0.5);
border-radius: 30upx;
backdrop-filter: blur(10upx);
.cta-text {
font-size: 30upx;
color: #666;
margin: 0 auto;
line-height: 1.8;
display: block;
font-style: italic;
opacity: 0.9;
}
}
/* 响应式设计 */
@media (max-width: 750px) {
.memorial-content {
padding: 50upx 24upx 80upx;
}
.header {
padding: 30upx 0 40upx;
.logo {
font-size: 56upx;
margin-bottom: 20upx;
}
.tagline {
font-size: 28upx;
}
}
.memorial-quote {
margin: 50upx 0 60upx;
padding: 18upx;
}
.banner-swiper {
height: 360upx;
}
.feature-grid {
grid-template-columns: repeat(2, 1fr);
gap: 12upx;
margin: 50upx 0;
}
.feature-item {
padding: 12upx 10upx;
aspect-ratio: 1.25;
border-radius: 16upx;
.feature-icon {
font-size: 40upx;
height: 64upx;
width: 64upx;
line-height: 64upx;
margin-bottom: 8upx;
}
.feature-name {
font-size: 22upx;
}
}
.video-call-section {
margin: 40upx 0 30upx;
padding: 0 16upx;
}
.video-call-btn {
padding: 32upx;
.btn-icon {
font-size: 36upx;
}
.btn-text {
font-size: 28upx;
}
}
.cta-section {
margin: 60upx 0 30upx;
padding: 32upx 24upx;
.cta-text {
font-size: 28upx;
}
}
}
</style>