Files
wechat_wc/src/pages/designList/index.tsx
T

227 lines
8.2 KiB
TypeScript

import { View, Text, ScrollView, Image } from '@tarojs/components'
import Taro from '@tarojs/taro'
import { useState, useEffect, useCallback } from 'react'
import './index.scss'
import { getDesignList, removeDesigns, type DesignItem } from '../../utils/store'
import { PRODUCT_ICON_MAP } from '../../utils/productConfig'
import { assetUrl } from '../../utils/asset'
import { useThemeContext } from '../../context/ThemeContext'
import { useSafeArea } from '../../hooks/useSafeArea'
import { useStatusBar } from '../../hooks/useStatusBar'
import LoginGuard from '../../components/LoginGuard'
import ThemedPageMeta from '../../components/ThemedPageMeta'
const STATUS_TABS = [
{ code: 'all', label: '全部' },
{ code: 'toDesign', label: '待设计' },
{ code: 'undesigned', label: '未设计' },
{ code: 'designing', label: '设计中' },
{ 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' },
ordered: { label: '已下单', cls: 'badge-green' }
}
export default function DesignListPage() {
const { resolvedTheme } = useThemeContext()
const safe = useSafeArea()
useStatusBar(resolvedTheme)
const [activeTab, setActiveTab] = useState('all')
const [list, setList] = useState<DesignItem[]>([])
const [managing, setManaging] = useState(false)
const [selected, setSelected] = useState<Set<string>>(new Set())
const load = useCallback(() => {
setList(getDesignList())
}, [])
const init = useCallback(() => {
const filter = Taro.getStorageSync('designList:filter')
if (filter && STATUS_TABS.some(t => t.code === filter)) {
setActiveTab(filter)
Taro.removeStorageSync('designList:filter')
}
load()
}, [load])
useEffect(() => {
const page = Taro.getCurrentInstance().page
if (page) {
const orig = page.onShow
page.onShow = function () {
init()
if (orig) orig.apply(this)
}
}
init()
}, [init])
const filtered = activeTab === 'all'
? list
: activeTab === 'toDesign'
? list.filter(d => d.status === 'undesigned' || d.status === 'designing')
: list.filter(d => d.status === activeTab)
const goDesign = (item: DesignItem) => {
if (item.status === 'ordered') {
Taro.showToast({ title: '该商品已下单,请查看订单', icon: 'none' })
return
}
Taro.navigateTo({
url: `/pages/diy/index?source=designList&designId=${item.id}`
})
}
const toggleSelect = (id: string) => {
const next = new Set(selected)
if (next.has(id)) next.delete(id)
else next.add(id)
setSelected(next)
}
const toggleSelectAll = () => {
if (selected.size === filtered.length) {
setSelected(new Set())
} else {
setSelected(new Set(filtered.map(i => i.id)))
}
}
const handleDelete = () => {
if (selected.size === 0) return
Taro.showModal({
title: '确认删除',
content: `确定删除选中的 ${selected.size} 个条目吗?`,
success: (res) => {
if (res.confirm) {
removeDesigns(Array.from(selected))
setSelected(new Set())
setManaging(false)
load()
}
}
})
}
const handleManage = () => {
if (managing) {
setManaging(false)
setSelected(new Set())
} else {
setManaging(true)
}
}
return (
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<LoginGuard>
<View className='design-page'>
<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>
{VISIBLE_STATUS_TABS.map(tab => (
<View
key={tab.code}
className={`chip ${activeTab === tab.code ? 'active' : ''}`}
onTap={() => setActiveTab(tab.code)}
>
<Text className='tab-label'>{tab.label}</Text>
</View>
))}
</ScrollView>
</View>
{/* 批量管理工具栏 */}
{managing && (
<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' : ''}`} />
<Text className='batch-text'>全选 ({selected.size}/{filtered.length})</Text>
</View>
<View className={`batch-delete ${selected.size > 0 ? 'active' : ''}`} onTap={handleDelete}>
<Text>删除</Text>
</View>
</View>
</View>
)}
{/* 列表 */}
<ScrollView className='design-list' scrollY>
{filtered.map(item => {
const style = STATUS_STYLE[item.status]
const rawIcon = (item.productIcon || '').startsWith('/icon/') || /^https?:/i.test(item.productIcon || '')
? item.productIcon
: PRODUCT_ICON_MAP[item.productId] || '/icon/四角星.svg'
const iconSrc = assetUrl(rawIcon)
const isSelected = selected.has(item.id)
return (
<View
key={item.id}
className={`design-card ${isSelected ? 'selected' : ''}`}
onTap={() => managing ? toggleSelect(item.id) : undefined}
>
<View className='design-body'>
{managing && (
<View className={`batch-checkbox ${isSelected ? 'checked' : ''}`} />
)}
<Image className='design-icon-img' src={iconSrc} mode='aspectFit' />
<View className='design-info'>
<View className='design-title-row'>
<Text className='design-name'>{item.productName}</Text>
<Text className={`badge ${style.cls}`}>{style.label}</Text>
</View>
<Text className='design-meta'>数量: {item.count} | 单价: ¥{item.unitPrice}</Text>
<Text className='design-total'>小计: ¥{(item.unitPrice * item.count).toFixed(2)}</Text>
</View>
</View>
{!managing && (
<View className='design-actions'>
{item.status !== 'ordered' && (
<View className='btn-primary design-btn' onTap={() => goDesign(item)}>
<Text>{item.status === 'undesigned' ? '开始设计' : '继续设计'}</Text>
</View>
)}
{item.status === 'ordered' && (
<View className='btn-secondary design-btn' onTap={() => Taro.switchTab({ url: '/pages/orders/index' })}>
<Text>查看订单</Text>
</View>
)}
</View>
)}
</View>
)
})}
{filtered.length === 0 && (
<View className='empty-state'>
<Image className='empty-icon-img' src={assetUrl('/icon/调色盘.png')} mode='aspectFit' />
<Text className='empty-text'>还没有设计清单</Text>
<Text className='empty-sub'>去首页逛逛,找到喜欢的定制品</Text>
<View className='btn-primary' onTap={() => Taro.switchTab({ url: '/pages/index/index' })}>
<Text>去逛逛</Text>
</View>
</View>
)}
</ScrollView>
</View>
</LoginGuard>
</View>
)
}