refactor(friends-photo): streamline Friends Photo page components and styles
This commit is contained in:
parent
637cfc5b95
commit
7f9168d116
|
|
@ -4,8 +4,8 @@ export default defineAppConfig({
|
|||
pages: [
|
||||
'pages/home/index', // 新的模板卡片首页
|
||||
'pages/history/index', // 历史记录页面
|
||||
'pages/result/index',
|
||||
'pages/friends-photo/index', // 好友合照页面
|
||||
'pages/result/index',
|
||||
],
|
||||
tabBar: {
|
||||
color: '#8E9BAE',
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ function App({ children }: PropsWithChildren<any>) {
|
|||
}
|
||||
|
||||
const authorize = createPlatformFactory().createAuthorize()
|
||||
const payment = createPlatformFactory().createPayment()
|
||||
// const payment = createPlatformFactory().createPayment()
|
||||
try {
|
||||
// 检查登录状态,包括OAuth 2.0回调处理
|
||||
const isLoggedIn = await authorize.checkLogin()
|
||||
|
|
@ -29,8 +29,8 @@ function App({ children }: PropsWithChildren<any>) {
|
|||
// 可以根据需要决定是否自动跳转登录
|
||||
await authorize.login()
|
||||
}
|
||||
const result = await payment.pay(`character_figurine_v1`, ``)
|
||||
console.log({ result })
|
||||
// const result = await payment.pay(`character_figurine_v1`, ``)
|
||||
// console.log({ result })
|
||||
} catch (error) {
|
||||
console.error('登录检查失败:', error)
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
|
|
@ -1,63 +0,0 @@
|
|||
/* 介绍卡片 */
|
||||
.intro-card {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
margin: 20px;
|
||||
border-radius: 20px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(102, 126, 234, 0.3);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.intro-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -50%;
|
||||
right: -50%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, transparent 70%);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.intro-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.intro-icon {
|
||||
font-size: 36px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 16px;
|
||||
padding: 12px;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.intro-text {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.intro-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.intro-subtitle {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* 响应式适配 */
|
||||
@media (max-width: 375px) {
|
||||
.intro-card {
|
||||
margin: 16px;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
import { View } from '@tarojs/components';
|
||||
import { useI18n } from '../../../../hooks/useI18n';
|
||||
import './index.css';
|
||||
|
||||
interface IntroCardProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function IntroCard({ className = '' }: IntroCardProps) {
|
||||
const { t } = useI18n();
|
||||
|
||||
return (
|
||||
<View className={`intro-card ${className}`}>
|
||||
<View className="intro-content">
|
||||
<View className="intro-icon">👫</View>
|
||||
<View className="intro-text">
|
||||
<View className="intro-title">{t('friendsPhoto.friendsPhotoGeneration')}</View>
|
||||
<View className="intro-subtitle">{t('friendsPhoto.uploadTwoPhotosDesc')}</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
@ -4,74 +4,44 @@
|
|||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 20px;
|
||||
background: white;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.08);
|
||||
backdrop-filter: blur(10px);
|
||||
padding: 20px 14px;
|
||||
padding-bottom: calc(20px + env(safe-area-inset-bottom));
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/* 提交按钮 */
|
||||
.submit-button {
|
||||
width: 100%;
|
||||
height: 56px;
|
||||
background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
|
||||
border-radius: 28px;
|
||||
height: 96px;
|
||||
background: #000;
|
||||
border-radius: 24px;
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
outline: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 6px 24px rgba(59, 130, 246, 0.4);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.submit-button::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -50%;
|
||||
left: -50%;
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
transform: rotate(45deg);
|
||||
transition: transform 0.6s ease;
|
||||
}
|
||||
|
||||
.submit-button:not(.disabled):active::before {
|
||||
transform: rotate(45deg) translateX(100%);
|
||||
}
|
||||
|
||||
.submit-button.disabled {
|
||||
background: #d1d5db;
|
||||
box-shadow: none;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.submit-button:not(.disabled):active {
|
||||
transform: translateY(2px);
|
||||
box-shadow: 0 3px 16px rgba(59, 130, 246, 0.4);
|
||||
}
|
||||
|
||||
.submit-icon {
|
||||
font-size: 18px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.submit-text {
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.submit-button[disabled] {
|
||||
background-color: #ccc;
|
||||
cursor: not-allowed;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* 加载动画 */
|
||||
.loading-spinner {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
border: 2px solid rgb(255 255 255 / 30%);
|
||||
border-top: 2px solid white;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
|
|
@ -81,22 +51,8 @@
|
|||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式适配 */
|
||||
@media (max-width: 375px) {
|
||||
.submit-section {
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 深色模式适配 */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.submit-section {
|
||||
background: #2a2a2a;
|
||||
border-color: #333;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,10 +21,7 @@ export default function SubmitButton({ disabled, loading, onSubmit, className =
|
|||
<View className="submit-text">{t('friendsPhoto.generating')}</View>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<View className="submit-icon">✨</View>
|
||||
<View className="submit-text">{t('friendsPhoto.startGenerating')}</View>
|
||||
</>
|
||||
<View className="submit-text">{t('friendsPhoto.startGenerating')}</View>
|
||||
)}
|
||||
</Button>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -1,60 +1,29 @@
|
|||
/* 上传卡片 */
|
||||
.upload-card {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.upload-card:active {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.upload-card-content {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* 上传信息 */
|
||||
.upload-info {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.upload-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1d1f22;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.upload-description {
|
||||
font-size: 14px;
|
||||
color: #8e9bae;
|
||||
}
|
||||
|
||||
/* 上传区域 */
|
||||
.upload-area {
|
||||
/* 上传内容区域 */
|
||||
.upload-content {
|
||||
width: 100%;
|
||||
height: 160px;
|
||||
border: 2px dashed #e5e7eb;
|
||||
border-radius: 12px;
|
||||
aspect-ratio: 3/4;
|
||||
background: #f6f7f9;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #fafbfc;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.upload-area:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.upload-area.has-image {
|
||||
border: 2px solid #3b82f6;
|
||||
background: transparent;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 上传占位符 */
|
||||
|
|
@ -62,18 +31,16 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.upload-icon {
|
||||
font-size: 32px;
|
||||
color: #8e9bae;
|
||||
}
|
||||
|
||||
.upload-hint {
|
||||
font-size: 14px;
|
||||
color: #8e9bae;
|
||||
font-weight: 500;
|
||||
width: 25%;
|
||||
aspect-ratio: 1;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* 上传的图片 */
|
||||
|
|
@ -81,61 +48,13 @@
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
/* 图片覆盖层 */
|
||||
.image-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
.upload-area.has-image:active .image-overlay {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.overlay-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.change-icon {
|
||||
font-size: 24px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.change-text {
|
||||
color: white;
|
||||
/* 标题 */
|
||||
.upload-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 深色模式适配 */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.upload-card {
|
||||
background: #2a2a2a;
|
||||
border: 1px solid #333;
|
||||
}
|
||||
|
||||
.upload-title {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.upload-description {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
background: #333;
|
||||
border-color: #444;
|
||||
}
|
||||
color: #666;
|
||||
text-align: center;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,25 @@
|
|||
import { View, Image } from '@tarojs/components';
|
||||
import { useI18n } from '../../../../hooks/useI18n';
|
||||
import './index.css';
|
||||
|
||||
interface UploadCardProps {
|
||||
imageUrl: string;
|
||||
title: string;
|
||||
description: string;
|
||||
onUpload: () => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function UploadCard({ imageUrl, title, description, onUpload, className = '' }: UploadCardProps) {
|
||||
const { t } = useI18n();
|
||||
|
||||
export default function UploadCard({ imageUrl, title, onUpload, className = '' }: UploadCardProps) {
|
||||
return (
|
||||
<View className={`upload-card ${className}`}>
|
||||
<View className="upload-card-content">
|
||||
<View className="upload-info">
|
||||
<View className="upload-title">{title}</View>
|
||||
<View className="upload-description">{description}</View>
|
||||
</View>
|
||||
<View className={`upload-area ${imageUrl ? 'has-image' : ''}`} onClick={onUpload}>
|
||||
{imageUrl ? (
|
||||
<>
|
||||
<Image src={imageUrl} className="upload-image" mode="aspectFill" />
|
||||
<View className="image-overlay">
|
||||
<View className="overlay-content">
|
||||
<View className="change-icon">🔄</View>
|
||||
<View className="change-text">{t('friendsPhoto.clickToChange')}</View>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
) : (
|
||||
<View className="upload-placeholder">
|
||||
<View className="upload-icon">📷</View>
|
||||
<View className="upload-hint">{t('friendsPhoto.clickToUpload')}</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<View className={`upload-card ${className}`} onClick={onUpload}>
|
||||
<View className="upload-content">
|
||||
{imageUrl ? (
|
||||
<Image src={imageUrl} className="upload-image" mode="aspectFill" />
|
||||
) : (
|
||||
<View className="upload-placeholder">
|
||||
<Image src="/assets/icons/photo.png" className="upload-icon" mode="aspectFit" />
|
||||
<View className="upload-title">{title}</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,2 @@
|
|||
export { default as IntroCard } from './IntroCard';
|
||||
export { default as UploadCard } from './UploadCard';
|
||||
export { default as SubmitButton } from './SubmitButton';
|
||||
|
|
|
|||
|
|
@ -1,2 +1 @@
|
|||
export { useUsageGuide } from './useUsageGuide';
|
||||
export { useImageUpload } from './useImageUpload';
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { useI18n } from '../../../hooks/useI18n';
|
||||
|
||||
export function useUsageGuide() {
|
||||
const [showGuide, setShowGuide] = useState(true);
|
||||
const { t } = useI18n();
|
||||
|
||||
useEffect(() => {
|
||||
if (!showGuide) return;
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
Taro.showModal({
|
||||
title: t('friendsPhoto.usageTips'),
|
||||
content: t('friendsPhoto.usageTipsContent'),
|
||||
confirmText: t('friendsPhoto.iKnow'),
|
||||
showCancel: false,
|
||||
success: () => {
|
||||
setShowGuide(false);
|
||||
},
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [showGuide, t]);
|
||||
|
||||
return {
|
||||
showGuide,
|
||||
setShowGuide,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,45 +1,20 @@
|
|||
/* 页面容器 */
|
||||
.friends-photo {
|
||||
height: 100vh;
|
||||
background: #f5f6f8;
|
||||
background: #f8f9fa;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 滚动容器 */
|
||||
.friends-photo-scroll {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
padding-bottom: 100px; /* 为固定底部按钮留空间 */
|
||||
}
|
||||
|
||||
|
||||
/* 上传区域 */
|
||||
.upload-section {
|
||||
padding: 0 20px;
|
||||
flex: 1;
|
||||
padding: 40px 14px 88px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
|
||||
/* 底部间距 */
|
||||
.bottom-spacer {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
|
||||
/* 响应式适配 */
|
||||
@media (max-width: 375px) {
|
||||
.upload-section {
|
||||
padding: 0 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 深色模式适配 */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.friends-photo {
|
||||
background: #1a1a1a;
|
||||
}
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { View, ScrollView } from '@tarojs/components';
|
||||
import { View } from '@tarojs/components';
|
||||
import { useState, useEffect } from 'react';
|
||||
import Taro, { navigateTo, useRouter } from '@tarojs/taro';
|
||||
import { useServerSdk } from '../../hooks/index';
|
||||
|
|
@ -6,10 +6,10 @@ import { useI18n } from '../../hooks/useI18n';
|
|||
import { i18nManager } from '../../i18n/manager';
|
||||
|
||||
// 导入组件
|
||||
import { IntroCard, UploadCard, SubmitButton } from './components';
|
||||
import { UploadCard, SubmitButton } from './components';
|
||||
|
||||
// 导入hooks
|
||||
import { useUsageGuide, useImageUpload } from './hooks';
|
||||
import { useImageUpload } from './hooks';
|
||||
|
||||
import './index.css';
|
||||
|
||||
|
|
@ -20,8 +20,6 @@ export default function FriendsPhoto() {
|
|||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// 使用自定义hooks
|
||||
useUsageGuide(); // 自动处理使用指南显示
|
||||
const { image1, image2, uploadSingleImage } = useImageUpload();
|
||||
|
||||
// 设置页面标题
|
||||
|
|
@ -89,29 +87,19 @@ export default function FriendsPhoto() {
|
|||
|
||||
return (
|
||||
<View className="friends-photo">
|
||||
<ScrollView className="friends-photo-scroll" scrollY enhanced showScrollbar={false} enablePassive bounces>
|
||||
{/* 顶部介绍卡片 */}
|
||||
<IntroCard />
|
||||
|
||||
{/* 上传区域 */}
|
||||
<View className="upload-section">
|
||||
<UploadCard
|
||||
imageUrl={image1}
|
||||
title={t('friendsPhoto.firstPhoto')}
|
||||
description={t('friendsPhoto.selectYourPhoto')}
|
||||
onUpload={() => uploadSingleImage(1)}
|
||||
/>
|
||||
<UploadCard
|
||||
imageUrl={image2}
|
||||
title={t('friendsPhoto.secondPhoto')}
|
||||
description={t('friendsPhoto.selectFriendPhoto')}
|
||||
onUpload={() => uploadSingleImage(2)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* 底部间距 */}
|
||||
<View className="bottom-spacer" />
|
||||
</ScrollView>
|
||||
{/* 上传区域 */}
|
||||
<View className="upload-section">
|
||||
<UploadCard
|
||||
imageUrl={image1}
|
||||
title={t('friendsPhoto.selectYourPhoto')}
|
||||
onUpload={() => uploadSingleImage(1)}
|
||||
/>
|
||||
<UploadCard
|
||||
imageUrl={image2}
|
||||
title={t('friendsPhoto.selectFriendPhoto')}
|
||||
onUpload={() => uploadSingleImage(2)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* 固定底部按钮 */}
|
||||
<SubmitButton disabled={!image1 || !image2} loading={loading} onSubmit={handleSubmit} />
|
||||
|
|
|
|||
|
|
@ -9,4 +9,4 @@ export class H5Payment extends Payment {
|
|||
}
|
||||
throw new Error(`payment error: ${response}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue