feat: 全站视觉焕新与悬浮玻璃 TabBar 迁移

This commit is contained in:
2026-08-07 23:29:19 +08:00
parent 19408e5a8c
commit 61f1217384
97 changed files with 4007 additions and 2024 deletions
-25
View File
@@ -129,31 +129,6 @@ page {
border-radius: 999rpx;
}
/* 固定底部操作栏 */
.action-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
align-items: center;
justify-content: space-between;
gap: 48rpx;
padding: 40rpx 64rpx calc(40rpx + env(safe-area-inset-bottom));
background: rgba(255, 255, 255, 0.55);
backdrop-filter: blur(32px) saturate(1.2);
-webkit-backdrop-filter: blur(32px) saturate(1.2);
border-top: 1rpx solid var(--glass-line);
z-index: 500;
}
.theme-dark .action-bar {
background: rgba(25, 25, 25, 0.55);
backdrop-filter: blur(32px) saturate(1.2);
-webkit-backdrop-filter: blur(32px) saturate(1.2);
border-top: 1rpx solid var(--glass-line);
}
/* === 标题文字 === */
.page-title {
font-size: 80rpx;
+25
View File
@@ -0,0 +1,25 @@
.bottom-action-bar {
position: fixed;
left: 36rpx;
right: 36rpx;
bottom: 36rpx;
z-index: 500;
box-sizing: border-box;
display: flex;
align-items: center;
gap: 24rpx;
padding: 24rpx;
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
border-radius: 64rpx;
background: rgba(255, 255, 255, 0.55);
backdrop-filter: blur(32px) saturate(1.2);
-webkit-backdrop-filter: blur(32px) saturate(1.2);
border: 1rpx solid rgba(255, 255, 255, 0.55);
box-shadow: 0 12rpx 40rpx rgba(46, 34, 34, 0.18), 0 4rpx 12rpx rgba(46, 34, 34, 0.08);
}
.theme-dark .bottom-action-bar {
background: rgba(25, 25, 25, 0.55);
border-color: rgba(255, 255, 255, 0.14);
box-shadow: 0 12rpx 40rpx rgba(0, 0, 0, 0.5), 0 4rpx 12rpx rgba(0, 0, 0, 0.3);
}
+17
View File
@@ -0,0 +1,17 @@
import { View } from '@tarojs/components'
import type { CSSProperties, ReactNode } from 'react'
import './index.scss'
export interface BottomActionBarProps {
children?: ReactNode
className?: string
style?: CSSProperties
}
export default function BottomActionBar({ children, className, style }: BottomActionBarProps) {
return (
<View className={`bottom-action-bar ${className || ''}`} style={style}>
{children}
</View>
)
}
+15 -11
View File
@@ -36,17 +36,6 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
setResolved(resolveTheme(mode))
}, [])
const setTheme = useCallback((t: ThemeMode) => {
saveTheme(t)
set(t)
updateResolved(t)
}, [updateResolved])
const toggleTheme = useCallback(() => {
const next = resolvedTheme === 'light' ? 'dark' : 'light'
setTheme(next)
}, [resolvedTheme, setTheme])
/**
* darkmode 只作为系统主题探测通道;选中“跟随系统”时才跟着系统切换,
* 固定浅色/深色时由 setTheme 直接决定,不被动绑定系统。
@@ -80,6 +69,21 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
}
}, [updateFromSystem])
const setTheme = useCallback((t: ThemeMode) => {
saveTheme(t)
set(t)
if (t === 'auto') {
detectSystemTheme()
} else {
updateResolved(t)
}
}, [detectSystemTheme, updateResolved])
const toggleTheme = useCallback(() => {
const next = resolvedTheme === 'light' ? 'dark' : 'light'
setTheme(next)
}, [resolvedTheme, setTheme])
useEffect(() => {
detectSystemTheme()
}, [detectSystemTheme])
+59 -11
View File
@@ -1,11 +1,36 @@
.custom-tab-bar {
.tab-bar-root {
position: fixed;
bottom: 12px;
left: 12px;
right: 12px;
border-radius: 24px;
height: calc(96px + constant(safe-area-inset-bottom));
height: calc(96px + env(safe-area-inset-bottom));
left: 0;
right: 0;
bottom: 0;
height: 160rpx;
pointer-events: none;
z-index: 999;
}
.tab-bar-gradient {
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 100%;
}
.tab-bar-root.theme-light .tab-bar-gradient {
background: linear-gradient(to top, rgba(250, 247, 242, 0.5) 0%, rgba(250, 247, 242, 0.1) 50%, rgba(250, 247, 242, 0) 86%);
}
.tab-bar-root.theme-dark .tab-bar-gradient {
background: linear-gradient(to top, rgba(25, 25, 25, 0.5) 0%, rgba(25, 25, 25, 0.1) 50%, rgba(25, 25, 25, 0) 86%);
}
.custom-tab-bar {
position: absolute;
bottom: 36rpx;
left: 36rpx;
right: 36rpx;
border-radius: 64rpx;
height: 116rpx;
box-sizing: border-box;
background: rgba(255, 255, 255, 0.55);
backdrop-filter: blur(32px) saturate(1.2);
@@ -13,9 +38,9 @@
display: flex;
justify-content: space-around;
align-items: center;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
border: 1rpx solid rgba(255, 255, 255, 0.55);
box-shadow: 0 12rpx 40rpx rgba(0, 0, 0, 0.18), 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
pointer-events: auto;
z-index: 1000;
}
@@ -24,7 +49,8 @@
background: rgba(25, 25, 25, 0.55);
backdrop-filter: blur(32px) saturate(1.2);
-webkit-backdrop-filter: blur(32px) saturate(1.2);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
border-color: rgba(255, 255, 255, 0.14);
box-shadow: 0 12rpx 40rpx rgba(0, 0, 0, 0.5), 0 4rpx 12rpx rgba(0, 0, 0, 0.3);
}
.tab-item {
@@ -35,10 +61,30 @@
padding: 0 12px;
position: relative;
flex: 1;
height: 100%;
max-width: 160px;
}
.tab-indicator {
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 6rpx;
width: 120rpx;
height: 100rpx;
border-radius: 50rpx;
background: rgba(0, 0, 0, 0.14);
box-shadow: 0 0 6rpx rgba(0, 0, 0, 0.07);
}
.custom-tab-bar.theme-dark .tab-indicator {
background: rgba(255, 255, 255, 0.14);
box-shadow: 0 0 6rpx rgba(255, 255, 255, 0.07);
}
.tab-icon-img {
position: relative;
z-index: 1;
width: 40rpx;
height: 40rpx;
margin-bottom: 2px;
@@ -52,6 +98,8 @@
}
.tab-label {
position: relative;
z-index: 1;
font-size: 20px;
color: #8a7e76;
font-weight: 700;
+45 -15
View File
@@ -1,7 +1,7 @@
import { View, Text, Image } from '@tarojs/components'
import Taro from '@tarojs/taro'
import { useEffect, useState } from 'react'
import { getTheme, resolveTheme } from '../utils/store'
import { getTheme, resolveTheme, setDetectedSystemTheme } from '../utils/store'
import { THEME_CHANGE_EVENT } from '../context/ThemeContext'
import { applyPageBackground } from '../utils/themeBackground'
import { assetUrl } from '../utils/asset'
@@ -26,6 +26,11 @@ function currentTabPath(): string {
return matchTab(path)
}
type ThemeChangeApi = {
onThemeChange?: (listener: (res: { theme?: string }) => void) => void
offThemeChange?: (listener: (res: { theme?: string }) => void) => void
}
export default function CustomTabBar() {
const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>(resolveTheme(getTheme()))
@@ -40,6 +45,27 @@ export default function CustomTabBar() {
}
}, [])
// 自定义 tabBar 不处在 React Tree 里,额外直接监听系统主题,保证“跟随系统”时也即时切换
useEffect(() => {
const handler = (res: { theme?: string }) => {
if (res && (res.theme === 'dark' || res.theme === 'light')) {
setDetectedSystemTheme(res.theme)
if (getTheme() === 'auto') {
setResolvedTheme(res.theme)
}
}
}
const themeApi = Taro as typeof Taro & ThemeChangeApi
if (themeApi.onThemeChange) {
themeApi.onThemeChange(handler)
}
return () => {
if (themeApi.offThemeChange) {
themeApi.offThemeChange(handler)
}
}
}, [])
// 其它入口(如页面内部调用 switchTab)也会回到 tabBar,收到事件后重新同步选中态
useEffect(() => {
const handler = (path?: string) => {
@@ -66,20 +92,24 @@ export default function CustomTabBar() {
}
return (
<View className={`custom-tab-bar theme-${resolvedTheme}`}>
{TABS.map((tab) => {
const isActive = tab.pagePath === activeTab
return (
<View
key={tab.pagePath}
className={`tab-item ${isActive ? 'active' : ''}`}
onTap={() => switchTab(tab.pagePath)}
>
<Image className={`tab-icon-img ${isActive ? 'active' : ''}`} src={isActive ? tab.iconActive : tab.icon} mode='aspectFit' />
<Text className='tab-label'>{tab.label}</Text>
</View>
)
})}
<View className={`tab-bar-root theme-${resolvedTheme}`}>
<View className='tab-bar-gradient' />
<View className={`custom-tab-bar theme-${resolvedTheme}`}>
{TABS.map((tab) => {
const isActive = tab.pagePath === activeTab
return (
<View
key={tab.pagePath}
className={`tab-item ${isActive ? 'active' : ''}`}
onTap={() => switchTab(tab.pagePath)}
>
{isActive && <View className='tab-indicator' />}
<Image className={`tab-icon-img ${isActive ? 'active' : ''}`} src={isActive ? tab.iconActive : tab.icon} mode='aspectFit' />
<Text className='tab-label'>{tab.label}</Text>
</View>
)
})}
</View>
</View>
)
}
+188 -77
View File
@@ -1,135 +1,268 @@
/* ============================================================
Address Page — 收货地址
============================================================ */
.address-page {
padding: 0 24px 24px;
padding: 0 32rpx;
padding-bottom: calc(48rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
}
/* --- Page Header --- */
.page-header {
margin-bottom: 24rpx;
padding: 0;
}
.page-header-inner {
display: flex;
align-items: center;
gap: 16rpx;
min-height: 88rpx;
}
.back-btn {
font-size: 40px;
padding: 10px;
display: flex;
align-items: center;
justify-content: center;
width: 88rpx;
height: 88rpx;
flex: 0 0 auto;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
}
.back-btn:active {
transform: scale(0.96);
}
.back-arrow {
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
}
.nav-title {
flex: 1;
text-align: center;
font-size: 34rpx;
font-weight: 700;
color: var(--text-primary);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.nav-placeholder {
width: 88rpx;
flex: 0 0 auto;
}
/* --- 地址列表 --- */
.address-list {
margin-top: 20px;
display: flex;
flex-direction: column;
gap: 24rpx;
}
.address-card {
padding: 24px;
margin-bottom: 20px;
padding: 32rpx;
}
.address-header {
margin-bottom: 20px;
margin-bottom: 8rpx;
}
.address-user {
display: flex;
flex-wrap: wrap;
align-items: center;
margin-bottom: 12px;
gap: 16rpx;
margin-bottom: 12rpx;
}
.address-name {
font-size: 32px;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
margin-right: 16px;
}
.address-phone {
font-size: 28px;
font-size: 24rpx;
color: var(--text-secondary);
}
.default-tag {
margin-left: 12px;
display: inline-flex;
align-items: center;
height: 40rpx;
padding: 0 16rpx;
border-radius: 999rpx;
background: var(--accent-primary);
color: #fff;
font-size: 20px;
padding: 2px 10px;
border-radius: 8px;
color: var(--bg-page);
font-size: 20rpx;
font-weight: 600;
}
.address-full {
font-size: 28px;
display: block;
font-size: 26rpx;
color: var(--text-secondary);
line-height: 1.5;
line-height: 1.6;
}
.address-actions {
display: flex;
justify-content: flex-end;
gap: 24px;
padding-top: 16px;
gap: 16rpx;
margin-top: 20rpx;
padding-top: 24rpx;
border-top: 1rpx solid var(--border);
}
.address-act {
font-size: 26px;
display: flex;
align-items: center;
min-height: 56rpx;
padding: 0 24rpx;
border-radius: 999rpx;
background: var(--accent-secondary-soft);
color: var(--accent-secondary);
font-size: 24rpx;
font-weight: 500;
}
.address-act.delete {
background: var(--danger-soft);
color: var(--danger);
}
/* 表单弹窗 */
/* --- 空状态 --- */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
padding: 96rpx 40rpx;
text-align: center;
}
.empty-icon-img {
width: 88rpx;
height: 88rpx;
margin-bottom: 24rpx;
}
.empty-text {
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 12rpx;
}
.empty-sub {
font-size: 26rpx;
color: var(--text-secondary);
}
/* --- 底部操作栏 --- */
.bottom-action-bar .btn-primary {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
min-height: 96rpx;
padding: 0;
font-size: 30rpx;
font-weight: 600;
}
/* --- 新增 / 编辑弹窗 --- */
.modal-overlay {
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 48rpx;
}
.address-form {
width: 100%;
max-width: 600px;
padding: 40px;
max-width: 640rpx;
padding: 40rpx;
box-sizing: border-box;
}
.modal-title {
display: block;
text-align: center;
margin-bottom: 32rpx;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
}
.form-input {
width: 100%;
height: 80px;
background: var(--bg-input);
border: 1rpx solid var(--border);
border-radius: 16px;
padding: 0 24px;
font-size: 28px;
color: var(--text-primary);
margin-bottom: 20px;
height: 88rpx;
margin-bottom: 20rpx;
padding: 0 24rpx;
box-sizing: border-box;
border: 1rpx solid var(--border);
border-radius: 16rpx;
background: var(--bg-input);
font-size: 28rpx;
color: var(--text-primary);
}
.form-input:focus {
border-color: var(--accent-primary);
background: var(--bg-card);
}
.form-picker {
width: 100%;
height: 80px;
background: var(--bg-input);
border: 1rpx solid var(--border);
border-radius: 16px;
display: flex;
align-items: center;
padding: 0 24px;
margin-bottom: 20px;
width: 100%;
height: 88rpx;
margin-bottom: 20rpx;
padding: 0 24rpx;
box-sizing: border-box;
border: 1rpx solid var(--border);
border-radius: 16rpx;
background: var(--bg-input);
}
.form-picker-val {
font-size: 28px;
font-size: 28rpx;
color: var(--text-primary);
}
.form-picker-ph {
font-size: 28px;
color: var(--text-secondary);
font-size: 28rpx;
color: var(--text-muted);
}
.form-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32px;
gap: 24rpx;
margin-bottom: 32rpx;
}
.form-label {
font-size: 28px;
font-size: 28rpx;
color: var(--text-primary);
}
.checkbox {
width: 44px;
height: 44px;
border: 1rpx solid var(--border);
border-radius: 10px;
width: 44rpx;
height: 44rpx;
border: 2rpx solid var(--border-strong);
border-radius: 12rpx;
background: var(--bg-card);
transition: background 160ms ease, border-color 160ms ease;
}
.checkbox.checked {
@@ -139,39 +272,17 @@
.form-actions {
display: flex;
gap: 20px;
gap: 20rpx;
}
.form-actions .btn-secondary,
.form-actions .btn-primary {
flex: 1;
padding: 20px 0;
text-align: center;
}
/* 空状态(主题适配) */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
padding: 120px 40px;
text-align: center;
}
.empty-icon-img {
width: 48px;
height: 48px;
margin-bottom: 24px;
}
.empty-text {
font-size: 32px;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 12px;
}
.empty-sub {
font-size: 26px;
color: var(--text-secondary);
justify-content: center;
flex: 1;
min-height: 96rpx;
padding: 0;
font-size: 28rpx;
font-weight: 600;
}
+10 -7
View File
@@ -8,6 +8,7 @@ import { useThemeContext } from '../../context/ThemeContext'
import { useSafeArea } from '../../hooks/useSafeArea'
import { useStatusBar } from '../../hooks/useStatusBar'
import ThemedPageMeta from '../../components/ThemedPageMeta'
import BottomActionBar from '../../components/BottomActionBar'
import { assetUrl } from '../../utils/asset'
export default function AddressPage() {
@@ -98,11 +99,13 @@ export default function AddressPage() {
<ThemedPageMeta />
<View className='address-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='flex-between' style={{ width: '100%' }}>
<Text className='back-btn' onTap={() => Taro.navigateBack()}></Text>
<Text className='page-title'></Text>
<View style={{ width: '60px' }} />
<View className='page-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header-inner'>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='nav-title'></Text>
<View className='nav-placeholder' />
</View>
</View>
@@ -142,11 +145,11 @@ export default function AddressPage() {
<View className='safe-bottom-placeholder' />
{/* 底部添加按钮 */}
<View className='action-bar'>
<BottomActionBar>
<View className='btn-primary' onTap={openAdd}>
<Text></Text>
</View>
</View>
</BottomActionBar>
{/* 新增/编辑弹窗 */}
{showForm && (
+35 -18
View File
@@ -1,35 +1,52 @@
.agreement-page {
padding: 0 32px 32px;
}
/* ============================================================
Agreement Page — 定制协议
============================================================ */
.agreement-title {
font-size: 40px;
font-weight: 800;
color: var(--text-primary);
display: block;
margin-bottom: 32px;
.agreement-page {
padding: 0 32rpx calc(24rpx + env(safe-area-inset-bottom));
min-height: 100vh;
box-sizing: border-box;
}
.agreement-content {
padding: 40px 0;
padding: 32rpx 0 48rpx;
line-height: 1.8;
}
.agreement-title {
display: block;
font-size: 44rpx;
font-weight: 700;
line-height: 1.2;
color: var(--text-primary);
margin-bottom: 32rpx;
letter-spacing: 0;
}
.agreement-section {
margin-bottom: 32px;
display: block;
margin-bottom: 24rpx;
padding: 32rpx;
}
.agreement-section:last-child {
margin-bottom: 0;
}
.agreement-h3 {
font-size: 32px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 16px;
font-size: 32rpx;
font-weight: 700;
line-height: 1.3;
color: var(--text-primary);
margin-bottom: 16rpx;
letter-spacing: 0;
}
.agreement-p {
font-size: 28px;
color: var(--text-secondary);
line-height: 1.8;
display: block;
font-size: 28rpx;
line-height: 1.8;
color: var(--text-secondary);
white-space: pre-line;
}
+1 -1
View File
@@ -40,7 +40,7 @@ export default function AgreementPage() {
<View className='agreement-content' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<Text className='agreement-title'></Text>
{SECTIONS.map((sec, idx) => (
<View key={idx} className='agreement-section'>
<View key={idx} className='agreement-section surface-card'>
<Text className='agreement-h3'>{sec.title}</Text>
<Text className='agreement-p'>{sec.content}</Text>
</View>
+167 -65
View File
@@ -1,27 +1,80 @@
/* ============================================================
Checkout Page — 确认下单
============================================================ */
.checkout-page {
padding: 0 24px 24px;
padding: 0 32rpx;
padding-bottom: calc(48rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
}
/* --- Page Header --- */
.page-header {
margin-bottom: 24rpx;
padding: 0;
}
.page-header-inner {
display: flex;
align-items: center;
gap: 16rpx;
min-height: 88rpx;
}
.back-btn {
font-size: 40px;
padding: 10px;
display: flex;
align-items: center;
justify-content: center;
width: 88rpx;
height: 88rpx;
flex: 0 0 auto;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
}
/* 画布展示区 */
.back-btn:active {
transform: scale(0.96);
}
.back-arrow {
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
}
.nav-title {
flex: 1;
text-align: center;
font-size: 34rpx;
font-weight: 700;
color: var(--text-primary);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.nav-placeholder {
width: 88rpx;
flex: 0 0 auto;
}
/* --- 设计预览 --- */
.checkout-canvas {
display: flex;
align-items: center;
justify-content: center;
padding: 40px;
margin-bottom: 24rpx;
padding: 32rpx;
}
.canvas-area {
position: relative;
overflow: hidden;
background: rgba(0,0,0,0.03);
border: 1rpx solid var(--border-strong);
max-width: 100%;
box-sizing: border-box;
background: var(--bg-input);
border: 1rpx solid var(--border-strong);
}
.checkout-image {
@@ -32,125 +85,153 @@
max-height: 100%;
}
/* 商品信息 */
.checkout-info {
padding: 24px;
/* --- 商品信息 --- */
.checkout-info,
.checkout-address-card {
margin-bottom: 24rpx;
padding: 32rpx;
}
.card-title {
display: block;
margin-bottom: 24rpx;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
}
.info-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 0;
gap: 24rpx;
padding: 24rpx 0;
border-bottom: 1rpx solid var(--border);
}
.info-row:last-child {
border-bottom: none;
padding-bottom: 0;
}
.info-label {
font-size: 28px;
flex: 0 0 auto;
font-size: 28rpx;
color: var(--text-secondary);
}
.info-value {
font-size: 28px;
color: var(--text-primary);
flex: 1;
text-align: right;
font-size: 28rpx;
font-weight: 500;
color: var(--text-primary);
word-break: break-all;
}
.total-row {
padding-top: 24px;
margin-top: 8px;
padding-top: 24rpx;
margin-top: 8rpx;
}
.info-total {
font-size: 40px;
font-size: 40rpx;
font-weight: 800;
color: var(--accent-primary);
font-variant-numeric: tabular-nums;
}
/* 地址卡片 */
.checkout-address-card {
padding: 24px;
}
/* --- 收货地址 --- */
.checkout-address-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
gap: 24rpx;
margin-bottom: 16rpx;
}
.checkout-address-header .card-title {
margin-bottom: 0;
}
.address-change {
padding: 6px 16px;
border-radius: 8px;
display: flex;
align-items: center;
height: 56rpx;
padding: 0 24rpx;
border-radius: 999rpx;
background: var(--accent-secondary-soft);
}
.change-text {
font-size: 24px;
font-size: 24rpx;
font-weight: 500;
color: var(--accent-secondary);
}
.checkout-address-body {
padding-top: 8px;
padding-top: 8rpx;
}
.addr-row {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 8px;
gap: 16rpx;
margin-bottom: 8rpx;
}
.addr-name {
font-size: 28px;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
}
.addr-phone {
font-size: 26px;
font-size: 24rpx;
color: var(--text-secondary);
}
.addr-detail {
font-size: 26px;
font-size: 26rpx;
color: var(--text-secondary);
line-height: 1.5;
line-height: 1.6;
}
.checkout-address-empty {
padding: 32px 0;
padding: 32rpx 0;
text-align: center;
}
.empty-text {
font-size: 26px;
font-size: 28rpx;
color: var(--text-secondary);
}
/* 底部弹窗 — 地址选择(样式复用 app.scss 全局定义,移除非必要覆写) */
/* --- 地址选择弹层 --- */
.addr-picker-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
margin-bottom: 24rpx;
}
.addr-picker-title {
font-size: 32px;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
}
.addr-picker-close {
font-size: 28px;
display: flex;
align-items: center;
justify-content: center;
width: 64rpx;
height: 64rpx;
border-radius: 50%;
background: var(--bg-muted);
color: var(--text-secondary);
padding: 8px;
font-size: 28rpx;
}
.addr-picker-list {
@@ -159,69 +240,90 @@
}
.addr-picker-item {
padding: 20px 16px;
border-bottom: 1rpx solid var(--border);
padding: 24rpx;
border: 1rpx solid transparent;
border-radius: 16rpx;
transition: background 160ms ease, border-color 160ms ease;
}
.addr-picker-item + .addr-picker-item {
margin-top: 16rpx;
}
.addr-picker-item.active {
background: var(--accent-secondary-soft);
border-radius: 12px;
background: var(--accent-primary-soft);
border-color: var(--accent-primary);
}
.addr-picker-row {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 8px;
gap: 16rpx;
margin-bottom: 8rpx;
}
.addr-picker-name {
font-size: 28px;
font-size: 30rpx;
font-weight: 700;
color: var(--text-primary);
}
.addr-picker-phone {
font-size: 26px;
font-size: 24rpx;
color: var(--text-secondary);
}
.addr-picker-default {
font-size: 22px;
display: inline-flex;
align-items: center;
height: 40rpx;
padding: 0 16rpx;
border-radius: 999rpx;
font-size: 20rpx;
font-weight: 600;
color: var(--accent-primary);
border: 1px solid var(--accent-primary);
padding: 2px 8px;
border-radius: 6px;
background: var(--accent-primary-soft);
}
.addr-picker-detail {
font-size: 26px;
font-size: 26rpx;
color: var(--text-secondary);
line-height: 1.6;
}
.addr-picker-empty {
padding: 40px;
padding: 48rpx 32rpx;
text-align: center;
font-size: 28rpx;
color: var(--text-secondary);
font-size: 28px;
}
.addr-picker-add {
margin-top: 16px;
padding: 20px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
height: 96rpx;
margin-top: 24rpx;
border: 1rpx solid var(--border-strong);
border-radius: 12px;
border-radius: 999rpx;
background: var(--bg-card);
}
.addr-picker-add-text {
font-size: 28px;
font-size: 28rpx;
font-weight: 600;
color: var(--accent-secondary);
}
/* 底部操作 — 毛玻璃规则由全局 .action-bar 提供 */
.action-bar .btn-secondary,
.action-bar .btn-primary {
/* --- 底部操作栏 --- */
.bottom-action-bar .btn-secondary,
.bottom-action-bar .btn-primary {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
text-align: center;
min-height: 96rpx;
padding: 0;
font-size: 30rpx;
font-weight: 600;
}
+26 -16
View File
@@ -7,6 +7,7 @@ import { useThemeContext } from '../../context/ThemeContext'
import { useSafeArea } from '../../hooks/useSafeArea'
import { useStatusBar } from '../../hooks/useStatusBar'
import ThemedPageMeta from '../../components/ThemedPageMeta'
import BottomActionBar from '../../components/BottomActionBar'
export default function CheckoutPage() {
const { theme, resolvedTheme } = useThemeContext()
@@ -67,8 +68,14 @@ export default function CheckoutPage() {
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='checkout-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<Text className='page-title'></Text>
<View className='page-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header-inner'>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='nav-title'></Text>
<View className='nav-placeholder' />
</View>
</View>
</View>
</View>
@@ -85,20 +92,22 @@ export default function CheckoutPage() {
}
return (
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='checkout-page'>
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='checkout-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='flex-between' style={{ width: '100%' }}>
<Text className='back-btn' onTap={() => Taro.navigateBack()}></Text>
<Text className='page-title'></Text>
<View style={{ width: '60px' }} />
<View className='page-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header-inner'>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='nav-title'></Text>
<View className='nav-placeholder' />
</View>
</View>
{/* 效果展示区 */}
<View className='checkout-canvas surface-card mt-20'>
<View className='checkout-canvas surface-card'>
<View className='canvas-area' style={maskStyle}>
{hasStickers ? (
design.designData.stickers.map((s: any) => (
@@ -128,7 +137,8 @@ export default function CheckoutPage() {
</View>
{/* 商品信息 */}
<View className='checkout-info surface-card mt-20'>
<View className='checkout-info surface-card'>
<Text className='card-title'></Text>
<View className='info-row'>
<Text className='info-label'></Text>
<Text className='info-value'>{design.productName}</Text>
@@ -148,9 +158,9 @@ export default function CheckoutPage() {
</View>
{/* 收货地址 */}
<View className='checkout-address-card surface-card mt-20'>
<View className='checkout-address-card surface-card'>
<View className='checkout-address-header'>
<Text className='info-label'></Text>
<Text className='card-title'></Text>
<View className='address-change' onTap={() => setShowAddrPicker(true)}>
<Text className='change-text'></Text>
</View>
@@ -173,14 +183,14 @@ export default function CheckoutPage() {
</View>
{/* 底部操作 */}
<View className='action-bar'>
<BottomActionBar>
<View className='btn-secondary' onTap={() => Taro.navigateBack()}>
<Text></Text>
</View>
<View className='btn-primary' onTap={handleConfirm}>
<Text></Text>
</View>
</View>
</BottomActionBar>
<View className='safe-bottom-placeholder' />
+131 -71
View File
@@ -1,76 +1,95 @@
.design-page {
padding: 0 24px 24px;
padding: 0 32rpx 24rpx;
min-height: 100vh;
}
.manage-btn {
font-size: 28px;
color: var(--accent-secondary);
font-weight: 500;
.page-header.design-header {
display: flex;
align-items: center;
min-height: 88rpx;
padding-bottom: 16rpx;
}
/* 状态 Tab */
.header-spacer {
width: 88rpx;
height: 88rpx;
flex-shrink: 0;
}
.header-title {
flex: 1;
text-align: center;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
}
.header-manage {
width: 88rpx;
text-align: center;
font-size: 28rpx;
font-weight: 500;
color: var(--accent-secondary);
}
/* 状态筛选 chip-row */
.status-tabs {
margin: 20px 0;
background: var(--bg-card);
border: 1rpx solid var(--border);
border-radius: 16px;
padding: 8px 0;
margin: 8rpx 0 24rpx;
}
.tabs-scroll {
white-space: nowrap;
}
.tab-item {
display: inline-block;
padding: 20px 32px;
position: relative;
}
.tab-label {
font-size: 28px;
.chip {
display: inline-flex;
align-items: center;
justify-content: center;
height: 64rpx;
padding: 0 32rpx;
margin-right: 16rpx;
border-radius: 999rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
color: var(--text-secondary);
font-size: 26rpx;
font-weight: 500;
}
.tab-item.active .tab-label {
color: var(--accent-primary);
font-weight: 700;
.chip.active {
background: var(--accent-primary);
border-color: var(--accent-primary);
color: var(--bg-page);
font-weight: 600;
}
.tab-underline {
position: absolute;
bottom: 8px;
left: 50%;
transform: translateX(-50%);
width: 40px;
height: 4px;
background: var(--accent-primary);
border-radius: 2px;
.chip .tab-label {
color: inherit;
}
/* 批量管理工具栏 */
.batch-bar {
padding: 20px 24px;
margin-bottom: 16px;
display: flex;
align-items: center;
margin-bottom: 24rpx;
padding: 24rpx;
background: var(--bg-card);
border-radius: 24rpx;
box-shadow: var(--shadow-card);
}
.batch-select-all {
display: flex;
align-items: center;
gap: 16px;
}
.batch-checkbox {
width: 36px;
height: 36px;
width: 40rpx;
height: 40rpx;
border-radius: 50%;
border: 2rpx solid var(--border-strong);
flex-shrink: 0;
transition: all 0.2s;
transition: background 160ms ease, border-color 160ms ease;
}
.batch-checkbox.checked {
@@ -79,14 +98,15 @@
}
.batch-text {
font-size: 26px;
margin-left: 16rpx;
font-size: 26rpx;
color: var(--text-primary);
}
.batch-delete {
font-size: 26px;
font-size: 26rpx;
color: var(--text-secondary);
padding: 10px 24px;
padding: 12rpx 24rpx;
}
.batch-delete.active {
@@ -94,15 +114,19 @@
font-weight: 600;
}
/* 设计卡片列表 */
/* 设计清单 detail-card */
.design-list {
padding-bottom: 24px;
padding-bottom: 24rpx;
}
.design-card {
margin-bottom: 20px;
padding: 28px;
transition: all 0.2s ease;
margin-bottom: 24rpx;
padding: 24rpx;
background: var(--bg-card);
border: 1rpx solid transparent;
border-radius: 24rpx;
box-shadow: var(--shadow-card);
transition: background 160ms ease, border-color 160ms ease;
}
.design-card.selected {
@@ -112,48 +136,65 @@
.design-body {
display: flex;
align-items: flex-start;
gap: 20px;
margin-bottom: 20px;
}
.design-icon {
font-size: 56px;
flex-shrink: 0;
align-items: center;
gap: 20rpx;
}
.design-icon-img {
width: 56px;
height: 56px;
width: 48rpx;
height: 48rpx;
flex-shrink: 0;
border-radius: 12rpx;
background: var(--bg-input);
}
.design-info {
flex: 1;
min-width: 0;
}
.design-title-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
gap: 16rpx;
margin-bottom: 8rpx;
}
.design-name {
font-size: 32px;
flex: 1;
min-width: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 30rpx;
font-weight: 700;
color: var(--text-primary);
}
.design-card .badge {
display: inline-flex;
align-items: center;
justify-content: center;
height: 40rpx;
padding: 0 16rpx;
border-radius: 999rpx;
font-size: 22rpx;
font-weight: 600;
line-height: 1;
flex-shrink: 0;
}
.design-meta {
font-size: 24px;
color: var(--text-secondary);
display: block;
margin-bottom: 8px;
font-size: 24rpx;
color: var(--text-secondary);
margin-bottom: 4rpx;
}
.design-total {
font-size: 26px;
display: block;
font-size: 24rpx;
font-weight: 600;
color: var(--accent-primary);
}
@@ -161,11 +202,18 @@
.design-actions {
display: flex;
justify-content: flex-end;
margin-top: 24rpx;
}
.design-btn {
padding: 16px 40px;
font-size: 26px;
display: flex;
align-items: center;
justify-content: center;
height: 64rpx;
padding: 0 32rpx;
font-size: 26rpx;
font-weight: 600;
border-radius: 999rpx;
}
/* 空状态 */
@@ -173,25 +221,37 @@
display: flex;
flex-direction: column;
align-items: center;
padding: 100px 40px;
padding: 100rpx 40rpx;
text-align: center;
}
.empty-icon-img {
width: 56px;
height: 56px;
margin-bottom: 24px;
width: 88rpx;
height: 88rpx;
margin-bottom: 24rpx;
}
.empty-text {
font-size: 32px;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 12px;
margin-bottom: 12rpx;
}
.empty-sub {
font-size: 26px;
font-size: 28rpx;
color: var(--text-secondary);
margin-bottom: 32px;
margin-bottom: 32rpx;
}
.empty-state .btn-primary {
display: flex;
align-items: center;
justify-content: center;
min-width: 320rpx;
height: 88rpx;
padding: 0 48rpx;
border-radius: 999rpx;
font-size: 30rpx;
font-weight: 600;
}
+11 -13
View File
@@ -19,6 +19,8 @@ const STATUS_TABS = [
{ code: 'ordered', label: '已下单' }
]
const VISIBLE_STATUS_TABS = STATUS_TABS.filter(tab => tab.code !== 'undesigned')
const STATUS_STYLE: Record<string, { label: string; cls: string }> = {
undesigned: { label: '未设计', cls: 'badge-pink' },
designing: { label: '设计中', cls: 'badge-blue' },
@@ -120,27 +122,24 @@ export default function DesignListPage() {
<ThemedPageMeta />
<LoginGuard>
<View className='design-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='flex-between' style={{ width: '100%' }}>
<Text className='back-btn' onTap={() => Taro.navigateBack()}></Text>
<Text className='page-title'></Text>
<Text className='manage-btn' onTap={handleManage}>
{managing ? '完成' : '管理'}
</Text>
<View className='page-header design-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='header-spacer' />
<Text className='header-title'></Text>
<View className='header-manage' onTap={handleManage}>
<Text>{managing ? '完成' : '管理'}</Text>
</View>
</View>
{/* 状态筛选 */}
<View className='status-tabs'>
<ScrollView className='tabs-scroll' scrollX>
{STATUS_TABS.map(tab => (
{VISIBLE_STATUS_TABS.map(tab => (
<View
key={tab.code}
className={`tab-item ${activeTab === tab.code ? 'active' : ''}`}
className={`chip ${activeTab === tab.code ? 'active' : ''}`}
onTap={() => setActiveTab(tab.code)}
>
<Text className='tab-label'>{tab.label}</Text>
{activeTab === tab.code && <View className='tab-underline' />}
</View>
))}
</ScrollView>
@@ -148,7 +147,7 @@ export default function DesignListPage() {
{/* 批量管理工具栏 */}
{managing && (
<View className='batch-bar surface-card'>
<View className='batch-bar'>
<View className='flex-between' style={{ width: '100%' }}>
<View className='batch-select-all' onTap={toggleSelectAll}>
<View className={`batch-checkbox ${selected.size === filtered.length && filtered.length > 0 ? 'checked' : ''}`} />
@@ -173,7 +172,7 @@ export default function DesignListPage() {
return (
<View
key={item.id}
className={`design-card surface-card ${isSelected ? 'selected' : ''}`}
className={`design-card ${isSelected ? 'selected' : ''}`}
onTap={() => managing ? toggleSelect(item.id) : undefined}
>
<View className='design-body'>
@@ -220,7 +219,6 @@ export default function DesignListPage() {
)}
</ScrollView>
<View style={{ height: '40px' }} />
</View>
</LoginGuard>
</View>
+270 -145
View File
@@ -1,24 +1,91 @@
.diy-page {
padding: 0 24px 24px;
padding: 0 32rpx calc(48rpx + env(safe-area-inset-bottom));
min-height: 100vh;
box-sizing: border-box;
}
/* 顶部标题区 */
.diy-page .page-header {
display: flex;
align-items: center;
margin: 0 0 24rpx;
padding-top: 0;
padding-bottom: 16rpx;
background: transparent;
border: none;
box-shadow: none;
}
.diy-page .page-header.surface-card {
background: transparent;
border: none;
box-shadow: none;
}
.diy-page .page-header .flex-between {
min-height: 88rpx;
}
.back-btn {
display: flex;
align-items: center;
justify-content: center;
width: 80rpx;
height: 80rpx;
flex-shrink: 0;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
}
.back-btn:active {
transform: scale(0.96);
}
.diy-page .page-title {
flex: 1;
min-width: 0;
padding: 0 16rpx;
text-align: center;
font-size: 34rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
line-height: 1.2;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.header-spacer {
width: 80rpx;
height: 80rpx;
flex-shrink: 0;
}
/* 画布区域 */
.canvas-wrapper {
padding: 40px;
padding: 24rpx;
display: flex;
justify-content: center;
align-items: center;
border-radius: 24rpx;
}
.canvas-area {
position: relative;
background: var(--bg-input);
overflow: hidden;
border-radius: 16px;
min-width: 200px;
min-height: 200px;
border-radius: 24rpx;
min-width: 300rpx;
min-height: 400rpx;
max-width: 100%;
box-sizing: border-box;
box-shadow: inset 0 0 0 1rpx var(--border-strong);
}
.mask-border {
@@ -37,46 +104,59 @@
max-width: 100%;
max-height: 100%;
z-index: 5;
border: 2px solid transparent;
border: 2rpx solid transparent;
border-radius: 8rpx;
}
.canvas-image.active {
border-color: var(--accent-primary);
box-shadow: 0 0 0 8rpx var(--accent-primary-soft);
}
.canvas-image.overlap {
border-color: var(--danger);
box-shadow: 0 0 12px var(--danger-soft);
box-shadow: 0 0 0 8rpx var(--danger-soft);
}
/* 贴纸面板 */
.sticker-panel {
padding: 28px;
padding: 24rpx;
}
.sticker-panel .section-title {
display: block;
margin-bottom: 20rpx;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
}
.sticker-list {
display: flex;
flex-wrap: wrap;
gap: 16px;
gap: 16rpx;
}
.sticker-thumb {
position: relative;
width: 120px;
height: 120px;
width: 164rpx;
height: 164rpx;
border: 1rpx solid var(--border);
border-radius: 12px;
border-radius: 20rpx;
overflow: hidden;
background: var(--bg-input);
box-shadow: var(--shadow-card);
}
.sticker-thumb.active {
border-color: var(--accent-primary);
border-width: 2rpx;
box-shadow: 0 0 0 6rpx var(--accent-primary-soft);
}
.sticker-thumb.overlap {
border-color: var(--danger);
box-shadow: 0 0 0 6rpx var(--danger-soft);
}
.sticker-thumb-img {
@@ -86,52 +166,59 @@
.sticker-del {
position: absolute;
top: 4px;
right: 4px;
width: 36px;
height: 36px;
top: 8rpx;
right: 8rpx;
width: 44rpx;
height: 44rpx;
background: var(--danger);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
box-shadow: var(--shadow-card);
}
.del-icon {
color: #fff;
font-size: 24px;
font-size: 28rpx;
font-weight: 700;
line-height: 1;
}
.sticker-add-btn {
width: 120px;
height: 120px;
border: 1rpx solid var(--border);
border-radius: 12px;
width: 164rpx;
height: 164rpx;
border: 1rpx solid var(--border-strong);
border-radius: 20rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: var(--bg-input);
background: var(--bg-muted);
}
.sticker-add-btn:active {
transform: scale(0.97);
}
.add-icon {
font-size: 48px;
font-size: 44rpx;
color: var(--accent-primary);
line-height: 1;
font-weight: 600;
}
.add-label {
font-size: 22px;
font-size: 22rpx;
color: var(--text-secondary);
margin-top: 8px;
margin-top: 8rpx;
}
.overlap-hint {
display: block;
margin-top: 16px;
font-size: 26px;
margin-top: 16rpx;
font-size: 24rpx;
color: var(--danger);
font-weight: 600;
text-align: center;
@@ -139,153 +226,78 @@
/* 工具栏 */
.toolbar {
padding: 28px 32px;
padding: 24rpx;
}
.tool-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
gap: 16rpx;
padding: 8rpx 0;
}
.tool-row:last-child {
margin-bottom: 0;
.tool-row + .tool-row {
border-top: 1rpx solid var(--border);
margin-top: 8rpx;
padding-top: 16rpx;
}
.tool-label {
font-size: 28px;
font-size: 26rpx;
font-weight: 600;
color: var(--text-primary);
}
.tool-btn {
width: 56px;
height: 56px;
width: 64rpx;
height: 64rpx;
background: var(--bg-input);
border: 1rpx solid var(--border-strong);
border-radius: 50%;
border: 1rpx solid var(--border);
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
font-size: 32rpx;
color: var(--text-primary);
font-weight: 700;
font-weight: 600;
}
.tool-btn:active {
transform: scale(0.96);
background: var(--bg-muted);
}
.tool-value {
font-size: 28px;
font-size: 26rpx;
font-weight: 600;
color: var(--accent-primary);
min-width: 80px;
min-width: 88rpx;
text-align: center;
font-variant-numeric: tabular-nums;
}
.tool-hint {
font-size: 24px;
font-size: 24rpx;
color: var(--text-secondary);
}
/* 预览弹窗 */
.preview-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 40px;
}
.preview-card {
background: var(--bg-card);
width: 100%;
max-height: 80vh;
overflow-y: auto;
padding: 40px;
}
.preview-title {
font-size: 36px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 24px;
text-align: center;
}
.preview-canvas {
background: var(--bg-input);
border-radius: 16px;
overflow: hidden;
margin: 0 auto 24px;
border: 1rpx solid var(--border-strong);
position: relative;
min-width: 200px;
min-height: 200px;
max-width: 100%;
box-sizing: border-box;
}
.preview-image {
position: absolute;
max-width: 100%;
max-height: 100%;
z-index: 5;
}
.preview-image.overlap {
border: 2px solid var(--danger);
}
.product-info {
text-align: center;
margin-bottom: 32px;
}
.product-name {
font-size: 30px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
}
.product-size {
font-size: 24px;
color: var(--text-secondary);
}
.preview-actions {
display: flex;
gap: 20px;
}
.preview-actions .btn-secondary,
.preview-actions .btn-primary {
flex: 1;
text-align: center;
}
.preview-actions .btn-primary.disabled {
opacity: 0.5;
pointer-events: none;
}
/* 常驻编辑按钮 */
.edit-btn-bar {
display: flex;
justify-content: flex-end;
margin-top: 24rpx;
}
.edit-btn {
padding: 16px 48px;
border-radius: 50px;
font-size: 28px;
display: flex;
align-items: center;
justify-content: center;
min-width: 176rpx;
height: 88rpx;
padding: 0 40rpx;
border-radius: 999rpx;
font-size: 28rpx;
font-weight: 600;
text-align: center;
background: var(--bg-input);
@@ -301,19 +313,132 @@
}
.edit-btn.disabled {
opacity: 0.45;
pointer-events: none;
}
/* 底部操作栏 — 毛玻璃由 BottomActionBar 提供 */
.bottom-action-bar .btn-primary,
.bottom-action-bar .btn-secondary {
flex: 1;
text-align: center;
padding: 28rpx 0;
font-size: 28rpx;
font-weight: 600;
line-height: 1.2;
}
/* 预览弹层 */
.preview-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.45);
display: flex;
align-items: flex-end;
justify-content: center;
z-index: 1000;
}
.preview-card {
width: 100%;
max-height: 88vh;
overflow-y: auto;
padding: 40rpx 32rpx calc(32rpx + env(safe-area-inset-bottom));
background: var(--bg-card);
border-radius: 32rpx 32rpx 0 0;
border: 1rpx solid var(--border);
box-shadow: var(--shadow-elevated);
box-sizing: border-box;
}
.preview-card::before {
content: '';
display: block;
width: 64rpx;
height: 8rpx;
margin: 0 auto 32rpx;
border-radius: 999rpx;
background: var(--bg-muted);
}
.preview-title {
font-size: 34rpx;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 24rpx;
text-align: center;
letter-spacing: 0;
}
.preview-canvas {
background: var(--bg-input);
border-radius: 24rpx;
overflow: hidden;
margin: 0 auto 24rpx;
border: 1rpx solid var(--border-strong);
position: relative;
min-width: 300rpx;
min-height: 400rpx;
max-width: 100%;
box-sizing: border-box;
}
.preview-image {
position: absolute;
max-width: 100%;
max-height: 100%;
z-index: 5;
}
.preview-image.overlap {
border: 2rpx solid var(--danger);
border-radius: 8rpx;
}
.product-info {
text-align: center;
margin-bottom: 28rpx;
}
.product-name {
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8rpx;
letter-spacing: 0;
}
.product-size {
font-size: 24rpx;
color: var(--text-secondary);
}
.preview-actions {
display: flex;
gap: 16rpx;
}
.preview-actions .btn-secondary,
.preview-actions .btn-primary {
flex: 1;
text-align: center;
padding: 28rpx 0;
font-size: 28rpx;
font-weight: 600;
line-height: 1.2;
}
.preview-actions .btn-primary.disabled {
opacity: 0.5;
pointer-events: none;
}
/* 底部操作栏 — 毛玻璃规则由全局 .action-bar 提供 */
.action-bar .btn-primary,
.action-bar .btn-secondary {
flex: 1;
text-align: center;
padding: 24px 0;
font-size: 28px;
}
/* 局部间距 */
.mt-20 {
margin-top: 20px;
margin-top: 24rpx;
}
+5 -4
View File
@@ -8,6 +8,7 @@ import { useThemeContext } from '../../context/ThemeContext'
import { useSafeArea } from '../../hooks/useSafeArea'
import { useStatusBar } from '../../hooks/useStatusBar'
import ThemedPageMeta from '../../components/ThemedPageMeta'
import BottomActionBar from '../../components/BottomActionBar'
export default function DIYPage() {
const { theme, resolvedTheme } = useThemeContext()
@@ -275,11 +276,11 @@ export default function DIYPage() {
<ThemedPageMeta />
<View className='diy-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header surface-card mt-20' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='flex-between' style={{ width: '100%' }}>
<Text className='back-btn' onTap={goBack}></Text>
<Text className='page-title'></Text>
<View style={{ width: '60px' }} />
<View className='header-spacer' />
</View>
</View>
@@ -358,14 +359,14 @@ export default function DIYPage() {
</View>
{/* 底部操作按钮 */}
<View className='action-bar'>
<BottomActionBar>
<View className='btn-primary' onTap={() => setPreviewMode(true)}>
<Text></Text>
</View>
<View className='btn-secondary' onTap={addSticker}>
<Text></Text>
</View>
</View>
</BottomActionBar>
{/* 预览弹层 */}
{previewMode && (
+126 -76
View File
@@ -1,37 +1,65 @@
.sticker-edit-page {
padding: 0 24px 24px;
padding: 0 32rpx calc(48rpx + env(safe-area-inset-bottom));
min-height: 100vh;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
/* 顶部导航 */
.edit-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: calc(env(safe-area-inset-top, 0px) + 24px) 0 24px;
gap: 16rpx;
padding-bottom: 24rpx;
}
.edit-back {
font-size: 36px;
display: flex;
align-items: center;
justify-content: center;
width: 80rpx;
height: 80rpx;
flex-shrink: 0;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
width: 60px;
}
.edit-back:active {
transform: scale(0.96);
}
.edit-title {
font-size: 34px;
flex: 1;
min-width: 0;
text-align: center;
font-size: 34rpx;
font-weight: 700;
color: var(--text-primary);
text-align: center;
flex: 1;
letter-spacing: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.edit-save {
font-size: 28px;
color: var(--accent-primary);
display: flex;
align-items: center;
justify-content: flex-end;
min-width: 80rpx;
font-size: 26rpx;
font-weight: 600;
width: 60px;
text-align: right;
color: var(--accent-primary);
}
.edit-save:active {
opacity: 0.85;
}
/* 画布区域 */
@@ -40,27 +68,30 @@
display: flex;
align-items: center;
justify-content: center;
padding: 20px 0;
min-height: 400px;
padding: 8rpx 0 24rpx;
min-height: 480rpx;
}
.edit-canvas {
width: 100%;
height: 500px;
height: 480rpx;
background: var(--bg-input);
border-radius: 16px;
border-radius: 24rpx;
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
}
/* 工具面板 */
.edit-tools {
padding: 32px;
padding: 24rpx;
}
.edit-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32px;
gap: 24rpx;
margin-bottom: 24rpx;
}
.edit-row:last-child {
@@ -68,76 +99,36 @@
}
.edit-label {
font-size: 28px;
font-weight: 500;
font-size: 26rpx;
font-weight: 600;
color: var(--text-primary);
width: 120px;
width: 96rpx;
flex-shrink: 0;
}
.slider-wrap {
flex: 1;
display: flex;
align-items: center;
gap: 16px;
}
.slider-track {
flex: 1;
height: 8px;
border-radius: 4px;
background: var(--bg-input);
position: relative;
}
.slider-fill {
height: 100%;
border-radius: 4px;
background: linear-gradient(90deg, var(--accent-primary), var(--accent-primary-soft));
position: absolute;
left: 0;
top: 0;
}
.slider-thumb {
width: 32px;
height: 32px;
border-radius: 50%;
background: #fff;
border: 4px solid var(--accent-primary);
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
.slider-value {
font-size: 24px;
color: var(--text-secondary);
min-width: 60px;
text-align: right;
}
/* 快速操作按钮 */
.edit-quick-actions {
display: flex;
gap: 16px;
gap: 16rpx;
flex-wrap: wrap;
}
.quick-btn {
padding: 16px 28px;
border-radius: 40px;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
height: 64rpx;
padding: 0 28rpx;
border-radius: 999rpx;
font-size: 24rpx;
font-weight: 500;
background: var(--bg-input);
color: var(--text-primary);
border: 1rpx solid var(--border);
transition: all 0.2s;
transition: all 0.2s ease;
}
.quick-btn:active {
opacity: 0.8;
opacity: 0.85;
transform: scale(0.97);
}
@@ -147,13 +138,67 @@
color: var(--accent-primary);
}
/* 底部操作栏 — 毛玻璃规则由全局 .action-bar 提供 */
/* 滑块 */
.slider-wrap {
flex: 1;
display: flex;
align-items: center;
gap: 12rpx;
min-width: 0;
}
.slider-track {
flex: 1;
height: 8rpx;
border-radius: 999rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
position: relative;
min-width: 0;
}
.slider-fill {
height: 100%;
border-radius: 999rpx;
background: linear-gradient(90deg, var(--accent-primary), var(--accent-primary-soft));
position: absolute;
left: 0;
top: 0;
}
.slider-thumb {
width: 32rpx;
height: 32rpx;
border-radius: 50%;
background: var(--bg-card);
border: 4rpx solid var(--accent-primary);
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
box-shadow: var(--shadow-card);
}
.slider-thumb.dragging {
transform: translate(-50%, -50%) scale(1.12);
}
.slider-value {
font-size: 22rpx;
color: var(--text-secondary);
min-width: 80rpx;
text-align: right;
font-variant-numeric: tabular-nums;
}
/* 底部操作栏 — 毛玻璃由 BottomActionBar 提供 */
.edit-footer .btn-primary,
.edit-footer .btn-secondary {
flex: 1;
text-align: center;
padding: 24px 0;
font-size: 28px;
padding: 28rpx 0;
font-size: 28rpx;
font-weight: 600;
line-height: 1.2;
}
/* 加载遮罩 */
@@ -163,7 +208,7 @@
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.4);
background: rgba(0, 0, 0, 0.45);
z-index: 1000;
display: flex;
align-items: center;
@@ -172,7 +217,12 @@
}
.edit-loading-text {
font-size: 28px;
font-size: 28rpx;
color: #fff;
margin-top: 20px;
margin-top: 20rpx;
}
/* 局部间距 */
.mt-20 {
margin-top: 24rpx;
}
+4 -3
View File
@@ -8,6 +8,7 @@ import { useThemeContext } from '../../../context/ThemeContext'
import { useSafeArea } from '../../../hooks/useSafeArea'
import { useStatusBar } from '../../../hooks/useStatusBar'
import ThemedPageMeta from '../../../components/ThemedPageMeta'
import BottomActionBar from '../../../components/BottomActionBar'
/* ============================================================
使用 Canvas 实现贴纸编辑(亮度/色相/线稿)
@@ -324,7 +325,7 @@ export default function StickerEditPage() {
id='editCanvas'
type='2d'
className='edit-canvas'
style={{ width: '100%', height: '400px' }}
style={{ width: '100%', height: '480rpx' }}
/>
</View>
@@ -415,14 +416,14 @@ export default function StickerEditPage() {
<View style={{ flex: 1 }} />
<View className='action-bar edit-footer'>
<BottomActionBar className='edit-footer'>
<View className='btn-secondary' onTap={() => Taro.navigateBack()}>
<Text></Text>
</View>
<View className='btn-primary' onTap={handleSave}>
<Text></Text>
</View>
</View>
</BottomActionBar>
<View className='safe-bottom-placeholder' />
+157 -146
View File
@@ -1,49 +1,52 @@
.index-page {
padding: 0 24px 24px;
padding: 0 32rpx 24rpx;
box-sizing: border-box;
}
/* 顶部标题栏 */
.header-bar {
padding: 20px 0 16px;
/* 页头 */
.home-header {
display: flex;
align-items: center;
align-items: flex-end;
padding-bottom: 32rpx;
}
.header-title {
font-size: 48px;
.home-title {
font-size: 56rpx;
font-weight: 800;
color: var(--text-primary);
letter-spacing: 4px;
letter-spacing: 0;
line-height: 1.15;
}
/* 搜索框卡片 */
.search-card {
padding: 20px 24px;
}
.search-inner {
/* 搜索框 */
.searchbox {
display: flex;
align-items: center;
height: 88rpx;
padding: 0 24rpx;
border-radius: 999rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
border-radius: 40px;
padding: 16px 24px;
border: 1rpx solid transparent;
transition: border-color 160ms ease, box-shadow 160ms ease, background 160ms ease;
}
.search-icon {
font-size: 28px;
margin-right: 16px;
.searchbox:focus-within {
border-color: var(--accent-primary);
box-shadow: 0 0 0 6rpx var(--accent-primary-soft);
background: var(--bg-card);
}
.search-icon-img {
width: 28px;
height: 28px;
margin-right: 16px;
width: 36rpx;
height: 36rpx;
margin-right: 12rpx;
flex-shrink: 0;
}
.search-input {
flex: 1;
font-size: 28px;
height: 88rpx;
font-size: 28rpx;
color: var(--text-primary);
background: transparent;
border: none;
@@ -51,163 +54,173 @@
}
.search-input::placeholder {
color: var(--text-secondary);
font-size: 26px;
color: var(--text-muted);
font-size: 26rpx;
}
.search-result-hint {
margin-top: 16px;
padding-top: 16px;
border-top: 1rpx solid var(--border);
margin: 16rpx 8rpx 0;
font-size: 24rpx;
color: var(--text-secondary);
}
.hint-text {
font-size: 24px;
color: var(--text-secondary);
display: block;
}
/* 成品展示轮播 */
.showcase-section {
margin-top: 20px;
/* 区块标题 */
.home-section-title {
display: block;
margin: 48rpx 0 24rpx;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
}
/* 定制成品 hero 轮播 */
.showcase-swiper {
height: 520rpx;
width: 100%;
height: 360rpx;
}
.showcase-swiper-item {
display: flex;
align-items: center;
justify-content: center;
padding: 0 10rpx;
box-sizing: border-box;
height: 360rpx;
overflow: hidden;
border-radius: 24rpx;
}
.showcase-swiper-card {
.hero-block {
position: relative;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
border-radius: 24px;
overflow: hidden;
box-shadow: var(--shadow-card);
box-sizing: border-box;
border-radius: 24rpx;
background: linear-gradient(150deg, rgba(217, 108, 106, 0.42), rgba(108, 123, 219, 0.18)), var(--bg-muted);
}
.showcase-image-wrapper {
width: 100%;
height: 320rpx;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
flex-shrink: 0;
position: relative;
}
.showcase-real-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.showcase-text-area {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
background: var(--bg-card);
padding: 16px 20px;
position: relative;
}
.showcase-info .showcase-title {
font-size: 32px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
}
.showcase-info .showcase-desc {
font-size: 24px;
color: var(--text-secondary);
display: block;
}
.showcase-tag {
.hero-media {
position: absolute;
top: 16px;
right: 16px;
background: var(--accent-primary);
color: #ffffff;
font-size: 20px;
padding: 4px 16px;
border-radius: 20px;
font-weight: 600;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.glass-overlay {
position: absolute;
left: 24rpx;
bottom: 24rpx;
z-index: 2;
display: flex;
flex-direction: column;
align-items: flex-start;
max-width: 78%;
padding: 16rpx 24rpx;
border-radius: 24rpx;
background: rgba(255, 255, 255, 0.72);
backdrop-filter: blur(24rpx);
-webkit-backdrop-filter: blur(24rpx);
border: 1rpx solid rgba(255, 255, 255, 0.6);
box-shadow: var(--shadow-card);
}
/* 热门品类 */
.category-section {
margin-top: 20px;
.hero-title {
display: block;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
line-height: 1.25;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.category-grid {
.hero-desc {
display: block;
margin-top: 8rpx;
font-size: 24rpx;
color: var(--text-secondary);
letter-spacing: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 两列 media-card */
.home-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 24rpx;
}
.category-item {
.media-card {
overflow: hidden;
border-radius: 24rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
box-shadow: var(--shadow-card);
transition: transform 200ms ease;
}
.media-card:active {
transform: scale(0.98);
}
.media-card-image {
position: relative;
aspect-ratio: 1 / 1;
overflow: hidden;
background: var(--bg-muted);
}
.media-card-img {
display: block;
width: 100%;
height: 100%;
}
.media-card-body {
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx 16rpx 24rpx;
text-align: center;
padding: 0 0 24px;
overflow: hidden;
transition: transform 0.2s;
}
.category-item:active {
transform: scale(0.96);
}
/* 品类顶部实物照片 */
.category-img-wrapper {
.media-card-title {
display: block;
width: 100%;
height: 180rpx;
overflow: hidden;
border-radius: 16px;
margin-bottom: 16px;
position: relative;
}
.category-img-real {
width: 100%;
height: 100%;
object-fit: cover;
}
.category-name {
font-size: 28px;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 28rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 8px;
letter-spacing: 0;
}
.category-desc {
font-size: 22px;
.media-card-desc {
display: block;
width: 100%;
margin-top: 8rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 22rpx;
color: var(--text-secondary);
letter-spacing: 0;
}
.category-price {
font-size: 30px;
.media-card-price {
display: block;
margin-top: 12rpx;
font-size: 28rpx;
font-weight: 700;
color: var(--accent-primary);
margin-top: 8px;
letter-spacing: 0;
font-variant-numeric: tabular-nums;
}
/* 空状态 */
@@ -215,29 +228,27 @@
display: flex;
flex-direction: column;
align-items: center;
padding: 60px 40px;
margin-top: 24rpx;
padding: 48rpx 32rpx;
border-radius: 24rpx;
background: var(--bg-muted);
text-align: center;
}
.empty-icon-img {
width: 48px;
height: 48px;
margin-bottom: 16px;
width: 64rpx;
height: 64rpx;
margin-bottom: 16rpx;
}
.empty-text {
font-size: 30px;
font-size: 30rpx;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 8px;
margin-bottom: 8rpx;
}
.empty-sub {
font-size: 24px;
font-size: 24rpx;
color: var(--text-secondary);
}
/* 底部安全区 */
.safe-bottom-placeholder {
height: 200px;
}
+128 -68
View File
@@ -11,12 +11,48 @@ import ThemedPageMeta from '../../components/ThemedPageMeta'
// 成品展示配图(从 img 里取对应实物图)
const SHOWCASE_LIST = [
{ title: '毕业纪念笔记本', desc: '全班名字组成校徽', image: assetUrl('/img/book_small/The1.jpg') },
{ title: '铜质杯垫', desc: '金属质感桌面艺术', image: assetUrl('/img/cup/The1.jpg') },
{ title: '竹制笔盒', desc: '自然竹纹文房雅器', image: assetUrl('/img/penbox/The1.jpg') },
{ title: '书本型灯', desc: '温暖光影点亮心意', image: assetUrl('/img/booklight/The1.jpg') },
{ title: '情侣定制礼', desc: '两个人的名字交织', image: assetUrl('/img/book_big/The1.jpg') },
{ title: '企业年会礼', desc: '员工名字组成Logo', image: assetUrl('/img/penbox/The2.jpg') }
{
title: '毕业纪念笔记本',
desc: '全班名字组成校徽',
priceText: '¥45 起',
categoryId: 'notebook-large',
image: assetUrl('/img/book_small/The1.jpg')
},
{
title: '铜质杯垫',
desc: '金属质感桌面艺术',
priceText: '¥25 起',
categoryId: 'coaster',
image: assetUrl('/img/cup/The1.jpg')
},
{
title: '竹制笔盒',
desc: '自然竹纹文房雅器',
priceText: '¥75 起',
categoryId: 'penbox',
image: assetUrl('/img/penbox/The1.jpg')
},
{
title: '书本型灯',
desc: '温暖光影点亮心意',
priceText: '¥45 起',
categoryId: 'booklamp',
image: assetUrl('/img/booklight/The1.jpg')
},
{
title: '情侣定制礼',
desc: '两个人的名字交织',
priceText: '¥45 起',
categoryId: 'notebook-large',
image: assetUrl('/img/book_big/The1.jpg')
},
{
title: '企业年会礼',
desc: '员工名字组成Logo',
priceText: '¥75 起',
categoryId: 'penbox',
image: assetUrl('/img/penbox/The2.jpg')
}
]
// 品类对应的实物照片映射(首页卡片顶部大图)
@@ -38,6 +74,17 @@ export default function Index() {
Taro.navigateTo({ url: `/pages/product/index?id=${categoryId}` })
}
const navigateFromShowcase = (item: { categoryId?: string; title: string }) => {
if (item.categoryId) {
navigateToProduct(item.categoryId)
return
}
Taro.showToast({
title: `${item.title}”定制通道即将开放`,
icon: 'none'
})
}
const filteredCategories = searchKey.trim()
? CATEGORIES.filter(
(c) => c.name.includes(searchKey) || c.desc.includes(searchKey)
@@ -53,62 +100,51 @@ export default function Index() {
<ThemedPageMeta />
<View className='index-page'>
{/* 顶部标题栏 */}
<View className='header-bar' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<Text className='header-title'></Text>
{/* 页头 */}
<View className='home-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<Text className='home-title'></Text>
</View>
{/* 搜索 */}
<View className='search-card surface-card'>
<View className='search-inner'>
<Image className='search-icon-img' src={assetUrl('/icon/搜索.svg')} mode='aspectFit' />
<Input
className='search-input'
type='text'
placeholder='搜索定制品类:笔记本、杯垫、书灯...'
value={searchKey}
onInput={handleSearch}
confirmType='search'
/>
{/* 搜索 */}
<View className='searchbox'>
<Image className='search-icon-img' src={assetUrl('/icon/搜索.svg')} mode='aspectFit' />
<Input
className='search-input'
type='text'
placeholder='搜索定制品类:笔记本、杯垫、书灯...'
value={searchKey}
onInput={handleSearch}
confirmType='search'
/>
</View>
{searchKey.trim() && (
<View className='search-result-hint'>
<Text className='hint-text'>
{filteredCategories.length > 0
? `找到 ${filteredCategories.length} 个相关品类`
: '没有找到相关品类,试试看其他关键词'}
</Text>
</View>
{searchKey.trim() && (
<View className='search-result-hint'>
<Text className='hint-text'>
{filteredCategories.length > 0
? `找到 ${filteredCategories.length} 个相关品类`
: '没有找到相关品类,试试看其他关键词'}
</Text>
</View>
)}
</View>
)}
{/* 成品展示轮播 */}
<View className='showcase-section mt-20'>
<Text className='section-title'></Text>
{/* 定制成品展示 */}
<View className='showcase-section'>
<Text className='home-section-title'></Text>
<Swiper
className='showcase-swiper'
indicatorColor='#e0d5c8'
indicatorActiveColor='#d96c6a'
circular
autoplay
interval={3000}
duration={500}
previousMargin='40rpx'
nextMargin='40rpx'
indicatorDots
>
{SHOWCASE_LIST.map((item, idx) => (
<SwiperItem key={idx} className='showcase-swiper-item'>
<View className='showcase-swiper-card surface-card'>
<View className='showcase-image-wrapper'>
<Image className='showcase-real-img' src={item.image} mode='aspectFill' />
</View>
<View className='showcase-text-area'>
<View className='showcase-info'>
<Text className='showcase-title'>{item.title}</Text>
<Text className='showcase-desc'>{item.desc}</Text>
</View>
<View className='showcase-tag'></View>
<View className='hero-block'>
<Image className='hero-media' src={item.image} mode='aspectFill' />
<View className='glass-overlay'>
<Text className='hero-title'>{item.title}</Text>
<Text className='hero-desc'>{item.desc}</Text>
</View>
</View>
</SwiperItem>
@@ -117,30 +153,32 @@ export default function Index() {
</View>
{/* 热门品类 */}
<View className='category-section mt-20'>
<Text className='section-title'></Text>
<View className='category-grid'>
<View className='category-section'>
<Text className='home-section-title'></Text>
<View className='home-grid'>
{filteredCategories.map((cat) => (
<View
key={cat.id}
className='category-item surface-card'
onTap={() => navigateToProduct(cat.id)}
>
<View className='category-img-wrapper'>
<Image
className='category-img-real'
src={PRODUCT_IMG_MAP[cat.id] || assetUrl('/icon/四角星.svg')}
mode='aspectFill'
/>
</View>
<Text className='category-name'>{cat.name}</Text>
<Text className='category-desc'>{cat.desc}</Text>
<Text className='category-price'>¥{cat.price} </Text>
<View
key={cat.id}
className='media-card'
onTap={() => navigateToProduct(cat.id)}
>
<View className='media-card-image'>
<Image
className='media-card-img'
src={PRODUCT_IMG_MAP[cat.id] || assetUrl('/icon/四角星.svg')}
mode='aspectFill'
/>
</View>
<View className='media-card-body'>
<Text className='media-card-title'>{cat.name}</Text>
<Text className='media-card-desc'>{cat.desc}</Text>
<Text className='media-card-price'>¥{cat.price} </Text>
</View>
</View>
))}
</View>
{filteredCategories.length === 0 && (
<View className='empty-category surface-card'>
<View className='empty-category'>
<Image className='empty-icon-img' src={assetUrl('/icon/搜索.svg')} mode='aspectFit' />
<Text className='empty-text'></Text>
<Text className='empty-sub'></Text>
@@ -148,7 +186,29 @@ export default function Index() {
)}
</View>
<View className='safe-bottom-placeholder' />
{/* 为你推荐 */}
<View className='recommend-section'>
<Text className='home-section-title'></Text>
<View className='home-grid'>
{SHOWCASE_LIST.slice(0, 4).map((item, idx) => (
<View
key={idx}
className='media-card'
onTap={() => navigateFromShowcase(item)}
>
<View className='media-card-image'>
<Image className='media-card-img' src={item.image} mode='aspectFill' />
</View>
<View className='media-card-body'>
<Text className='media-card-title'>{item.title}</Text>
<Text className='media-card-desc'>{item.desc}</Text>
<Text className='media-card-price'>{item.priceText}</Text>
</View>
</View>
))}
</View>
</View>
</View>
</View>
)
+324 -329
View File
@@ -1,56 +1,148 @@
/* ============================================================
Order Detail Page — 订单详情
============================================================ */
.order-detail-page {
padding: 0 24px 24px;
min-height: 100vh;
padding: 0 32rpx;
padding-bottom: calc(64rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
}
/* 返回按钮 */
.back-btn {
font-size: 40px;
padding: 10px;
/* --- Page Header --- */
.page-header {
margin-bottom: 24rpx;
padding: 0;
}
/* 状态卡片 */
.status-card {
padding: 32px;
}
.status-top {
.page-header-inner {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 32px;
gap: 16rpx;
min-height: 88rpx;
}
.status-badge {
font-size: 26px;
.back-btn {
display: flex;
align-items: center;
justify-content: center;
width: 88rpx;
height: 88rpx;
flex: 0 0 auto;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
}
.back-btn:active {
transform: scale(0.96);
}
.back-arrow {
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
}
.nav-title {
flex: 1;
text-align: center;
font-size: 34rpx;
font-weight: 700;
color: var(--text-primary);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.nav-placeholder {
width: 88rpx;
flex: 0 0 auto;
}
/* --- 状态横幅 --- */
.status-banner {
margin-bottom: 24rpx;
padding: 32rpx;
background: var(--accent-primary-soft);
border-color: transparent;
}
.status-text {
display: block;
font-size: 40rpx;
font-weight: 800;
color: var(--accent-primary);
letter-spacing: 0;
}
.status-desc {
font-size: 26px;
display: block;
margin-top: 8rpx;
font-size: 26rpx;
color: var(--text-secondary);
}
/* 物流时间轴 */
.logistics-timeline {
position: relative;
padding-left: 20px;
/* --- 通用卡片 --- */
.detail-card {
margin-bottom: 24rpx;
padding: 32rpx;
}
.logistics-timeline::before {
.card-icon-img {
width: 40rpx;
height: 40rpx;
margin-right: 12rpx;
}
/* --- 物流信息 --- */
.logistics-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16rpx;
padding-bottom: 24rpx;
margin-bottom: 24rpx;
border-bottom: 1rpx solid var(--border);
}
.logistics-header .flex-center {
display: flex;
align-items: center;
min-width: 0;
}
.logistics-title {
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
}
.logistics-num {
flex: 0 0 auto;
font-size: 22rpx;
color: var(--text-secondary);
}
.timeline {
position: relative;
padding-left: 20rpx;
}
.timeline::before {
content: '';
position: absolute;
left: 8px;
top: 8px;
bottom: 8px;
width: 2px;
left: 8rpx;
top: 12rpx;
bottom: 12rpx;
width: 2rpx;
background: var(--border);
opacity: 0.3;
opacity: 0.5;
}
.timeline-item {
display: flex;
align-items: flex-start;
margin-bottom: 24px;
margin-bottom: 32rpx;
position: relative;
}
@@ -59,14 +151,14 @@
}
.timeline-dot {
width: 18px;
height: 18px;
width: 20rpx;
height: 20rpx;
border-radius: 50%;
background: var(--bg-card);
border: 2rpx solid var(--border-strong);
margin-right: 20px;
margin-right: 24rpx;
margin-left: -30rpx;
flex-shrink: 0;
margin-left: -20px;
z-index: 2;
}
@@ -77,101 +169,236 @@
.timeline-content {
flex: 1;
min-width: 0;
}
.timeline-title {
font-size: 28px;
color: var(--text-primary);
.timeline-status {
display: block;
margin-bottom: 6px;
margin-bottom: 8rpx;
font-size: 30rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
}
.timeline-time {
font-size: 24px;
display: block;
margin-bottom: 8rpx;
font-size: 22rpx;
color: var(--text-secondary);
}
/* 地址卡片 */
.address-card {
padding: 32px;
.timeline-desc {
display: block;
font-size: 26rpx;
color: var(--text-secondary);
line-height: 1.6;
}
/* --- 商品信息 --- */
.product-row {
display: flex;
align-items: center;
gap: 24rpx;
padding-bottom: 24rpx;
border-bottom: 1rpx solid var(--border);
}
.product-icon-wrapper {
display: flex;
align-items: center;
justify-content: center;
width: 88rpx;
height: 88rpx;
flex: 0 0 auto;
border-radius: 16rpx;
background: var(--bg-input);
overflow: hidden;
}
.product-icon-img {
width: 52rpx;
height: 52rpx;
}
.product-info {
flex: 1;
min-width: 0;
}
.product-name {
display: block;
margin-bottom: 8rpx;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
line-height: 1.3;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.product-sku {
display: block;
font-size: 24rpx;
color: var(--text-secondary);
}
.price-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24rpx;
padding-top: 24rpx;
}
.price-label {
font-size: 28rpx;
color: var(--text-secondary);
}
.price-value {
font-size: 32rpx;
font-weight: 700;
color: var(--accent-primary);
font-variant-numeric: tabular-nums;
}
/* --- 收货地址 --- */
.address-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
gap: 16rpx;
margin-bottom: 16rpx;
}
.address-header .flex-center {
display: flex;
align-items: center;
flex: 1;
min-width: 0;
}
.address-title {
font-size: 30px;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
}
.address-change {
padding: 6px 16px;
border-radius: 8px;
display: flex;
align-items: center;
height: 56rpx;
padding: 0 24rpx;
border-radius: 999rpx;
background: var(--accent-secondary-soft);
}
.change-text {
font-size: 24px;
font-size: 24rpx;
font-weight: 500;
color: var(--accent-secondary);
}
.address-body {
padding-top: 8px;
padding-top: 8rpx;
}
.address-row {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 8px;
gap: 16rpx;
margin-bottom: 8rpx;
}
.address-name {
font-size: 28px;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
}
.address-phone {
font-size: 26px;
font-size: 24rpx;
color: var(--text-secondary);
}
.address-detail {
font-size: 26px;
font-size: 26rpx;
color: var(--text-secondary);
line-height: 1.5;
line-height: 1.6;
}
.address-empty {
padding: 32px 0;
padding: 32rpx 0;
text-align: center;
font-size: 28rpx;
color: var(--text-secondary);
}
/* 底部弹窗 — 地址选择(样式复用 app.scss 全局定义,移除非必要覆写) */
/* --- 订单信息 --- */
.meta-title {
display: block;
margin-bottom: 8rpx;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
}
.meta-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24rpx;
padding: 20rpx 0;
border-bottom: 1rpx solid var(--border);
}
.meta-row:last-child {
border-bottom: none;
padding-bottom: 0;
}
.meta-label {
flex: 0 0 auto;
font-size: 26rpx;
color: var(--text-secondary);
}
.meta-value {
flex: 1;
text-align: right;
font-size: 26rpx;
font-weight: 500;
color: var(--text-primary);
word-break: break-all;
}
/* --- 地址选择弹层 --- */
.addr-picker-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
margin-bottom: 24rpx;
}
.addr-picker-title {
font-size: 32px;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
}
.addr-picker-close {
font-size: 28px;
display: flex;
align-items: center;
justify-content: center;
width: 64rpx;
height: 64rpx;
border-radius: 50%;
background: var(--bg-muted);
color: var(--text-secondary);
padding: 8px;
font-size: 28rpx;
}
.addr-picker-list {
@@ -180,314 +407,82 @@
}
.addr-picker-item {
padding: 20px 16px;
border-bottom: 1rpx solid var(--border);
padding: 24rpx;
border: 1rpx solid transparent;
border-radius: 16rpx;
transition: background 160ms ease, border-color 160ms ease;
}
.addr-picker-item + .addr-picker-item {
margin-top: 16rpx;
}
.addr-picker-item.active {
background: var(--accent-secondary-soft);
border-radius: 12px;
background: var(--accent-primary-soft);
border-color: var(--accent-primary);
}
.addr-picker-row {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 8px;
gap: 16rpx;
margin-bottom: 8rpx;
}
.addr-picker-name {
font-size: 28px;
font-size: 30rpx;
font-weight: 700;
color: var(--text-primary);
}
.addr-picker-phone {
font-size: 26px;
font-size: 24rpx;
color: var(--text-secondary);
}
.addr-picker-default {
font-size: 22px;
display: inline-flex;
align-items: center;
height: 40rpx;
padding: 0 16rpx;
border-radius: 999rpx;
font-size: 20rpx;
font-weight: 600;
color: var(--accent-primary);
border: 1rpx solid var(--accent-primary);
padding: 2px 8px;
border-radius: 6px;
background: var(--accent-primary-soft);
}
.addr-picker-detail {
font-size: 26px;
font-size: 26rpx;
color: var(--text-secondary);
line-height: 1.6;
}
.addr-picker-empty {
padding: 40px;
padding: 48rpx 32rpx;
text-align: center;
font-size: 28rpx;
color: var(--text-secondary);
font-size: 28px;
}
.addr-picker-add {
margin-top: 16px;
padding: 20px;
text-align: center;
border: 1rpx solid var(--border-strong);
border-radius: 12px;
}
.addr-picker-add-text {
font-size: 28px;
color: var(--accent-secondary);
}
/* 卡片标题 icon(物流/地址) */
.card-icon-img {
width: 32px;
height: 32px;
margin-right: 10px;
}
/* 商品卡片 */
.product-card {
padding: 32px;
}
.product-row {
display: flex;
align-items: center;
margin-bottom: 24px;
}
.product-icon-wrapper {
width: 100px;
height: 100px;
background: var(--bg-input);
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20px;
overflow: hidden;
padding: 8px;
box-sizing: border-box;
}
.product-icon-img {
width: 64px;
height: 64px;
}
.product-info {
flex: 1;
}
.product-name {
font-size: 30px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
}
.product-sku {
font-size: 24px;
color: var(--text-secondary);
}
.price-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 0;
border-top: 1rpx solid var(--border);
}
.price-label {
font-size: 26px;
color: var(--text-secondary);
}
.price-value {
font-size: 28px;
color: var(--text-primary);
}
.price-row.total {
padding-top: 20px;
}
.total-label {
font-size: 28px;
font-weight: 700;
}
.total-value {
font-size: 36px;
font-weight: 800;
color: var(--accent-primary);
}
/* 信息卡片 */
.info-card {
padding: 32px;
}
.info-card .info-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 0;
}
.info-card .info-label {
font-size: 26px;
color: var(--text-secondary);
}
.info-card .info-value {
font-size: 26px;
color: var(--text-primary);
}
/* 状态横幅 */
.status-text {
font-size: 48px;
font-weight: 800;
color: var(--text-primary);
display: block;
margin-bottom: 10px;
}
/* 物流信息 */
.logistics-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24px;
padding-bottom: 16px;
border-bottom: 1rpx solid var(--border);
}
.logistics-title {
font-size: 30px;
font-weight: 700;
color: var(--text-primary);
}
.logistics-num {
font-size: 24px;
color: var(--text-secondary);
}
.timeline {
position: relative;
padding-left: 20px;
}
.timeline::before {
content: '';
position: absolute;
left: 8px;
top: 8px;
bottom: 8px;
width: 2px;
background: var(--border);
opacity: 0.3;
}
.timeline-item {
display: flex;
align-items: flex-start;
margin-bottom: 24px;
position: relative;
}
.timeline-item:last-child {
margin-bottom: 0;
}
.timeline-dot {
width: 18px;
height: 18px;
border-radius: 50%;
background: var(--bg-card);
border: 2rpx solid var(--border-strong);
margin-right: 20px;
flex-shrink: 0;
margin-left: -20px;
z-index: 2;
}
.timeline-item.active .timeline-dot {
background: var(--accent-primary);
border-color: var(--accent-primary);
}
.timeline-content {
flex: 1;
}
.timeline-status {
font-size: 28px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 6px;
}
.timeline-time {
font-size: 24px;
color: var(--text-secondary);
display: block;
margin-bottom: 4px;
}
.timeline-desc {
font-size: 26px;
color: var(--text-secondary);
line-height: 1.4;
}
/* 订单信息 */
.meta-title {
font-size: 30px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 16px;
}
.meta-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 0;
}
.meta-label {
font-size: 26px;
color: var(--text-secondary);
}
.meta-value {
font-size: 26px;
color: var(--text-primary);
}
.preview-card {
padding: 32px;
}
.design-preview {
position: relative;
background: var(--bg-input);
border-radius: 16px;
overflow: hidden;
height: 96rpx;
margin-top: 24rpx;
border: 1rpx solid var(--border-strong);
margin: 0 auto;
border-radius: 999rpx;
background: var(--bg-card);
}
.preview-sticker {
position: absolute;
max-width: 100%;
max-height: 100%;
.addr-picker-add-text {
font-size: 28rpx;
font-weight: 600;
color: var(--accent-secondary);
}
/* --- 底部留白 --- */
.page-bottom-spacer {
height: 48rpx;
}
+24 -16
View File
@@ -56,8 +56,14 @@ export default function OrderDetailPage() {
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='order-detail-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<Text className='page-title'></Text>
<View className='page-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header-inner'>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='nav-title'></Text>
<View className='nav-placeholder' />
</View>
</View>
</View>
</View>
@@ -65,20 +71,22 @@ export default function OrderDetailPage() {
}
return (
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='order-detail-page'>
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='order-detail-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='flex-between' style={{ width: '100%' }}>
<Text className='back-btn' onTap={() => Taro.navigateBack()}></Text>
<Text className='page-title'></Text>
<View style={{ width: '60px' }} />
<View className='page-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header-inner'>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='nav-title'></Text>
<View className='nav-placeholder' />
</View>
</View>
{/* 状态横幅 */}
<View className='status-banner surface-card mt-20'>
<View className='status-banner surface-card'>
<Text className='status-text'>
{order.statusCode === 'pending' && '待付款'}
{order.statusCode === 'paid' && '待发货'}
@@ -95,7 +103,7 @@ export default function OrderDetailPage() {
{/* 物流信息(仅 shipping/done */}
{(order.statusCode === 'shipping' || order.statusCode === 'done') && (
<View className='logistics-card surface-card mt-20'>
<View className='logistics-card detail-card surface-card'>
<View className='logistics-header'>
<View className='flex-center'>
<Image className='card-icon-img' src={assetUrl('/icon/包裹.png')} mode='aspectFit' />
@@ -133,7 +141,7 @@ export default function OrderDetailPage() {
)}
{/* 商品信息 */}
<View className='product-card surface-card mt-20'>
<View className='product-card detail-card surface-card'>
<View className='product-row'>
<View className='product-icon-wrapper'>
<Image
@@ -154,7 +162,7 @@ export default function OrderDetailPage() {
</View>
{/* 收货地址 */}
<View className='address-card surface-card mt-20'>
<View className='address-card detail-card surface-card'>
<View className='address-header'>
<View className='flex-center'>
<Image className='card-icon-img' src={assetUrl('/icon/地址.png')} mode='aspectFit' />
@@ -182,7 +190,7 @@ export default function OrderDetailPage() {
</View>
{/* 订单信息 */}
<View className='meta-card surface-card mt-20'>
<View className='meta-card detail-card surface-card'>
<Text className='meta-title'></Text>
<View className='meta-row'>
<Text className='meta-label'></Text>
@@ -198,7 +206,7 @@ export default function OrderDetailPage() {
</View>
</View>
<View style={{ height: '40px' }} />
<View className='page-bottom-spacer' />
{/* 地址选择底部弹窗 */}
{showAddrPicker && (
+202 -105
View File
@@ -1,163 +1,260 @@
.orders-page {
padding: 0 24px 24px;
padding: 0 32rpx 48rpx;
min-height: 100vh;
box-sizing: border-box;
}
.page-header {
padding: 32px 32px 24px;
margin: 20px 0 0;
/* 页面主标题 */
.orders-page .page-header {
display: flex;
align-items: flex-end;
padding-bottom: 32rpx;
margin: 0;
}
/* 状态Tab */
.status-tabs {
margin: 20px 0;
.orders-page .page-title {
display: block;
font-size: 44rpx;
font-weight: 700;
line-height: 1.2;
color: var(--text-primary);
letter-spacing: 0;
}
.tabs-scroll {
/* 状态筛选 chip */
.orders-page .status-tabs {
margin: 8rpx 0 32rpx;
}
.orders-page .tabs-scroll {
white-space: nowrap;
}
.tab-item {
display: inline-block;
padding: 20px 32px;
position: relative;
}
.tab-label {
font-size: 28px;
.orders-page .tab-item {
display: inline-flex;
align-items: center;
justify-content: center;
height: 64rpx;
padding: 0 32rpx;
margin-right: 16rpx;
border-radius: 999rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
color: var(--text-secondary);
font-size: 26rpx;
font-weight: 500;
}
.tab-item.active .tab-label {
color: var(--accent-primary);
font-weight: 700;
}
.tab-underline {
position: absolute;
bottom: 8px;
left: 50%;
transform: translateX(-50%);
width: 40px;
height: 4px;
.orders-page .tab-item.active {
background: var(--accent-primary);
border-radius: 4px;
border-color: var(--accent-primary);
color: var(--bg-page);
font-weight: 600;
}
/* 订单卡片 */
.orders-list {
padding: 0;
}
.order-card {
margin-bottom: 24px;
padding: 28px;
.orders-page .tab-label {
color: inherit;
}
.order-header {
.orders-page .tab-underline {
display: none;
}
/* 订单列表 */
.orders-page .orders-list {
padding: 0 0 8rpx;
}
.orders-page .order-card {
margin-bottom: 24rpx;
padding: 28rpx;
border-radius: 24rpx;
box-shadow: var(--shadow-card);
transition: transform 0.2s ease;
}
.orders-page .order-card:active {
transform: scale(0.98);
}
.orders-page .order-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 20px;
justify-content: space-between;
gap: 24rpx;
padding-bottom: 20rpx;
border-bottom: 1rpx solid var(--border);
margin-bottom: 20px;
margin-bottom: 24rpx;
}
.order-date {
font-size: 24px;
.orders-page .order-date {
display: block;
min-width: 0;
font-size: 24rpx;
color: var(--text-secondary);
}
.order-body {
display: flex;
align-items: flex-start;
margin-bottom: 20px;
.orders-page .order-card .badge {
display: inline-flex;
align-items: center;
justify-content: center;
height: 40rpx;
padding: 0 16rpx;
border-radius: 999rpx;
font-size: 22rpx;
font-weight: 600;
line-height: 1;
flex-shrink: 0;
}
.order-icon-wrapper {
width: 120px;
height: 120px;
background: var(--bg-input);
border-radius: 16px;
.orders-page .order-body {
display: flex;
align-items: center;
gap: 24rpx;
margin-bottom: 24rpx;
}
.orders-page .order-icon-wrapper {
width: 96rpx;
height: 96rpx;
border-radius: 24rpx;
background: var(--bg-muted);
display: flex;
align-items: center;
justify-content: center;
margin-right: 20px;
flex-shrink: 0;
}
.order-icon {
font-size: 56px;
}
.order-icon-img {
width: 56px;
height: 56px;
}
.order-info {
flex: 1;
}
.order-product {
font-size: 30px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
}
.order-sku {
font-size: 24px;
color: var(--text-secondary);
display: block;
margin-bottom: 8px;
}
.order-meta {
font-size: 22px;
color: var(--text-muted);
display: block;
.orders-page .order-icon-img {
width: 56rpx;
height: 56rpx;
}
.order-footer {
padding-top: 16px;
.orders-page .order-info {
flex: 1;
min-width: 0;
}
.orders-page .order-product {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 30rpx;
font-weight: 700;
line-height: 1.3;
color: var(--text-primary);
margin-bottom: 8rpx;
}
.orders-page .order-sku {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 24rpx;
line-height: 1.4;
color: var(--text-secondary);
margin-bottom: 6rpx;
}
.orders-page .order-meta {
display: block;
font-size: 22rpx;
line-height: 1.4;
color: var(--text-muted);
font-variant-numeric: tabular-nums;
}
.orders-page .order-footer {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 16rpx;
padding-top: 20rpx;
border-top: 1rpx solid var(--border);
}
.order-price-bar {
.orders-page .order-price-bar {
display: flex;
align-items: baseline;
justify-content: flex-end;
margin-bottom: 20px;
flex-shrink: 0;
}
.price-label {
font-size: 24px;
.orders-page .price-label {
font-size: 24rpx;
color: var(--text-secondary);
margin-right: 8px;
margin-right: 8rpx;
}
.price-value {
font-size: 36px;
.orders-page .price-value {
font-size: 34rpx;
font-weight: 800;
line-height: 1.2;
color: var(--accent-primary);
font-variant-numeric: tabular-nums;
}
.order-actions {
.orders-page .order-actions {
display: flex;
justify-content: flex-end;
gap: 16px;
flex-wrap: wrap;
gap: 12rpx;
}
.order-btn {
padding: 14px 28px !important;
font-size: 26px !important;
border-radius: 999rpx !important;
.orders-page .order-btn {
display: flex;
align-items: center;
justify-content: center;
height: 64rpx;
padding: 0 28rpx;
font-size: 26rpx;
font-weight: 600;
line-height: 1.2;
border-radius: 999rpx;
}
/* 空状态 */
.empty-state {
.orders-page .empty-state {
display: flex;
flex-direction: column;
align-items: center;
padding: 120px 40px;
padding: 80rpx 32rpx;
text-align: center;
background: var(--bg-muted);
border-radius: 24rpx;
}
.empty-icon-img {
width: 56px;
height: 56px;
margin-bottom: 24px;
.orders-page .empty-icon-img {
width: 88rpx;
height: 88rpx;
margin-bottom: 24rpx;
}
.empty-text {
font-size: 36px;
.orders-page .empty-text {
display: block;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 12px;
margin-bottom: 12rpx;
}
.empty-sub {
font-size: 28px;
.orders-page .empty-sub {
display: block;
font-size: 26rpx;
color: var(--text-secondary);
margin-bottom: 40px;
margin-bottom: 32rpx;
}
.orders-page .empty-state .btn-primary {
display: flex;
align-items: center;
justify-content: center;
min-width: 280rpx;
height: 88rpx;
padding: 0 48rpx;
border-radius: 999rpx;
font-size: 30rpx;
font-weight: 600;
}
+1 -2
View File
@@ -87,7 +87,7 @@ export default function OrdersPage() {
<LoginGuard>
<View className='orders-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<Text className='page-title'></Text>
</View>
@@ -188,7 +188,6 @@ export default function OrdersPage() {
)}
</ScrollView>
<View style={{ height: '40px' }} />
</View>
</LoginGuard>
</View>
+223 -104
View File
@@ -1,237 +1,356 @@
.product-page {
padding: 0 24px 24px;
padding-bottom: calc(24px + 200px); /* 为底部毛玻璃 action-bar 留空 */
padding: 0 32rpx 32rpx;
padding-bottom: calc(32rpx + 480rpx);
}
/* 通栏页头 */
.page-header {
position: relative;
z-index: 10;
padding: 0 24rpx 24rpx;
margin-bottom: 24rpx;
}
.page-header-inner {
display: flex;
align-items: center;
gap: 16rpx;
min-height: 88rpx;
}
/* 返回按钮 */
.back-btn {
font-size: 40px;
padding: 10px;
width: 88rpx;
height: 88rpx;
flex: 0 0 auto;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
display: flex;
align-items: center;
justify-content: center;
}
.back-btn:active {
transform: scale(0.96);
}
.back-arrow {
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
}
.nav-title {
flex: 1;
text-align: center;
font-size: 34rpx;
font-weight: 600;
color: var(--text-primary);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.nav-placeholder {
width: 88rpx;
flex: 0 0 auto;
}
/* Hero 轮播 */
.hero-section {
margin-top: 20px;
width: 100%;
}
.hero-swiper {
height: 400rpx;
height: 560rpx;
}
.hero-card {
.hero-block {
position: relative;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
box-sizing: border-box;
}
.hero-icon {
font-size: 100px;
margin-bottom: 16px;
}
.hero-icon-img {
width: 100px;
height: 100px;
margin-bottom: 16px;
}
.hero-name {
font-size: 36px;
font-weight: 700;
color: var(--text-primary);
overflow: hidden;
border-radius: 24rpx;
background: var(--bg-muted);
box-shadow: var(--shadow-card);
}
.hero-image {
width: 100%;
height: 100%;
object-fit: contain;
}
/* 基本信息 */
.info-section {
padding: 24px;
}
.info-row {
.hero-block-fallback {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: linear-gradient(160deg, var(--accent-primary-strong), var(--accent-secondary));
}
.hero-fallback-icon {
width: 140rpx;
height: 140rpx;
margin-bottom: 24rpx;
}
/* detail-card 版式 */
.detail-card {
padding: 32rpx;
margin-top: 24rpx;
}
.price-line {
display: flex;
align-items: flex-end;
justify-content: space-between;
padding: 20px 0;
border-bottom: 1rpx solid var(--border);
gap: 24rpx;
}
.info-row:last-child {
border-bottom: none;
.price-left {
flex: 1;
min-width: 0;
}
.info-label {
font-size: 28px;
color: var(--text-secondary);
}
.info-price {
font-size: 40px;
font-weight: 800;
color: var(--accent-primary);
}
.info-value {
font-size: 28px;
.detail-title {
display: block;
font-size: 36rpx;
font-weight: 700;
line-height: 1.3;
color: var(--text-primary);
}
/* 详细介绍 */
.detail-section {
padding: 24px;
.detail-desc {
display: block;
margin-top: 8rpx;
font-size: 24rpx;
line-height: 1.4;
color: var(--text-secondary);
}
.price-right {
flex: 0 0 auto;
text-align: right;
}
.price {
display: block;
font-size: 40rpx;
font-weight: 800;
line-height: 1.2;
color: var(--accent-primary);
font-variant-numeric: tabular-nums;
}
.price-old {
display: block;
margin-top: 6rpx;
font-size: 24rpx;
color: var(--text-muted);
text-decoration: line-through;
font-variant-numeric: tabular-nums;
}
.spec-row {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 24rpx;
padding: 24rpx 0;
border-bottom: 1rpx solid var(--border);
}
.spec-row:last-child {
border-bottom: none;
padding-bottom: 0;
}
.spec-key {
flex: 0 0 auto;
font-size: 26rpx;
color: var(--text-secondary);
}
.spec-value {
flex: 1;
text-align: right;
font-size: 26rpx;
font-weight: 600;
color: var(--text-primary);
word-break: break-all;
}
.detail-card .section-title {
font-size: 32rpx;
font-weight: 700;
margin-bottom: 24rpx;
}
.detail-text {
font-size: 28px;
color: var(--text-secondary);
display: block;
font-size: 28rpx;
line-height: 1.8;
color: var(--text-secondary);
}
/* 底部操作栏 */
.action-bar .price-summary {
.bottom-action-bar {
gap: 20rpx;
padding-left: 32rpx;
padding-right: 32rpx;
}
.bottom-action-bar .price-summary {
flex-shrink: 0;
}
.summary-label {
font-size: 22px;
color: var(--text-secondary);
display: block;
font-size: 22rpx;
color: var(--text-secondary);
}
.summary-price {
font-size: 36px;
display: block;
font-size: 36rpx;
font-weight: 700;
color: var(--accent-primary);
font-variant-numeric: tabular-nums;
}
.summary-original {
display: block;
margin-top: 2rpx;
font-size: 22rpx;
color: var(--text-muted);
text-decoration: line-through;
font-variant-numeric: tabular-nums;
}
.bottom-action-bar .btn-secondary,
.bottom-action-bar .btn-primary {
flex: 1;
text-align: center;
padding: 28rpx 0;
font-size: 28rpx;
font-weight: 600;
line-height: 1.2;
}
/* 弹窗 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 48px;
padding: 48rpx;
}
.modal-card {
width: 100%;
max-width: 600px;
padding: 40px;
max-width: 640rpx;
padding: 40rpx;
}
.modal-title {
font-size: 36px;
display: block;
text-align: center;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
text-align: center;
margin-bottom: 24px;
display: block;
margin-bottom: 24rpx;
}
.modal-product {
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
margin-bottom: 32px;
}
.modal-icon {
font-size: 48px;
gap: 16rpx;
margin-bottom: 32rpx;
}
.modal-icon-img {
width: 48px;
height: 48px;
width: 48rpx;
height: 48rpx;
}
.modal-name {
font-size: 32px;
color: var(--text-primary);
font-size: 32rpx;
font-weight: 600;
color: var(--text-primary);
}
.quantity-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32px;
margin-bottom: 32rpx;
}
.qty-label {
font-size: 28px;
font-size: 28rpx;
color: var(--text-secondary);
}
.qty-control {
display: flex;
align-items: center;
gap: 24px;
gap: 24rpx;
}
.qty-btn {
width: 60px;
height: 60px;
border-radius: 12px;
width: 60rpx;
height: 60rpx;
border-radius: 16rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
color: var(--text-primary);
font-size: 32rpx;
font-weight: 600;
color: var(--text-primary);
}
.qty-num {
font-size: 32px;
min-width: 48rpx;
text-align: center;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
min-width: 48px;
text-align: center;
}
.modal-total {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32px;
padding-top: 24px;
margin-bottom: 32rpx;
padding-top: 24rpx;
border-top: 1rpx solid var(--border);
}
.total-label {
font-size: 28px;
font-size: 28rpx;
color: var(--text-secondary);
}
.total-price {
font-size: 36px;
font-size: 36rpx;
font-weight: 800;
color: var(--accent-primary);
font-variant-numeric: tabular-nums;
}
.modal-actions {
display: flex;
gap: 20px;
gap: 20rpx;
}
.modal-actions .btn-secondary,
.modal-actions .btn-primary {
flex: 1;
padding: 20px 0;
text-align: center;
padding: 24rpx 0;
font-size: 28rpx;
font-weight: 600;
}
+66 -37
View File
@@ -8,10 +8,9 @@ import { useThemeContext } from '../../context/ThemeContext'
import { useSafeArea } from '../../hooks/useSafeArea'
import { useStatusBar } from '../../hooks/useStatusBar'
import ThemedPageMeta from '../../components/ThemedPageMeta'
import BottomActionBar from '../../components/BottomActionBar'
import { getProductIconImg } from '../../utils/productConfig'
const HERO_COLORS = ['var(--accent-primary-soft)', 'var(--bg-muted)', 'var(--accent-secondary-soft)']
export default function ProductPage() {
const { theme, resolvedTheme } = useThemeContext()
const safe = useSafeArea()
@@ -21,7 +20,7 @@ export default function ProductPage() {
const router = Taro.getCurrentInstance().router
const params = router ? router.params : undefined
const productId = params ? params.id : ''
const productId = params && params.id ? params.id : ''
const product = getProductById(productId)
if (!product) {
@@ -29,14 +28,25 @@ export default function ProductPage() {
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='product-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<Text className='page-title'></Text>
<View className='page-header' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header-inner'>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='nav-title'></Text>
<View className='nav-placeholder' />
</View>
</View>
</View>
</View>
)
}
const craftSpec = product.specs && product.specs.length > 0
? product.specs.find(item => item[0].indexOf('工艺') >= 0)
: undefined
const craftValue = craftSpec ? craftSpec[1] : '激光微雕'
const handleAddToList = () => {
setQuantity(1)
setShowModal(true)
@@ -64,16 +74,18 @@ export default function ProductPage() {
<ThemedPageMeta />
<View className='product-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='flex-between'>
<Text className='back-btn' onTap={() => Taro.navigateBack()}></Text>
<Text className='page-title'></Text>
<View style={{ width: '60px' }} />
<View className='page-header' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header-inner'>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='nav-title'></Text>
<View className='nav-placeholder' />
</View>
</View>
{/* 轮播 Hero */}
<View className='hero-section mt-20'>
<View className='hero-section'>
<Swiper
className='hero-swiper'
circular
@@ -81,54 +93,71 @@ export default function ProductPage() {
interval={3000}
duration={500}
indicatorDots
indicatorColor='#e0d5c8'
indicatorActiveColor='#d96c6a'
indicatorColor='var(--border-strong)'
indicatorActiveColor='var(--accent-primary)'
>
{product.images && product.images.length > 0 ? (
product.images.map((img, idx) => (
<SwiperItem key={idx}>
<View className='hero-card surface-card'>
<Image className='hero-image' src={img} mode='aspectFit' />
<View className='hero-block'>
<Image className='hero-image' src={img} mode='aspectFill' />
</View>
</SwiperItem>
))
) : (
HERO_COLORS.map((color, idx) => (
<SwiperItem key={idx}>
<View className='hero-card surface-card' style={{ background: color }}>
<Image className='hero-icon-img' src={getProductIconImg(product)} mode='aspectFit' />
<Text className='hero-name'>{product.name}</Text>
</View>
</SwiperItem>
))
<SwiperItem>
<View className='hero-block hero-block-fallback'>
<Image className='hero-fallback-icon' src={getProductIconImg(product)} mode='aspectFit' />
</View>
</SwiperItem>
)}
</Swiper>
</View>
{/* 基本信息 */}
<View className='info-section surface-card mt-20'>
<View className='info-row'>
<Text className='info-label'></Text>
<Text className='info-price'>¥{product.price}</Text>
{/* 商品信息 */}
<View className='detail-card surface-card'>
<View className='price-line'>
<View className='price-left'>
<Text className='detail-title'>{product.name}</Text>
<Text className='detail-desc'>{product.desc}</Text>
</View>
<View className='price-right'>
<Text className='price'>¥{product.price}</Text>
{product.originalPrice && product.originalPrice > product.price && (
<Text className='price-old'>¥{product.originalPrice}</Text>
)}
</View>
</View>
<View className='info-row'>
<Text className='info-label'></Text>
<Text className='info-value'>{product.leadTime}</Text>
</View>
{/* 规格信息 */}
<View className='detail-card surface-card'>
<View className='spec-row'>
<Text className='spec-key'></Text>
<Text className='spec-value'>¥{product.price}</Text>
</View>
<View className='info-row'>
<Text className='info-label'></Text>
<Text className='info-value'>{product.mask.width} × {product.mask.height} px</Text>
<View className='spec-row'>
<Text className='spec-key'></Text>
<Text className='spec-value'>{product.leadTime}</Text>
</View>
<View className='spec-row'>
<Text className='spec-key'></Text>
<Text className='spec-value'>{product.mask.width} × {product.mask.height} px</Text>
</View>
<View className='spec-row'>
<Text className='spec-key'></Text>
<Text className='spec-value'>{craftValue}</Text>
</View>
</View>
{/* 详细介绍 */}
<View className='detail-section surface-card mt-20'>
<View className='detail-card surface-card'>
<Text className='section-title'></Text>
<Text className='detail-text'>{product.description}</Text>
</View>
{/* 底部操作栏 */}
<View className='action-bar'>
<BottomActionBar>
<View className='price-summary'>
<Text className='summary-label'></Text>
<Text className='summary-price'>¥{product.price}</Text>
@@ -139,7 +168,7 @@ export default function ProductPage() {
<View className='btn-primary' onTap={goToDIY}>
<Text></Text>
</View>
</View>
</BottomActionBar>
{/* 安全区占位(防止内容被 action-bar 遮挡) */}
<View className='safe-bottom-placeholder' />
+197 -162
View File
@@ -1,244 +1,272 @@
.profile-page {
padding: 0 24px 24px;
padding: 0 32rpx 48rpx;
min-height: 100vh;
box-sizing: border-box;
}
/* 用户头部 */
.profile-header {
padding: 40px 32px 32px;
margin: 20px 0 0;
.profile-page .profile-header {
padding: 32rpx 32rpx 16rpx;
margin: 0 0 32rpx;
}
.user-info {
.profile-page .user-info {
display: flex;
align-items: center;
margin-bottom: 32px;
gap: 24rpx;
margin-bottom: 24rpx;
}
.avatar {
width: 120px;
height: 120px;
.profile-page .avatar,
.profile-page .avatar-placeholder {
width: 112rpx;
height: 112rpx;
border-radius: 50%;
border: 1rpx solid var(--border);
margin-right: 24px;
flex-shrink: 0;
}
.avatar-placeholder {
width: 120px;
height: 120px;
border-radius: 50%;
background: var(--bg-muted);
display: flex;
align-items: center;
justify-content: center;
margin-right: 24px;
border: 1rpx solid var(--border);
margin-right: 0;
flex-shrink: 0;
}
.avatar-icon {
font-size: 56px;
}
.user-name {
font-size: 40px;
font-weight: 800;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
}
.user-level {
font-size: 24px;
color: var(--text-secondary);
display: block;
}
/* 5状态快捷入口 - 2+3布局 */
.status-grid {
background: var(--bg-card);
border: 1rpx solid var(--border);
border-radius: 20px;
overflow: hidden;
}
.status-row {
.profile-page .avatar-icon-img {
width: 44rpx;
height: 44rpx;
}
.profile-page .user-meta {
flex: 1;
min-width: 0;
}
.profile-page .user-name {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 36rpx;
font-weight: 700;
line-height: 1.2;
color: var(--text-primary);
margin-bottom: 8rpx;
}
.profile-page .user-level {
display: block;
font-size: 24rpx;
line-height: 1.4;
color: var(--text-secondary);
}
/* 5 状态快捷入口 */
.profile-page .status-grid {
display: flex;
flex-direction: column;
border-top: 1rpx solid var(--border);
padding-top: 16rpx;
}
.profile-page .status-row {
display: flex;
align-items: center;
justify-content: space-around;
padding: 20px 0;
}
/* 每组(item + divider)作为一个 flex 单元 */
.status-group {
.profile-page .status-group {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
justify-content: center;
}
.status-item {
.profile-page .status-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 8px 0;
justify-content: center;
flex: 1;
min-height: 112rpx;
padding: 8rpx 0;
transition: transform 0.18s ease;
}
.status-num {
font-size: 36px;
.profile-page .status-item:active {
transform: scale(0.97);
}
.profile-page .status-icon-img {
width: 32rpx;
height: 32rpx;
margin-bottom: 10rpx;
}
.profile-page .status-num {
font-size: 32rpx;
font-weight: 800;
line-height: 1.2;
color: var(--accent-primary);
margin-bottom: 8px;
margin-bottom: 6rpx;
font-variant-numeric: tabular-nums;
}
.status-label {
font-size: 24px;
.profile-page .status-label {
font-size: 24rpx;
line-height: 1.2;
color: var(--text-secondary);
}
.status-divider {
width: 2px;
height: 48px;
.profile-page .status-divider {
width: 1rpx;
height: 56rpx;
background: var(--border);
opacity: 0.25;
flex-shrink: 0;
}
.status-divider-h {
height: 2px;
.profile-page .status-divider-h {
height: 1rpx;
background: var(--border);
opacity: 0.15;
margin: 0 16px;
margin: 4rpx 16rpx 12rpx;
}
/* 菜单网格 */
.menu-grid {
/* 区块标题 */
.profile-page .section-title {
display: block;
margin: 0 0 24rpx;
font-size: 32rpx;
font-weight: 700;
line-height: 1.25;
color: var(--text-primary);
}
/* 功能菜单 */
.profile-page .menu-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 20px;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16rpx;
}
.menu-card {
.profile-page .menu-card {
display: flex;
flex-direction: column;
align-items: center;
padding: 32px 16px;
transition: transform 0.2s;
justify-content: center;
min-height: 148rpx;
padding: 28rpx 16rpx;
border-radius: 24rpx;
box-shadow: var(--shadow-card);
transition: transform 0.2s ease;
}
.menu-card:active {
transform: scale(0.96);
.profile-page .menu-card:active {
transform: scale(0.97);
}
.menu-icon {
font-size: 48px;
margin-bottom: 12px;
.profile-page .menu-icon-img {
width: 44rpx;
height: 44rpx;
margin-bottom: 16rpx;
}
.menu-label {
font-size: 26px;
color: var(--text-primary);
font-weight: 500;
}
/* 企业定制 */
.enterprise-section {
padding: 32px;
}
.enterprise-title {
font-size: 30px;
font-weight: 700;
color: var(--text-primary);
.profile-page .menu-label {
display: block;
margin-bottom: 8px;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 26rpx;
font-weight: 600;
line-height: 1.2;
color: var(--text-primary);
}
.enterprise-desc {
font-size: 24px;
/* 企业定制入口 */
.profile-page .enterprise-section {
padding: 28rpx 32rpx;
margin: 0 0 48rpx;
}
.profile-page .enterprise-icon {
width: 32rpx;
height: 32rpx;
margin-right: 12rpx;
flex-shrink: 0;
}
.profile-page .enterprise-title {
display: block;
font-size: 30rpx;
font-weight: 700;
line-height: 1.3;
color: var(--text-primary);
margin-bottom: 6rpx;
}
.profile-page .enterprise-desc {
display: block;
font-size: 24rpx;
line-height: 1.4;
color: var(--text-secondary);
}
.enterprise-btn {
padding: 16px 32px !important;
font-size: 26px !important;
border-radius: 40px !important;
.profile-page .enterprise-btn {
display: flex;
align-items: center;
justify-content: center;
height: 80rpx;
padding: 0 32rpx;
font-size: 26rpx;
font-weight: 600;
line-height: 1.2;
border-radius: 999rpx;
flex-shrink: 0;
}
.menu-icon-img {
width: 36px;
height: 36px;
margin-bottom: 12px;
}
/* 状态 icon 图片 */
.status-icon-img {
width: 28px;
height: 28px;
margin-bottom: 4px;
}
/* 企业定制icon */
.enterprise-icon {
width: 28px;
height: 28px;
margin-right: 12px;
}
/* 头像占位图 */
.avatar-icon-img {
width: 36px;
height: 36px;
}
/* 登录弹窗头像占位 */
.avatar-placeholder-img {
width: 56px;
height: 56px;
}
.modal-overlay {
/* 登录弹窗 */
.profile-page .modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 48px;
padding: 48rpx;
}
.login-card {
.profile-page .login-card {
width: 100%;
max-width: 600px;
padding: 40px;
max-width: 640rpx;
padding: 40rpx;
text-align: center;
border-radius: 32rpx;
}
.login-title {
font-size: 36px;
.profile-page .login-title {
display: block;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 12px;
margin-bottom: 12rpx;
}
.login-desc {
font-size: 26px;
.profile-page .login-desc {
display: block;
font-size: 26rpx;
color: var(--text-secondary);
display: block;
margin-bottom: 32px;
margin-bottom: 32rpx;
}
.avatar-btn {
width: 160px;
height: 160px;
.profile-page .avatar-btn {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
margin: 0 auto 24px;
margin: 0 auto 24rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
display: flex;
@@ -250,39 +278,46 @@
font-size: 0;
}
.avatar-img {
.profile-page .avatar-img {
width: 100%;
height: 100%;
border-radius: 50%;
}
.avatar-placeholder {
font-size: 24px;
color: var(--text-secondary);
.profile-page .avatar-placeholder-img {
width: 64rpx;
height: 64rpx;
}
.nickname-input {
.profile-page .nickname-input {
width: 100%;
height: 80px;
height: 88rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
border-radius: 16px;
padding: 0 24px;
font-size: 28px;
border-radius: 16rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: var(--text-primary);
margin-bottom: 32px;
margin-bottom: 32rpx;
text-align: center;
box-sizing: border-box;
}
.login-actions {
.profile-page .login-actions {
display: flex;
gap: 20px;
gap: 20rpx;
}
.login-actions .btn-secondary,
.login-actions .btn-primary {
.profile-page .login-actions .btn-secondary,
.profile-page .login-actions .btn-primary {
flex: 1;
padding: 20px 0;
display: flex;
align-items: center;
justify-content: center;
height: 88rpx;
padding: 0;
font-size: 28rpx;
font-weight: 600;
text-align: center;
border-radius: 999rpx;
}
+1 -3
View File
@@ -282,7 +282,7 @@ export default function ProfilePage() {
<View className='profile-page'>
{/* 用户信息头部 */}
<View className='profile-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='profile-header surface-card' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='user-info'>
{isLoggedIn && userInfo.avatarUrl ? (
<Image className='avatar' src={userInfo.avatarUrl} mode='aspectFill' />
@@ -360,8 +360,6 @@ export default function ProfilePage() {
</View>
</View>
<View style={{ height: '40px' }} />
{/* 登录弹窗 */}
{showLogin && (
<View className='modal-overlay'>
+149 -62
View File
@@ -1,121 +1,208 @@
/* ============================================================
Service Page — 客服中心
============================================================ */
.service-page {
padding: 0 24px 24px;
padding: 0 32rpx calc(24rpx + env(safe-area-inset-bottom));
min-height: 100vh;
box-sizing: border-box;
}
.page-header {
padding: 32px 32px 24px;
margin: 20px 0 0;
.service-page .page-header.service-header {
margin: 0;
padding-left: 0;
padding-right: 0;
padding-bottom: 32rpx;
text-align: center;
}
/* 客服英雄区 */
.service-header .page-title {
font-size: 44rpx;
font-weight: 700;
line-height: 1.2;
color: var(--text-primary);
letter-spacing: 0;
}
/* 客服主入口 */
.service-hero {
display: flex;
flex-direction: column;
align-items: center;
padding: 56rpx 40rpx;
text-align: center;
padding: 50px 40px;
}
.service-hero-icon {
width: 56px;
height: 56px;
margin-bottom: 20px;
width: 88rpx;
height: 88rpx;
margin-bottom: 24rpx;
}
.service-title {
font-size: 36px;
display: block;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 12px;
margin-bottom: 12rpx;
letter-spacing: 0;
}
.service-desc {
font-size: 24px;
color: var(--text-secondary);
display: block;
margin-bottom: 32px;
font-size: 24rpx;
line-height: 1.5;
color: var(--text-secondary);
margin-bottom: 32rpx;
}
.service-btn {
padding: 24px 56px !important;
font-size: 30px !important;
border-radius: 50px !important;
display: flex;
align-items: center;
justify-content: center;
min-width: 280rpx;
height: 80rpx;
padding: 0 48rpx;
box-sizing: border-box;
font-size: 28rpx;
font-weight: 600;
}
/* 联系方式 */
.contact-list {
display: flex;
flex-direction: column;
gap: 20px;
.service-page .section-title {
display: block;
margin-bottom: 24rpx;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
}
.contact-list.surface-card {
padding: 0 32rpx;
overflow: hidden;
}
.contact-item {
display: flex;
align-items: center;
padding: 28px 32px;
min-height: 112rpx;
padding: 24rpx 0;
border-bottom: 1rpx solid var(--border);
}
.contact-icon {
font-size: 48px;
margin-right: 24px;
.contact-item:last-child {
border-bottom: none;
}
.contact-item-link {
transition: background 160ms ease;
}
.contact-item-link:active {
background: var(--bg-muted);
}
.contact-icon-img {
width: 32px;
height: 32px;
margin-right: 24px;
width: 48rpx;
height: 48rpx;
margin-right: 24rpx;
flex-shrink: 0;
}
.contact-info {
flex: 1;
}
.contact-label {
font-size: 24px;
color: var(--text-secondary);
display: block;
margin-bottom: 4px;
}
.contact-value {
font-size: 30px;
font-weight: 600;
color: var(--text-primary);
min-width: 0;
}
/* FAQ */
.faq-card {
margin-bottom: 20px;
padding: 28px 32px;
}
.faq-q {
font-size: 30px;
font-weight: 700;
color: var(--text-primary);
.contact-label {
display: block;
margin-bottom: 12px;
font-size: 24rpx;
line-height: 1.4;
color: var(--text-secondary);
margin-bottom: 4rpx;
}
.contact-value {
display: block;
font-size: 28rpx;
font-weight: 600;
color: var(--text-primary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.contact-arrow {
flex-shrink: 0;
margin-left: 16rpx;
font-size: 32rpx;
line-height: 1;
color: var(--text-muted);
}
/* 常见问题 */
.faq-card {
display: block;
margin-bottom: 24rpx;
padding: 32rpx;
}
.faq-q {
display: block;
font-size: 30rpx;
font-weight: 700;
line-height: 1.45;
color: var(--text-primary);
margin-bottom: 12rpx;
letter-spacing: 0;
}
.faq-a {
font-size: 26px;
display: block;
font-size: 26rpx;
line-height: 1.7;
color: var(--text-secondary);
line-height: 1.6;
}
/* 企业专属 */
.enterprise-service {
padding: 32px;
padding: 32rpx;
}
.enterprise-service .flex-center {
justify-content: flex-start;
margin-bottom: 12rpx;
}
.enterprise-icon {
width: 28px;
height: 28px;
margin-right: 12px;
width: 40rpx;
height: 40rpx;
margin-right: 12rpx;
flex-shrink: 0;
}
.enterprise-title {
font-size: 30px;
display: block;
font-size: 30rpx;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
letter-spacing: 0;
}
.enterprise-desc {
font-size: 24px;
color: var(--text-secondary);
margin-bottom: 24px;
display: block;
font-size: 24rpx;
line-height: 1.6;
color: var(--text-secondary);
margin-bottom: 24rpx;
}
.enterprise-btn {
display: flex;
align-items: center;
justify-content: center;
height: 80rpx;
font-size: 28rpx;
font-weight: 600;
}
+8 -7
View File
@@ -23,12 +23,12 @@ export default function ServicePage() {
<View className={`theme-${resolvedTheme}`} style={{ minHeight: '100vh' }}>
<ThemedPageMeta />
<View className='service-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header service-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<Text className='page-title'></Text>
</View>
{/* 客服入口 */}
<View className='service-hero surface-card mt-20'>
<View className='service-hero surface-card'>
<Image className='service-hero-icon' src={assetUrl('/icon/电话.png')} mode='aspectFit' />
<Text className='service-title'></Text>
<Text className='service-desc'> 09:00 - 18:00 线</Text>
@@ -40,22 +40,23 @@ export default function ServicePage() {
{/* 联系方式 */}
<View className='mt-20'>
<Text className='section-title'></Text>
<View className='contact-list'>
<View className='contact-item surface-card'>
<View className='contact-list surface-card'>
<View className='contact-item'>
<Image className='contact-icon-img' src={assetUrl('/icon/电话.png')} mode='aspectFit' />
<View className='contact-info'>
<Text className='contact-label'></Text>
<Text className='contact-value'>400-XXX-XXXX</Text>
</View>
</View>
<View className='contact-item surface-card' onTap={() => Taro.setClipboardData({ data: 'smart_engraving' })}>
<View className='contact-item contact-item-link' onTap={() => Taro.setClipboardData({ data: 'smart_engraving' })}>
<Image className='contact-icon-img' src={assetUrl('/icon/词云生成.png')} mode='aspectFit' />
<View className='contact-info'>
<Text className='contact-label'></Text>
<Text className='contact-value'>smart_engraving</Text>
</View>
<Text className='contact-arrow'></Text>
</View>
<View className='contact-item surface-card'>
<View className='contact-item'>
<Image className='contact-icon-img' src={assetUrl('/icon/使用帮助.png')} mode='aspectFit' />
<View className='contact-info'>
<Text className='contact-label'></Text>
@@ -88,7 +89,7 @@ export default function ServicePage() {
</View>
</View>
<View style={{ height: '40px' }} />
<View style={{ height: '80rpx' }} />
</View>
</View>
)
+271 -76
View File
@@ -1,60 +1,223 @@
/* ============================================================
Settings Page — 设置
============================================================ */
.settings-page {
padding: 0 24px 24px;
}
.settings-area {
padding-top: calc(env(safe-area-inset-top, 0px));
padding: 0 32rpx calc(24rpx + env(safe-area-inset-bottom));
min-height: 100vh;
box-sizing: border-box;
}
/* 顶部导航 */
.page-header.settings-header {
display: flex;
align-items: center;
gap: 16rpx;
min-height: 88rpx;
padding-left: 0;
padding-right: 0;
padding-bottom: 24rpx;
margin: 0;
}
.settings-header .back-btn {
display: flex;
align-items: center;
justify-content: center;
width: 88rpx;
height: 88rpx;
flex: 0 0 auto;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
box-sizing: border-box;
}
.settings-header .back-btn:active {
transform: scale(0.96);
}
.settings-header .back-arrow {
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
}
.settings-header .page-title {
flex: 1;
min-width: 0;
text-align: center;
font-size: 34rpx;
font-weight: 600;
color: var(--text-primary);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
letter-spacing: 0;
}
.header-spacer {
width: 88rpx;
flex: 0 0 auto;
}
/* 用户卡片 */
.settings-user {
padding: 24px;
padding: 32rpx;
margin-top: 24rpx;
}
.settings-user .flex-center {
flex: 1;
min-width: 0;
justify-content: flex-start;
}
.settings-avatar {
width: 100px;
height: 100px;
width: 112rpx;
height: 112rpx;
border-radius: 50%;
border: 1rpx solid var(--border);
background: var(--bg-input);
flex-shrink: 0;
}
.settings-avatar-placeholder {
width: 100px;
height: 100px;
width: 112rpx;
height: 112rpx;
border-radius: 50%;
background: var(--bg-input);
border: 1rpx solid var(--border);
display: flex;
align-items: center;
justify-content: center;
padding: 30px;
padding: 24rpx;
box-sizing: border-box;
flex-shrink: 0;
}
.settings-avatar-icon {
width: 64rpx;
height: 64rpx;
}
.settings-meta {
flex: 1;
min-width: 0;
margin-left: 24rpx;
}
.settings-name {
font-size: 32px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
font-size: 32rpx;
font-weight: 700;
line-height: 1.3;
color: var(--text-primary);
margin-bottom: 8rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.settings-id {
font-size: 24px;
display: block;
font-size: 24rpx;
line-height: 1.4;
color: var(--text-secondary);
}
.arrow {
font-size: 36px;
flex-shrink: 0;
font-size: 36rpx;
line-height: 1;
color: var(--text-muted);
}
/* 外观设置 */
.settings-section {
padding: 32rpx;
margin-top: 24rpx;
}
.section-label {
display: block;
font-size: 28rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 24rpx;
letter-spacing: 0;
}
.theme-options {
display: flex;
gap: 8rpx;
padding: 8rpx;
border-radius: 999rpx;
background: var(--bg-muted);
box-sizing: border-box;
}
.theme-option {
flex: 1;
min-width: 0;
height: 80rpx;
padding: 0 16rpx;
border-radius: 999rpx;
background: transparent;
border: 1rpx solid transparent;
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
color: var(--text-secondary);
font-size: 26rpx;
font-weight: 500;
transition: background 160ms ease, border-color 160ms ease, color 160ms ease, box-shadow 160ms ease;
box-sizing: border-box;
}
.theme-option.active {
background: var(--bg-card);
border-color: var(--border-strong);
color: var(--text-primary);
font-weight: 600;
box-shadow: var(--shadow-card);
}
.theme-option-text {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.theme-check {
width: 16rpx;
height: 16rpx;
border-radius: 50%;
background: var(--accent-primary);
flex-shrink: 0;
}
.theme-hint {
display: block;
text-align: center;
margin-top: 24rpx;
font-size: 24rpx;
color: var(--text-secondary);
}
/* 菜单列表 */
.settings-list {
padding: 0 24px;
padding: 0 32rpx;
margin-top: 24rpx;
}
.settings-item {
display: flex;
align-items: center;
padding: 28px 0;
min-height: 112rpx;
padding: 24rpx 0;
}
.settings-item.bordered {
@@ -62,83 +225,115 @@
}
.settings-item-icon-img {
width: 32px;
height: 32px;
margin-right: 16px;
width: 48rpx;
height: 48rpx;
margin-right: 24rpx;
flex-shrink: 0;
}
.settings-item-label {
flex: 1;
font-size: 30px;
color: var(--text-primary);
}
.logout-btn {
text-align: center;
padding: 24px 0;
color: var(--danger);
border: 1rpx solid var(--danger);
}
/* --- 主题选择 --- */
.settings-section {
padding: 32px;
}
.section-label {
font-size: 30px;
min-width: 0;
font-size: 30rpx;
font-weight: 600;
color: var(--text-primary);
display: block;
margin-bottom: 24px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.theme-options {
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.theme-option {
flex: 1;
min-width: 160px;
padding: 24px 16px;
border-radius: 20px;
background: var(--bg-input);
border: 1rpx solid transparent;
/* 退出登录 */
.logout-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
transition: all 0.2s ease;
height: 88rpx;
font-size: 28rpx;
font-weight: 600;
color: var(--danger);
border: 1rpx solid var(--danger);
background: transparent;
box-sizing: border-box;
}
.theme-option.active {
border-color: var(--accent-primary);
background: var(--accent-primary-soft);
/* 编辑弹窗 */
.settings-page .modal-overlay {
align-items: center;
justify-content: center;
padding: 48rpx;
z-index: 1000;
}
.theme-option-text {
font-size: 28px;
color: var(--text-primary);
font-weight: 500;
.settings-page .modal-card {
width: 100%;
max-width: 640rpx;
padding: 40rpx;
border-radius: 32rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
box-shadow: var(--shadow-elevated);
box-sizing: border-box;
}
.theme-check {
width: 16px;
height: 16px;
border-radius: 50%;
background: var(--accent-primary);
}
.theme-hint {
font-size: 24px;
color: var(--text-secondary);
margin-top: 20px;
.settings-page .modal-title {
display: block;
text-align: center;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 32rpx;
letter-spacing: 0;
}
/* 弹窗复用 address 弹窗和 profile 弹窗样式 */
.avatar-btn {
width: 128rpx;
height: 128rpx;
margin: 0 auto 32rpx;
padding: 0;
border-radius: 50%;
border: 1rpx solid var(--border);
background: var(--bg-input);
line-height: 1;
overflow: hidden;
}
.avatar-img,
.avatar-placeholder-img {
width: 100%;
height: 100%;
}
.nickname-input {
width: 100%;
height: 88rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
border-radius: 16rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: var(--text-primary);
box-sizing: border-box;
}
.nickname-input::placeholder {
color: var(--text-muted);
font-size: 26rpx;
}
.form-actions {
display: flex;
gap: 20rpx;
margin-top: 32rpx;
}
.form-actions .btn-secondary,
.form-actions .btn-primary {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
height: 80rpx;
font-size: 28rpx;
font-weight: 600;
box-sizing: border-box;
}
+7 -7
View File
@@ -72,12 +72,12 @@ export default function SettingsPage() {
<View className='settings-page'>
<View className='settings-area'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='flex-between' style={{ width: '100%' }}>
<Text className='back-btn' onTap={() => Taro.navigateBack()}></Text>
<Text className='page-title'></Text>
<View style={{ width: '60px' }} />
<View className='page-header settings-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='page-title'></Text>
<View className='header-spacer' />
</View>
{/* 用户卡片 */}
@@ -91,7 +91,7 @@ export default function SettingsPage() {
<Image className='settings-avatar-icon' src={assetUrl('/icon/个人.png')} mode='aspectFit' />
</View>
)}
<View style={{ marginLeft: '20px' }}>
<View className='settings-meta'>
<Text className='settings-name'>{user.nickName || '未登录'}</Text>
<Text className='settings-id'>ID: {user.openid ? user.openid.slice(-8) : '---'}</Text>
</View>
@@ -140,7 +140,7 @@ export default function SettingsPage() {
</View>
)}
<View style={{ height: '40px' }} />
<View style={{ height: '80rpx' }} />
{/* 编辑弹窗 */}
{showEdit && (
+73 -45
View File
@@ -9,7 +9,7 @@
left: 0;
right: 0;
bottom: 0;
background: rgb(28, 22, 18);
background: var(--bg-page);
}
/* --- Fixed Hero Area --- */
@@ -18,7 +18,7 @@
top: 0;
left: 0;
width: 100%;
height: 65vh; /* hero takes 65% viewport height */
height: 65vh;
z-index: 0;
overflow: hidden;
}
@@ -56,22 +56,22 @@
left: 0;
right: 0;
z-index: 2;
padding: 80rpx 40rpx 24rpx;
padding: 96rpx 40rpx calc(24rpx + env(safe-area-inset-bottom));
display: flex;
flex-direction: column;
gap: 8rpx;
}
.shop-hero-title {
font-size: 40rpx;
font-size: 44rpx;
font-weight: 700;
line-height: 1.3;
color: #f0e6d8;
color: var(--text-primary);
}
.shop-hero-subtitle {
font-size: 22rpx;
color: #b0a395;
font-size: 24rpx;
color: var(--text-secondary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -92,7 +92,7 @@
.shop-hero-original {
font-size: 26rpx;
color: #8a7e72;
color: var(--text-muted);
text-decoration: line-through;
}
@@ -103,7 +103,7 @@
}
.shop-content {
min-height: 100vh; /* ensure scrollability */
min-height: 100vh;
will-change: transform;
}
@@ -113,7 +113,7 @@
position: sticky;
top: 0;
z-index: 4;
padding: 40rpx 40rpx 32rpx;
padding: 24rpx 40rpx 24rpx;
display: flex;
flex-direction: column;
gap: 10rpx;
@@ -122,15 +122,15 @@
}
.shop-band-title {
font-size: 44rpx;
font-size: 40rpx;
font-weight: 700;
line-height: 1.3;
color: #f0e6d8;
color: var(--text-primary);
}
.shop-band-subtitle {
font-size: 24rpx;
color: #b0a395;
color: var(--text-secondary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -144,59 +144,74 @@
}
.shop-band-price {
font-size: 48rpx;
font-size: 40rpx;
font-weight: 700;
color: var(--accent-primary);
}
.shop-band-original {
font-size: 26rpx;
color: #8a7e72;
color: var(--text-muted);
text-decoration: line-through;
}
/* --- Detail Body --- */
.shop-detail-body {
padding: 32rpx 40rpx 60rpx;
padding: 0 32rpx calc(48rpx + env(safe-area-inset-bottom));
will-change: opacity, transform;
box-sizing: border-box;
}
.shop-content-card {
padding: 32rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
border-radius: 32rpx;
box-shadow: var(--shadow-card);
box-sizing: border-box;
}
.shop-section {
margin-bottom: 32rpx;
}
.shop-section:last-child {
margin-bottom: 0;
}
.shop-section-title {
font-size: 34rpx;
font-weight: 700;
color: #f0e6d8;
margin: 28rpx 0 20rpx;
color: var(--text-primary);
margin: 0 0 20rpx;
display: block;
position: relative;
padding-left: 20rpx;
letter-spacing: 0;
}
.shop-section-title::before {
content: '';
position: absolute;
left: 0;
top: 6rpx;
bottom: 6rpx;
top: 8rpx;
bottom: 8rpx;
width: 6rpx;
border-radius: 4rpx;
background: linear-gradient(180deg, var(--accent-primary), var(--accent-primary-soft));
border-radius: 999rpx;
background: var(--accent-primary);
}
.shop-section-text {
font-size: 28rpx;
color: #c4b8a8;
line-height: 1.75;
color: var(--text-secondary);
line-height: 1.8;
display: block;
}
.shop-divider {
height: 2rpx;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.08), transparent);
margin: 40rpx 0;
height: 1rpx;
background: var(--border);
margin: 32rpx 0;
}
/* --- Tags --- */
@@ -208,10 +223,11 @@
}
.shop-tag {
padding: 10rpx 28rpx;
border-radius: 40rpx;
height: 56rpx;
padding: 0 28rpx;
border-radius: 999rpx;
font-size: 22rpx;
font-weight: 500;
font-weight: 600;
background: var(--accent-primary-soft);
border: 1rpx solid var(--accent-primary);
display: inline-flex;
@@ -226,16 +242,16 @@
/* --- Spec Table --- */
.shop-spec-table {
width: 100%;
border-collapse: collapse;
border-radius: 16rpx;
border: 1rpx solid var(--border);
border-radius: 20rpx;
overflow: hidden;
font-size: 26rpx;
background: var(--bg-muted);
}
.shop-spec-row {
display: flex;
padding: 20rpx 24rpx;
border-bottom: 1rpx solid rgba(255,255,255,0.06);
padding: 24rpx 28rpx;
border-bottom: 1rpx solid var(--border);
}
.shop-spec-row:last-child {
@@ -244,14 +260,16 @@
.shop-spec-key {
width: 35%;
color: #8a7e72;
color: var(--text-muted);
font-weight: 500;
font-size: 24rpx;
}
.shop-spec-val {
flex: 1;
color: #e8e0d6;
color: var(--text-primary);
font-size: 26rpx;
font-weight: 500;
word-break: break-all;
}
@@ -268,11 +286,11 @@
width: 88rpx;
height: 88rpx;
border-radius: 50%;
background: rgba(0, 0, 0, 0.35);
backdrop-filter: blur(16rpx) saturate(1.4);
-webkit-backdrop-filter: blur(16rpx) saturate(1.4);
border: 1rpx solid rgba(255,255,255,0.12);
box-shadow: var(--shadow-card);
background: rgba(40, 35, 32, 0.5);
backdrop-filter: blur(16px) saturate(1.4);
-webkit-backdrop-filter: blur(16px) saturate(1.4);
border: 1rpx solid var(--glass-line);
box-shadow: var(--shadow-elevated);
display: flex;
align-items: center;
justify-content: center;
@@ -285,15 +303,25 @@
.shop-back-arrow {
font-size: 36rpx;
color: rgba(255,255,255,0.85);
color: var(--text-primary);
line-height: 1;
}
/* --- Bottom Action Bar — 样式由全局 .action-bar 提供,本地只补充价格摘要 --- */
.action-bar .price-summary {
/* --- Bottom Action Bar — 毛玻璃由 BottomActionBar 提供,本地只补充价格摘要 --- */
.bottom-action-bar .price-summary {
flex-shrink: 0;
}
.bottom-action-bar .btn-primary,
.bottom-action-bar .btn-secondary {
flex: 1;
text-align: center;
padding: 28rpx 0;
font-size: 28rpx;
font-weight: 600;
line-height: 1.2;
}
.summary-label {
font-size: 22rpx;
color: var(--text-secondary);
+53 -42
View File
@@ -8,6 +8,7 @@ import { useSafeArea } from '../../../hooks/useSafeArea'
import { useStatusBar } from '../../../hooks/useStatusBar'
import { useThemeContext } from '../../../context/ThemeContext'
import ThemedPageMeta from '../../../components/ThemedPageMeta'
import BottomActionBar from '../../../components/BottomActionBar'
const clamp = (v: number, min: number, max: number) => Math.min(Math.max(v, min), max)
const lerp = (a: number, b: number, t: number) => a + (b - a) * t
@@ -210,49 +211,59 @@ export default function ShopDetailPage() {
transform: `translateY(${heroStyles.contentOffset}px)`
}}
>
{product.story && (
<View className="shop-section">
<Text className="shop-section-title"></Text>
<Text className="shop-section-text">{product.story}</Text>
</View>
)}
<View className="shop-divider" />
{product.scene && (
<View className="shop-section">
<Text className="shop-section-title">使</Text>
<Text className="shop-section-text">{product.scene}</Text>
</View>
)}
{product.tags && product.tags.length > 0 && (
<View className="shop-section">
<View className="shop-tag-row">
{product.tags.map(tag => (
<View key={tag} className="shop-tag">
<Text className="shop-tag-text">{tag}</Text>
</View>
))}
<View className="shop-content-card">
{product.story && (
<View className="shop-section">
<Text className="shop-section-title"></Text>
<Text className="shop-section-text">{product.story}</Text>
</View>
</View>
)}
)}
<View className="shop-divider" />
{(product.story && product.scene) && (
<View className="shop-divider" />
)}
{product.specs && product.specs.length > 0 && (
<View className="shop-section">
<Text className="shop-section-title"></Text>
<View className="shop-spec-table">
{product.specs.map(([k, v]) => (
<View key={k} className="shop-spec-row">
<Text className="shop-spec-key">{k}</Text>
<Text className="shop-spec-val">{v}</Text>
</View>
))}
{product.scene && (
<View className="shop-section">
<Text className="shop-section-title">使</Text>
<Text className="shop-section-text">{product.scene}</Text>
</View>
</View>
)}
)}
{product.tags && product.tags.length > 0 && (
<View className="shop-section">
<View className="shop-tag-row">
{product.tags.map(tag => (
<View key={tag} className="shop-tag">
<Text className="shop-tag-text">{tag}</Text>
</View>
))}
</View>
</View>
)}
{((product.story || product.scene) && product.tags && product.tags.length > 0) && (
<View className="shop-divider" />
)}
{((product.story || product.scene || (product.tags && product.tags.length > 0)) && product.specs && product.specs.length > 0) && (
<View className="shop-divider" />
)}
{product.specs && product.specs.length > 0 && (
<View className="shop-section">
<Text className="shop-section-title"></Text>
<View className="shop-spec-table">
{product.specs.map(([k, v]) => (
<View key={k} className="shop-spec-row">
<Text className="shop-spec-key">{k}</Text>
<Text className="shop-spec-val">{v}</Text>
</View>
))}
</View>
</View>
)}
</View>
<View className="shop-bottom-spacer" />
</View>
@@ -268,8 +279,8 @@ export default function ShopDetailPage() {
<Text className="shop-back-arrow"></Text>
</View>
{/* Bottom CTA — 全局毛玻璃 action-bar,沿用 product/checkout 模式 */}
<View className="action-bar">
{/* Bottom CTA — 复用毛玻璃 BottomActionBar */}
<BottomActionBar>
<View className="price-summary">
<Text className="summary-label"></Text>
<Text className="summary-price">¥{product.price}</Text>
@@ -283,7 +294,7 @@ export default function ShopDetailPage() {
<View className="btn-primary" onTap={() => Taro.navigateTo({ url: `/pages/product/index?id=${product.id}` })}>
<Text></Text>
</View>
</View>
</BottomActionBar>
<View className="safe-bottom-placeholder" />
</View>
)
+29 -16
View File
@@ -4,19 +4,19 @@
/* --- List Layer --- */
.shop-list {
padding: 0 24rpx 24rpx;
padding: 0 32rpx 24rpx;
}
.shop-header {
text-align: center;
padding: 40rpx 0 24rpx;
padding: 48rpx 0 32rpx;
}
.shop-header-title {
font-size: 40rpx;
font-weight: 800;
font-size: 44rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 4rpx;
letter-spacing: 0;
display: block;
}
@@ -31,10 +31,11 @@
.shop-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20rpx;
gap: 24rpx;
}
.shop-card {
border: 1rpx solid var(--border);
border-radius: 24rpx;
overflow: hidden;
background: var(--bg-card);
@@ -43,13 +44,13 @@
}
.shop-card:active {
transform: scale(0.97);
transform: scale(0.98);
}
.shop-card-img-wrap {
aspect-ratio: 3 / 4;
aspect-ratio: 1 / 1;
overflow: hidden;
background: #2a2218;
background: var(--bg-muted);
}
.shop-card-img {
@@ -59,27 +60,39 @@
transition: transform 0.4s ease;
}
.shop-card-info {
padding: 16rpx 20rpx 20rpx;
.shop-card-body {
padding: 20rpx 24rpx 24rpx;
}
.shop-card-name {
font-size: 26rpx;
color: #e8e0d6;
font-size: 28rpx;
font-weight: 700;
color: var(--text-primary);
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
min-height: 74rpx;
}
.shop-card-desc {
font-size: 24rpx;
color: var(--text-secondary);
line-height: 1.4;
margin-top: 8rpx;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.shop-card-price {
font-size: 30rpx;
font-size: 32rpx;
font-weight: 700;
color: var(--accent-primary);
margin-top: 10rpx;
margin-top: 12rpx;
display: block;
font-variant: tabular-nums;
}
/* ============================================================
+2 -9
View File
@@ -27,7 +27,6 @@ export default function ShopPage() {
<View className="shop-grid">
{PRODUCTS.map(product => {
const tone = product.tone || [28, 22, 18]
const imageSrc = product.images[0] || product.iconImg || ''
return (
<View
@@ -43,13 +42,9 @@ export default function ShopPage() {
lazyLoad
/>
</View>
<View
className="shop-card-info"
style={{
backgroundColor: `rgba(${tone[0]}, ${tone[1]}, ${tone[2]}, 0.92)`
}}
>
<View className="shop-card-body">
<Text className="shop-card-name">{product.name}</Text>
<Text className="shop-card-desc">{product.desc || ''}</Text>
<Text className="shop-card-price">¥{product.price}</Text>
</View>
</View>
@@ -57,8 +52,6 @@ export default function ShopPage() {
})}
</View>
{/* TabBar spacer so list isn't obscured */}
<View style={{ height: '200px' }} />
</View>
</View>
)
+134 -57
View File
@@ -1,90 +1,140 @@
/* ============================================================
UserDatabase Page — 本地用户数据库
============================================================ */
.udb-page {
padding: 0 24px 40px;
padding: 0 32rpx calc(24rpx + env(safe-area-inset-bottom));
min-height: 100vh;
box-sizing: border-box;
}
/* 锁屏验证 */
.udb-lock-page {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.udb-lock-card {
display: flex;
flex-direction: column;
align-items: center;
padding: 60px 40px;
padding: 64rpx 40rpx;
text-align: center;
margin-top: 48rpx;
}
.udb-lock-icon {
width: 80px;
height: 80px;
margin-bottom: 24px;
width: 96rpx;
height: 96rpx;
margin-bottom: 24rpx;
}
.udb-lock-title {
font-size: 36px;
display: block;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 12px;
display: block;
margin-bottom: 12rpx;
letter-spacing: 0;
}
.udb-lock-desc {
font-size: 26px;
color: var(--text-secondary);
margin-bottom: 32px;
display: block;
font-size: 26rpx;
line-height: 1.6;
color: var(--text-secondary);
margin-bottom: 32rpx;
}
.udb-password-input {
width: 100%;
height: 80px;
height: 88rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
border-radius: 16px;
padding: 0 24px;
font-size: 30px;
border-radius: 16rpx;
padding: 0 24rpx;
box-sizing: border-box;
font-size: 30rpx;
color: var(--text-primary);
text-align: center;
margin-bottom: 24px;
box-sizing: border-box;
margin-bottom: 24rpx;
}
.udb-password-input::placeholder {
color: var(--text-muted);
}
.udb-error {
font-size: 24px;
color: var(--danger);
margin-bottom: 20px;
display: block;
font-size: 24rpx;
line-height: 1.5;
color: var(--danger);
margin-bottom: 20rpx;
}
.udb-btn {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 20px 0;
font-size: 30px;
height: 96rpx;
box-sizing: border-box;
font-size: 30rpx;
font-weight: 600;
}
/* 顶部标题 */
.page-header.udb-header {
min-height: 88rpx;
padding-left: 0;
padding-right: 0;
padding-bottom: 24rpx;
margin: 0;
}
.udb-header .page-title {
text-align: center;
font-size: 44rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
}
/* 工具栏 */
.udb-toolbar {
margin: 20px 0;
display: flex;
justify-content: flex-end;
margin: 8rpx 0 24rpx;
}
.udb-add-btn {
padding: 14px 28px;
font-size: 26px;
display: flex;
align-items: center;
justify-content: center;
height: 80rpx;
padding: 0 32rpx;
box-sizing: border-box;
font-size: 26rpx;
font-weight: 600;
}
/* 数据表格 */
.udb-table {
background: var(--bg-card);
border: 1rpx solid var(--border);
border-radius: 24px;
border-radius: 24rpx;
overflow: hidden;
box-shadow: var(--shadow-card);
}
.udb-row {
display: flex;
align-items: center;
padding: 20px 16px;
min-height: 112rpx;
padding: 16rpx 24rpx;
border-bottom: 1rpx solid var(--border);
box-sizing: border-box;
}
.udb-row:last-child {
@@ -93,31 +143,31 @@
.udb-header {
background: var(--bg-input);
padding: 16px;
min-height: 80rpx;
}
.udb-header .udb-col {
font-weight: 700;
font-size: 24px;
font-size: 24rpx;
color: var(--text-primary);
}
.udb-col {
font-size: 24px;
font-size: 24rpx;
color: var(--text-secondary);
flex-shrink: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding: 0 6px;
padding: 0 8rpx;
}
.col-nick {
flex: 0 0 22%;
flex: 0 0 24%;
}
.col-id {
flex: 0 0 36%;
flex: 0 0 32%;
}
.col-stats {
@@ -127,10 +177,12 @@
.col-action {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
gap: 12rpx;
flex-wrap: wrap;
}
.udb-row.active {
@@ -138,11 +190,13 @@
}
.udb-link {
padding: 6px 14px;
border-radius: 8px;
font-size: 22px;
padding: 10rpx 20rpx;
border-radius: 999rpx;
font-size: 22rpx;
line-height: 1.2;
color: var(--accent-secondary);
background: var(--accent-secondary-soft);
font-weight: 600;
}
.udb-danger {
@@ -151,55 +205,78 @@
}
.udb-current {
font-size: 22px;
font-size: 22rpx;
color: var(--accent-secondary);
font-weight: 600;
font-weight: 700;
}
.udb-empty {
padding: 40px;
padding: 80rpx 24rpx;
text-align: center;
color: var(--text-secondary);
font-size: 28px;
font-size: 28rpx;
}
/* 新建账号弹窗 */
.udb-page .modal-overlay {
align-items: center;
justify-content: center;
padding: 48rpx;
z-index: 1000;
}
/* 弹窗 */
.udb-add-card {
padding: 48px 36px;
width: 80%;
width: 100%;
max-width: 640rpx;
padding: 40rpx;
border-radius: 32rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
box-shadow: var(--shadow-elevated);
box-sizing: border-box;
}
.udb-add-title {
font-size: 32px;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 24px;
display: block;
text-align: center;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 32rpx;
letter-spacing: 0;
}
.udb-add-input {
width: 100%;
height: 80px;
height: 88rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
border-radius: 16px;
padding: 0 24px;
font-size: 28px;
color: var(--text-primary);
margin-bottom: 32px;
border-radius: 16rpx;
padding: 0 24rpx;
box-sizing: border-box;
font-size: 28rpx;
color: var(--text-primary);
margin-bottom: 32rpx;
}
.udb-add-input::placeholder {
color: var(--text-muted);
}
.udb-add-actions {
display: flex;
align-items: center;
gap: 20px;
gap: 20rpx;
}
.udb-add-actions .btn-secondary,
.udb-add-actions .btn-primary {
flex: 1;
padding: 18px 0;
text-align: center;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
font-weight: 600;
box-sizing: border-box;
}
+3 -3
View File
@@ -86,8 +86,8 @@ export default function UserDatabasePage() {
return (
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='udb-page'>
<View className='udb-lock-card surface-card mt-20'>
<View className='udb-page udb-lock-page' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='udb-lock-card surface-card'>
<Image className='udb-lock-icon' src={assetUrl('/icon/账号管理.png')} mode='aspectFit' />
<Text className='udb-lock-title'></Text>
<Text className='udb-lock-desc'>访</Text>
@@ -116,7 +116,7 @@ export default function UserDatabasePage() {
<ThemedPageMeta />
<View className='udb-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header udb-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<Text className='page-title'></Text>
</View>
+218 -99
View File
@@ -1,68 +1,125 @@
/* ============================================================
WordCloud Page — AI 词云生成
============================================================ */
.wordcloud-page {
min-height: 100vh;
padding: 0 24px 24px;
padding: 0 32rpx calc(24rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
}
/* 顶部导航 */
.page-header {
padding: calc(env(safe-area-inset-top, 0px) + 44px) 32px 24px;
margin: 20px 0 0;
.page-header.cloud-header {
display: flex;
align-items: center;
gap: 16rpx;
min-height: 88rpx;
padding-left: 0;
padding-right: 0;
padding-bottom: 24rpx;
margin: 0;
background: transparent;
}
.back-btn {
font-size: 40px;
.cloud-header .back-btn {
display: flex;
align-items: center;
justify-content: center;
width: 88rpx;
height: 88rpx;
flex: 0 0 auto;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
box-sizing: border-box;
}
.cloud-header .back-btn:active {
transform: scale(0.96);
}
.cloud-header .back-arrow {
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
padding: 10px;
}
.cloud-header .page-title {
flex: 1;
min-width: 0;
text-align: center;
font-size: 34rpx;
font-weight: 600;
color: var(--text-primary);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
letter-spacing: 0;
}
.header-spacer {
width: 88rpx;
flex: 0 0 auto;
}
/* 步骤指示器 */
.step-indicator {
display: flex;
align-items: center;
align-items: stretch;
justify-content: center;
padding: 32px;
margin: 0 24px;
padding: 32rpx 16rpx;
margin-bottom: 24rpx;
}
.step-item {
position: relative;
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
flex: 1;
min-width: 0;
}
.step-circle {
width: 64px;
height: 64px;
border-radius: 50%;
background: var(--bg-input);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 12px;
width: 64rpx;
height: 64rpx;
border-radius: 50%;
background: var(--bg-muted);
border: 1rpx solid var(--border);
box-sizing: border-box;
margin-bottom: 12rpx;
transition: background 160ms ease, border-color 160ms ease, box-shadow 160ms ease;
}
.step-circle.active {
background: var(--accent-primary);
border-color: var(--accent-primary);
box-shadow: 0 0 0 8rpx var(--accent-primary-soft);
}
.step-num {
font-size: 28px;
font-size: 28rpx;
font-weight: 700;
line-height: 1;
color: var(--text-muted);
}
.step-circle.active .step-num {
color: #fff;
color: var(--bg-page);
}
.step-label {
font-size: 24px;
max-width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 24rpx;
color: var(--text-secondary);
text-align: center;
}
.step-label.active {
@@ -72,11 +129,12 @@
.step-line {
position: absolute;
top: 30px;
top: 31rpx;
left: 60%;
width: 100%;
height: 4px;
height: 4rpx;
background: var(--bg-input);
border-radius: 999rpx;
}
.step-line.active {
@@ -85,105 +143,144 @@
/* 步骤内容 */
.step-content {
padding: 32px;
padding: 0 0 32rpx;
}
/* 上传区域 */
/* 上传底图 */
.upload-area {
min-height: 400px;
min-height: 420rpx;
display: flex;
align-items: center;
justify-content: center;
border: 1rpx solid var(--border);
border-radius: 24rpx;
overflow: hidden;
}
.upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
padding: 60px;
padding: 64rpx 48rpx;
text-align: center;
}
.upload-icon {
width: 80px;
height: 80px;
margin-bottom: 24px;
width: 80rpx;
height: 80rpx;
margin-bottom: 24rpx;
}
.upload-title {
font-size: 32px;
font-size: 32rpx;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 12px;
margin-bottom: 12rpx;
letter-spacing: 0;
}
.upload-desc {
font-size: 26px;
font-size: 26rpx;
color: var(--text-secondary);
margin-bottom: 16px;
margin-bottom: 24rpx;
}
.upload-tip {
font-size: 22px;
font-size: 22rpx;
line-height: 1.5;
color: var(--accent-secondary);
background: var(--accent-secondary-soft);
padding: 8px 20px;
padding: 12rpx 24rpx;
border-radius: 999rpx;
border: 1rpx solid var(--border);
}
.preview-image {
width: 100%;
height: 400px;
border-radius: 24px;
height: 420rpx;
border-radius: 24rpx;
}
/* 按钮 */
/* 按钮 */
.action-btns {
display: flex;
flex-direction: column;
gap: 20px;
margin-top: 40px;
gap: 20rpx;
margin-top: 32rpx;
}
/* 输入区域 */
.action-btns .btn-primary,
.action-btns .btn-secondary {
display: flex;
align-items: center;
justify-content: center;
height: 96rpx;
font-size: 30rpx;
font-weight: 600;
box-sizing: border-box;
}
/* 输入名单 */
.input-section {
padding: 32px;
border: 1rpx solid var(--border);
border-radius: 24rpx;
padding: 32rpx;
}
.input-section .section-title {
display: block;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 0;
letter-spacing: 0;
}
.names-input {
width: 100%;
min-height: 300px;
min-height: 320rpx;
background: var(--bg-input);
border-radius: 16px;
padding: 24px;
font-size: 28px;
line-height: 1.6;
box-sizing: border-box;
border: 1rpx solid var(--border);
border-radius: 16rpx;
padding: 24rpx;
margin-top: 24rpx;
box-sizing: border-box;
font-size: 28rpx;
line-height: 1.6;
color: var(--text-primary);
transition: border-color 160ms ease, background 160ms ease, box-shadow 160ms ease;
}
.names-input:focus {
border-color: var(--accent-primary);
background: var(--bg-card);
box-shadow: 0 0 0 6rpx var(--accent-primary-soft);
}
.names-input::placeholder {
color: var(--text-muted);
}
.input-stats {
display: block;
text-align: right;
font-size: 24px;
font-size: 24rpx;
color: var(--text-secondary);
margin-top: 12px;
margin-top: 12rpx;
}
.input-tips {
margin-top: 24px;
margin-top: 24rpx;
padding: 24rpx;
border-radius: 16rpx;
background: var(--bg-muted);
}
.tip-item {
display: block;
font-size: 24px;
font-size: 24rpx;
line-height: 1.6;
color: var(--text-secondary);
margin-bottom: 8px;
margin-bottom: 8rpx;
}
.tip-item:last-child {
margin-bottom: 0;
}
/* 生成中 */
@@ -191,133 +288,155 @@
display: flex;
flex-direction: column;
align-items: center;
padding: 80px 40px;
padding: 96rpx 48rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
border-radius: 24rpx;
box-shadow: var(--shadow-card);
}
.generating-icon {
width: 120px;
height: 120px;
width: 104rpx;
height: 104rpx;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.2); opacity: 0.7; }
50% { transform: scale(1.12); opacity: 0.72; }
}
.generating-title {
font-size: 40px;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
margin-top: 40px;
margin-top: 32rpx;
letter-spacing: 0;
}
.generating-subtitle {
font-size: 28px;
font-size: 26rpx;
color: var(--text-secondary);
margin-top: 16px;
margin-bottom: 40px;
margin-top: 12rpx;
margin-bottom: 40rpx;
}
.progress-bar {
width: 80%;
height: 16px;
background: var(--accent-primary-soft);
border-radius: 8px;
width: 100%;
height: 12rpx;
background: var(--bg-muted);
border-radius: 999rpx;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: var(--accent-primary);
border-radius: 8px;
border-radius: 999rpx;
transition: width 0.5s ease;
}
.progress-text {
font-size: 32px;
font-size: 30rpx;
font-weight: 700;
color: var(--accent-primary);
margin-top: 16px;
margin-top: 16rpx;
font-variant: tabular-nums;
}
/* 结果面板 */
/* 结果预览 */
.result-panel {
padding: 20px 0;
padding: 0;
}
.result-image-wrapper {
overflow: hidden;
position: relative;
border: 1rpx solid var(--border);
overflow: hidden;
border-radius: 24rpx;
}
.result-image {
width: 100%;
height: 500px;
background: linear-gradient(135deg, var(--accent-primary-soft) 0%, var(--accent-secondary-soft) 100%);
height: 520rpx;
background: var(--bg-muted);
}
.watermark-badge {
position: absolute;
bottom: 20px;
right: 20px;
right: 24rpx;
bottom: 24rpx;
padding: 10rpx 20rpx;
border-radius: 999rpx;
background: var(--glass);
border: 1rpx solid var(--glass-line);
font-size: 22rpx;
color: var(--text-primary);
padding: 8px 20px;
border-radius: 8px;
font-size: 22px;
border: 1rpx solid var(--border);
backdrop-filter: blur(24rpx);
-webkit-backdrop-filter: blur(24rpx);
}
.result-actions {
display: flex;
justify-content: space-around;
margin: 32px 0;
gap: 16rpx;
margin: 24rpx 0 0;
}
.action-btn {
flex: 1;
min-width: 0;
padding: 24rpx 8rpx;
border-radius: 24rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
box-shadow: var(--shadow-card);
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
gap: 10rpx;
box-sizing: border-box;
}
.action-btn:active {
transform: scale(0.98);
}
.action-icon {
width: 48px;
height: 48px;
margin-bottom: 8px;
width: 44rpx;
height: 44rpx;
}
.action-label {
font-size: 24px;
max-width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 22rpx;
color: var(--text-secondary);
}
/* 跳转DIY卡片 */
/* 跳转DIY卡片(保留旧样式,便于后续扩展) */
.diy-jump-card {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32px;
margin-bottom: 32rpx;
}
.diy-jump-title {
font-size: 32px;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
margin-bottom: 8rpx;
}
.diy-jump-desc {
font-size: 24px;
font-size: 24rpx;
color: var(--text-secondary);
display: block;
}
.diy-jump-arrow {
font-size: 40px;
font-size: 40rpx;
color: var(--accent-primary);
}
+5 -3
View File
@@ -66,10 +66,12 @@ export default function WordCloudPage() {
<ThemedPageMeta />
<View className='wordcloud-page'>
<View className='page-header flex-between' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<Text className='back-btn' onTap={goBack}></Text>
<View className='page-header cloud-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='back-btn' onTap={goBack}>
<Text className='back-arrow'></Text>
</View>
<Text className='page-title'>AI词云生成</Text>
<View style={{ width: '60px' }} />
<View className='header-spacer' />
</View>
{/* 步骤指示器 */}