diff --git a/src/screens/schedule/ScheduleScreen.tsx b/src/screens/schedule/ScheduleScreen.tsx index 34efa4a..a38a902 100644 --- a/src/screens/schedule/ScheduleScreen.tsx +++ b/src/screens/schedule/ScheduleScreen.tsx @@ -199,6 +199,7 @@ export const ScheduleScreen: React.FC = () => { return Math.max(DEFAULT_SECTION_HEIGHT, calculatedHeight); }, [screenHeight, isMobile, insets.bottom]); const [isAddModalVisible, setIsAddModalVisible] = useState(false); + const [measuredDayWidth, setMeasuredDayWidth] = useState(null); const [pendingDay, setPendingDay] = useState(0); const [pendingMergedSection, setPendingMergedSection] = useState(1); const [newCourseName, setNewCourseName] = useState(''); @@ -676,7 +677,9 @@ export const ScheduleScreen: React.FC = () => { const height = duration * sectionHeight - 4; const laneGap = 2; const baseLeft = 2; - const availableWidth = dayColumnWidth - baseLeft * 2; + const baseRight = 2; + const effectiveDayWidth = measuredDayWidth ?? dayColumnWidth; + const availableWidth = effectiveDayWidth - baseLeft - baseRight; const cardWidth = laneCount > 1 ? (availableWidth - laneGap * (laneCount - 1)) / laneCount @@ -728,6 +731,9 @@ export const ScheduleScreen: React.FC = () => { return ( { + if (isWeb) setMeasuredDayWidth(e.nativeEvent.layout.width); + }} style={[ styles.dayColumn, { @@ -1336,6 +1342,7 @@ function createScheduleStyles(colors: AppColors) { backgroundColor: colors.background.default, borderRightWidth: StyleSheet.hairlineWidth, borderRightColor: colors.divider, + overflow: 'hidden', }, gridCell: { borderBottomWidth: StyleSheet.hairlineWidth, diff --git a/src/screens/trade/TradeDetailScreen.tsx b/src/screens/trade/TradeDetailScreen.tsx index 9efdd0b..34b9d64 100644 --- a/src/screens/trade/TradeDetailScreen.tsx +++ b/src/screens/trade/TradeDetailScreen.tsx @@ -1,15 +1,37 @@ import React, { useState, useEffect, useCallback, useMemo } from 'react'; -import { View, ScrollView, Image, StyleSheet, Pressable, Alert, Modal } from 'react-native'; +import { + View, + ScrollView, + Image, + StyleSheet, + Pressable, + Alert, + Modal, + LayoutAnimation, + Platform, +} from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { MaterialCommunityIcons } from '@expo/vector-icons'; import { useRouter } from 'expo-router'; -import { useAppColors, spacing, borderRadius, fontSizes, shadows, type AppColors } from '../../theme'; +import { + useAppColors, + spacing, + borderRadius, + fontSizes, + shadows, + type AppColors, +} from '../../theme'; import { Text, Loading, AppBackButton, ImageGrid, ImageGallery } from '../../components/common'; import { tradeService } from '../../services/trade/tradeService'; import { messageService } from '../../services/message/messageService'; import { useIsAuthenticated, useCurrentUser } from '../../stores/auth'; import type { TradeItemDetailDTO } from '../../types/trade'; -import { TRADE_CONDITION_MAP } from '../../types/trade'; +import { + TRADE_CONDITION_MAP, + TRADE_CATEGORY_MAP, + TRADE_TYPE_MAP, + TRADE_STATUS_MAP, +} from '../../types/trade'; import { hrefChat, hrefEditTrade } from '../../navigation/hrefs'; import { useResponsive, useResponsiveValue, useResponsiveSpacing } from '../../hooks'; @@ -19,6 +41,8 @@ function createStyles(colors: AppColors) { flex: 1, backgroundColor: colors.background.default, }, + + // ─── Header ├── header: { flexDirection: 'row', alignItems: 'center', @@ -28,55 +52,44 @@ function createStyles(colors: AppColors) { backgroundColor: colors.background.paper, ...shadows.sm, }, - headerLeft: { - width: 40, - alignItems: 'flex-start', - }, headerTitle: { fontSize: fontSizes.xl, fontWeight: '700', color: colors.text.primary, }, - headerRight: { - width: 40, - }, - // 降价标签 - discountBadge: { - position: 'absolute', - bottom: 12, - left: 12, + + // ─── 卖家信息卡片 ─── + sellerCard: { flexDirection: 'row', alignItems: 'center', - gap: 4, - paddingHorizontal: 10, - paddingVertical: 5, - borderRadius: borderRadius.lg, - backgroundColor: 'rgba(0,0,0,0.6)', - }, - discountBadgeText: { - color: '#fff', - fontSize: fontSizes.sm, - fontWeight: '600', - }, - content: { - padding: spacing.md, + paddingHorizontal: spacing.lg, + paddingVertical: spacing.md, backgroundColor: colors.background.paper, }, - // 顶部卖家信息栏 - sellerHeader: { - flexDirection: 'row', - alignItems: 'center', - gap: spacing.sm, - marginBottom: spacing.md, + sellerAvatarWrap: { + position: 'relative', }, sellerAvatar: { - width: 36, - height: 36, - borderRadius: 18, + width: 44, + height: 44, + borderRadius: 22, backgroundColor: colors.background.default, + borderWidth: 2, + borderColor: colors.primary.main + '30', + }, + sellerAvatarPlaceholder: { + width: 44, + height: 44, + borderRadius: 22, + backgroundColor: colors.primary.main + '18', + alignItems: 'center', + justifyContent: 'center', + borderWidth: 2, + borderColor: colors.primary.main + '30', }, sellerInfo: { flex: 1, + marginLeft: spacing.md, }, sellerNameRow: { flexDirection: 'row', @@ -85,254 +98,409 @@ function createStyles(colors: AppColors) { }, sellerName: { fontSize: fontSizes.lg, - fontWeight: '600', + fontWeight: '700', color: colors.text.primary, + letterSpacing: -0.2, }, - sellerCreditBadge: { + sellerBadge: { paddingHorizontal: 6, paddingVertical: 2, - borderRadius: borderRadius.sm, - backgroundColor: '#FFE066', + borderRadius: 6, + backgroundColor: colors.primary.main + '15', }, - sellerCreditText: { + sellerBadgeText: { fontSize: 10, - color: '#5C4B00', fontWeight: '700', + color: colors.primary.main, + letterSpacing: 0.3, }, - sellerMeta: { - fontSize: fontSizes.sm, - color: colors.text.hint, - marginTop: 2, - paddingLeft: 36 + spacing.sm, - }, - priceInHeader: { - fontSize: fontSizes['2xl'], - fontWeight: '700', - color: '#FF4D4F', - }, - priceSymbol: { - fontSize: fontSizes.md, - fontWeight: '700', - color: '#FF4D4F', - }, - - titleRow: { - flexDirection: 'row', - alignItems: 'flex-start', - gap: spacing.sm, - marginBottom: spacing.lg, - }, - conditionBadge: { - paddingHorizontal: 8, - paddingVertical: 3, - borderRadius: borderRadius.sm, - backgroundColor: '#FFE066', - flexShrink: 0, - }, - conditionBadgeText: { - fontSize: fontSizes.sm, - color: '#5C4B00', - fontWeight: '600', - }, - // 副标题信息行(包邮、自提) - subInfoRow: { + sellerMetaRow: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm, + marginTop: 2, + }, + sellerMetaText: { + fontSize: fontSizes.xs, + color: colors.text.hint, + }, + sellerMetaDot: { + width: 3, + height: 3, + borderRadius: 1.5, + backgroundColor: colors.text.hint, + }, + + // ─── 内容主体 ─── + bodySection: { + paddingHorizontal: spacing.lg, + paddingTop: spacing.lg, + paddingBottom: spacing.md, + backgroundColor: colors.background.paper, + }, + + // 标题 + 价格 同行 + titlePriceRow: { + flexDirection: 'row', + alignItems: 'flex-start', + justifyContent: 'space-between', + gap: spacing.md, + marginBottom: spacing.sm, + }, + titleText: { + fontWeight: '800', + color: colors.text.primary, + letterSpacing: -0.5, + flex: 1, + flexShrink: 1, + }, + priceBlock: { + alignItems: 'flex-end', + flexShrink: 0, + marginTop: 2, + }, + priceSymbol: { + fontSize: fontSizes.sm, + fontWeight: '700', + color: '#E8453C', + }, + priceValue: { + fontSize: fontSizes['2xl'], + fontWeight: '800', + color: '#E8453C', + letterSpacing: -0.5, + }, + priceNegotiable: { + fontSize: fontSizes.xs, + fontWeight: '600', + color: '#E8453C', + paddingHorizontal: 5, + paddingVertical: 1, + borderRadius: 4, + backgroundColor: '#E8453C' + '12', + marginTop: 2, + }, + + // 类型标签行 + tagRow: { + flexDirection: 'row', + alignItems: 'center', + gap: spacing.xs, marginBottom: spacing.md, flexWrap: 'wrap', }, - subInfoItem: { - fontSize: fontSizes.sm, + typeTag: { + flexDirection: 'row', + alignItems: 'center', + gap: 3, + paddingHorizontal: 8, + paddingVertical: 3, + borderRadius: 6, + overflow: 'hidden', + }, + typeTagSell: { + backgroundColor: colors.secondary.main + '14', + }, + typeTagBuy: { + backgroundColor: colors.info.main + '14', + }, + typeTagText: { + fontSize: fontSizes.xs, + fontWeight: '700', + letterSpacing: 0.3, + }, + conditionTag: { + paddingHorizontal: 8, + paddingVertical: 3, + borderRadius: 6, + backgroundColor: '#F5A623' + '18', + }, + conditionTagText: { + fontSize: fontSizes.xs, + fontWeight: '600', + color: '#B87A00', + letterSpacing: 0.2, + }, + categoryTag: { + paddingHorizontal: 8, + paddingVertical: 3, + borderRadius: 6, + backgroundColor: colors.neutral.bg, + }, + categoryTagText: { + fontSize: fontSizes.xs, + fontWeight: '500', color: colors.text.secondary, }, - shippingTag: { - paddingHorizontal: 5, - paddingVertical: 1, - borderRadius: borderRadius.sm, - borderWidth: 0.5, - borderColor: '#FFCCC7', - backgroundColor: '#FFF2F0', + statusTagSold: { + paddingHorizontal: 8, + paddingVertical: 3, + borderRadius: 6, + backgroundColor: colors.text.hint + '20', }, - shippingTagText: { + statusTagSoldText: { fontSize: fontSizes.xs, - color: '#FF4D4F', + fontWeight: '700', + color: colors.text.hint, }, - // 促销横幅 - promoBanner: { - flexDirection: 'row', - alignItems: 'center', - gap: spacing.sm, - paddingHorizontal: spacing.md, - paddingVertical: spacing.sm, - backgroundColor: '#FFF5F5', - borderRadius: borderRadius.md, + + // 描述 + descriptionText: { + color: colors.text.secondary, + letterSpacing: 0.15, + lineHeight: 24, marginBottom: spacing.md, }, - promoBannerText: { - fontSize: fontSizes.md, - color: '#FF4D4F', - fontWeight: '700', + + // 属性行 + attrSection: { + paddingTop: spacing.md, + borderTopWidth: 1, + borderTopColor: colors.divider + '60', }, - promoBannerSub: { - fontSize: fontSizes.md, - color: '#FF7875', - }, - title: { - fontWeight: '800', - color: colors.text.primary, - letterSpacing: -0.3, - flex: 1, - }, - // 商品属性行 attrGrid: { flexDirection: 'row', - justifyContent: 'flex-start', - alignItems: 'center', - marginBottom: spacing.md, - gap: spacing.lg, + flexWrap: 'wrap', + gap: spacing.md, }, - attrItem: { + attrPill: { flexDirection: 'row', alignItems: 'center', gap: 4, }, + attrIcon: { + width: 22, + height: 22, + borderRadius: 6, + backgroundColor: colors.background.default, + alignItems: 'center', + justifyContent: 'center', + }, attrLabel: { - fontSize: fontSizes.sm, + fontSize: fontSizes.xs, color: colors.text.hint, }, attrValue: { fontSize: fontSizes.sm, color: colors.text.primary, - fontWeight: '500', + fontWeight: '600', }, - // 描述 - 与帖子正文同步 - contentText: { - color: colors.text.primary, - letterSpacing: 0.2, - marginBottom: spacing.lg, + + // 物流标签 + shippingRow: { + flexDirection: 'row', + gap: spacing.sm, + marginTop: spacing.md, + flexWrap: 'wrap', }, - // 底部操作栏 + shippingPill: { + flexDirection: 'row', + alignItems: 'center', + gap: 3, + paddingHorizontal: 8, + paddingVertical: 4, + borderRadius: 8, + backgroundColor: colors.secondary.main + '0D', + borderWidth: 1, + borderColor: colors.secondary.main + '25', + }, + shippingPillText: { + fontSize: fontSizes.xs, + fontWeight: '600', + color: colors.secondary.dark, + }, + + // ─── 促销横幅 ─── + promoBanner: { + flexDirection: 'row', + alignItems: 'center', + gap: spacing.sm, + paddingHorizontal: spacing.lg, + paddingVertical: spacing.md, + backgroundColor: '#FFF7ED', + borderBottomWidth: 1, + borderBottomColor: '#FFD6A8' + '40', + }, + promoIcon: { + width: 28, + height: 28, + borderRadius: 8, + backgroundColor: colors.primary.main + '18', + alignItems: 'center', + justifyContent: 'center', + }, + promoText: { + fontSize: fontSizes.md, + fontWeight: '700', + color: '#C2410C', + flex: 1, + }, + + // ─── 图片区域 ─── + imageSection: { + backgroundColor: colors.background.paper, + }, + + // ─── 分隔线 ─── + divider: { + height: spacing.sm, + backgroundColor: colors.background.default, + }, + + // ─── 底部操作栏 ─── bottomBar: { flexDirection: 'row', alignItems: 'center', - paddingHorizontal: spacing.md, - paddingVertical: 4, + paddingHorizontal: spacing.lg, + paddingVertical: spacing.sm + 2, backgroundColor: colors.background.paper, - borderTopWidth: 1, + borderTopWidth: StyleSheet.hairlineWidth, borderTopColor: colors.divider, gap: spacing.md, }, - bottomAction: { + favButton: { + width: 44, + height: 44, + borderRadius: 14, + borderWidth: 1.5, + borderColor: colors.divider, + backgroundColor: colors.background.paper, alignItems: 'center', justifyContent: 'center', - gap: 2, }, - bottomActionText: { - fontSize: 10, - color: colors.text.secondary, + favButtonActive: { + borderColor: '#E8453C', + backgroundColor: '#E8453C' + '0A', + }, + shareButton: { + width: 44, + height: 44, + borderRadius: 14, + borderWidth: 1.5, + borderColor: colors.divider, + backgroundColor: colors.background.paper, + alignItems: 'center', + justifyContent: 'center', }, chatButton: { + flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: spacing.xs, - height: 36, - paddingHorizontal: spacing.lg, + height: 44, borderRadius: 14, backgroundColor: colors.primary.main, + ...shadows.sm, }, chatButtonText: { color: colors.text.inverse, - fontSize: fontSizes.md, - fontWeight: '600', + fontSize: fontSizes.lg, + fontWeight: '700', + letterSpacing: 0.5, }, chatButtonDisabled: { backgroundColor: colors.text.hint, + ...shadows.sm, }, - // 管理按钮 - editButton: { + manageButton: { + flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', - gap: spacing.sm, - height: 48, + gap: spacing.xs, + height: 44, borderRadius: 14, - borderWidth: 1, + borderWidth: 1.5, borderColor: colors.divider, - paddingHorizontal: spacing.lg, backgroundColor: colors.background.paper, }, - editButtonText: { - fontSize: fontSizes.md, + manageButtonText: { + fontSize: fontSizes.lg, color: colors.text.primary, - fontWeight: '600', + fontWeight: '700', }, - statusSection: { - marginBottom: spacing.md, - }, - divider: { - height: 1, - backgroundColor: colors.divider, - marginVertical: spacing.md, - }, - // 底部弹窗 + + // ─── 管理弹窗 ─── modalOverlay: { flex: 1, - backgroundColor: 'rgba(0,0,0,0.5)', + backgroundColor: 'rgba(0,0,0,0.4)', justifyContent: 'flex-end', }, modalContent: { backgroundColor: colors.background.paper, - borderTopLeftRadius: borderRadius.xl, - borderTopRightRadius: borderRadius.xl, + borderTopLeftRadius: 20, + borderTopRightRadius: 20, paddingBottom: spacing.xl, }, + modalHandle: { + width: 36, + height: 4, + borderRadius: 2, + backgroundColor: colors.divider, + alignSelf: 'center', + marginTop: spacing.sm, + marginBottom: spacing.md, + }, + modalTitle: { + fontSize: fontSizes.lg, + fontWeight: '700', + color: colors.text.primary, + textAlign: 'center', + marginBottom: spacing.md, + }, modalItem: { - paddingVertical: spacing.md, + flexDirection: 'row', alignItems: 'center', - borderBottomWidth: 1, - borderBottomColor: colors.divider, + gap: spacing.md, + paddingVertical: spacing.md + 2, + paddingHorizontal: spacing.xl, + }, + modalItemIcon: { + width: 36, + height: 36, + borderRadius: 10, + alignItems: 'center', + justifyContent: 'center', }, modalItemText: { fontSize: fontSizes.lg, color: colors.text.primary, + fontWeight: '500', + flex: 1, }, modalCancel: { - paddingVertical: spacing.md, - alignItems: 'center', + marginHorizontal: spacing.xl, marginTop: spacing.sm, + paddingVertical: spacing.md + 2, + alignItems: 'center', + borderRadius: 14, + backgroundColor: colors.background.default, }, modalCancelText: { fontSize: fontSizes.lg, - color: colors.text.hint, - }, - // 管理按钮 - manageButton: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - gap: spacing.xs, - height: 36, - paddingHorizontal: spacing.lg, - borderRadius: 14, - backgroundColor: 'transparent', - }, - manageButtonText: { - fontSize: fontSizes.md, - color: colors.text.primary, + color: colors.text.secondary, fontWeight: '600', }, - contentAttrs: { + + // ─── 底部统计 ─── + statsRow: { flexDirection: 'row', - justifyContent: 'flex-end', alignItems: 'center', - gap: spacing.md, - flexWrap: 'wrap', + gap: spacing.lg, + paddingHorizontal: spacing.lg, + paddingVertical: spacing.md, + backgroundColor: colors.background.paper, }, - contentAttrText: { - fontSize: fontSizes.sm, - color: colors.text.secondary, + statItem: { + flexDirection: 'row', + alignItems: 'center', + gap: 4, + }, + statText: { + fontSize: fontSizes.xs, + color: colors.text.hint, + fontWeight: '500', }, }); } @@ -356,17 +524,11 @@ export function TradeDetailScreen({ tradeId }: TradeDetailScreenProps) { const isOwner = item?.user_id === currentUser?.id; - // 响应式 hook(与帖子同步) - const { - width, - isMobile, - isTablet, - isDesktop, - isWideScreen, - } = useResponsive(); + const { isMobile, isTablet, isDesktop, isWideScreen } = useResponsive(); - const responsivePadding = useResponsiveSpacing({ xs: 12, sm: 14, md: 16, lg: 20, xl: 24, '2xl': 28, '3xl': 32, '4xl': 40 }); - const responsiveGap = useResponsiveSpacing({ xs: 8, sm: 10, md: 12, lg: 16, xl: 20, '2xl': 24, '3xl': 28, '4xl': 32 }); + const responsivePadding = useResponsiveSpacing({ + xs: 16, sm: 18, md: 20, lg: 24, xl: 28, '2xl': 32, '3xl': 40, '4xl': 48, + }); const fetchItem = useCallback(async () => { try { @@ -455,13 +617,11 @@ export function TradeDetailScreen({ tradeId }: TradeDetailScreenProps) { } }, [isAuth, item?.author?.id, router]); - // 响应式图片间距和圆角(与帖子同步) const imageGap = isDesktop ? 12 : isTablet ? 10 : 8; const imageBorderRadius = isDesktop ? borderRadius.xl : borderRadius.lg; const images = item?.images || []; - // 转换图片格式给 ImageGrid 使用 const tradeImages = useMemo(() => { return images.map(img => ({ id: img.id, @@ -477,6 +637,20 @@ export function TradeDetailScreen({ tradeId }: TradeDetailScreenProps) { setShowImageModal(true); }, []); + const formatDate = (dateStr: string) => { + const d = new Date(dateStr); + const now = new Date(); + const diffMs = now.getTime() - d.getTime(); + const diffMin = Math.floor(diffMs / 60000); + const diffHr = Math.floor(diffMs / 3600000); + const diffDay = Math.floor(diffMs / 86400000); + if (diffMin < 1) return '刚刚'; + if (diffMin < 60) return `${diffMin}分钟前`; + if (diffHr < 24) return `${diffHr}小时前`; + if (diffDay < 7) return `${diffDay}天前`; + return `${d.getMonth() + 1}月${d.getDate()}日`; + }; + if (loading) { return ; } @@ -485,96 +659,212 @@ export function TradeDetailScreen({ tradeId }: TradeDetailScreenProps) { return ( - 商品不存在或已删除 + + + 商品不存在或已删除 + ); } + const isSell = item.trade_type === 'sell'; + const isInactive = item.status !== 'active'; + const conditionLabel = TRADE_CONDITION_MAP[item.condition as keyof typeof TRADE_CONDITION_MAP]; + const categoryLabel = TRADE_CATEGORY_MAP[item.category as keyof typeof TRADE_CATEGORY_MAP]; + const statusLabel = TRADE_STATUS_MAP[item.status as keyof typeof TRADE_STATUS_MAP]; + return ( + {/* ─── Header ─── */} - - router.back()} /> - + router.back()} /> 商品详情 - + - - - {/* 卖家信息头部 */} - {item.author && ( - - - {item.author.avatar ? ( - - ) : ( - - - - )} - - - - {item.author.nickname && item.author.nickname.length > 10 - ? `${item.author.nickname.slice(0, 10)}...` - : item.author.nickname || '匿名'} - - {(item.author?.credit_score || 0) > 80 && ( - - 卖家信用优秀 - - )} - + + {/* ─── 促销横幅 ─── */} + {item.promo_text && ( + + + + + {item.promo_text} + + )} + + {/* ─── 卖家卡片 ─── */} + {item.author && ( + + + {item.author.avatar ? ( + + ) : ( + + - {item.price != null ? ( - - 价格:¥{item.price % 1 === 0 ? item.price.toFixed(0) : item.price.toFixed(2)} - - ) : ( - 价格:面议 + )} + + + + + {item.author.nickname || '匿名'} + + {(item.author?.credit_score || 0) > 80 && ( + + 信用优秀 + )} - + + {formatDate(item.created_at)}发布 + + {item.views_count || 0}次浏览 + - )} + + )} - {/* 标题 - 与帖子同步 */} - + + + {/* ─── 商品主体 ─── */} + + {/* 标题 + 价格 同行 */} + {item.title} + + + {item.price != null ? ( + <> + + ¥ + + {item.price % 1 === 0 ? item.price.toFixed(0) : item.price.toFixed(2)} + + + {item.is_negotiable && ( + 可议价 + )} + + ) : ( + 面议 + )} + - {/* 商品描述 - 与帖子正文同步 */} + {/* 标签行 */} + + + + + {TRADE_TYPE_MAP[item.trade_type]} + + + + {isInactive && ( + + {statusLabel} + + )} + + {isSell && conditionLabel && ( + + {conditionLabel} + + )} + + {categoryLabel && ( + + {categoryLabel} + + )} + + + {/* 描述 */} {item.content && ( {item.content} )} + + {/* 属性区 (出售商品) */} + {isSell && ( + + + {item.brand && ( + + + + + + 品牌 + {item.brand} + + + )} + + + + + + 功能 + {item.function_status || '正常'} + + + + + {/* 物流标签 */} + + {item.is_free_shipping && ( + + + 包邮 + + )} + {item.is_self_pickup && ( + + + 可自提 + + )} + {item.is_quick_ship && ( + + + 快速发货 + + )} + + + )} - {/* 图片 - 使用 ImageGrid 与帖子同步 */} + {/* ─── 图片区域(文本下方) ─── */} {tradeImages.length > 0 && ( - + )} - {/* 内容区右下角属性文字(仅出售商品显示) */} - {item.trade_type === 'sell' && ( - - - 品牌:{item.brand || '其他'} - - 成色:{TRADE_CONDITION_MAP[item.condition as keyof typeof TRADE_CONDITION_MAP] || item.condition || '未知'} - - 功能状态:{item.function_status || '正常使用'} - + {/* ─── 统计行 ─── */} + + + + {item.views_count || 0} - )} + + + {item.favorites_count || 0} + + {item.created_at && ( + + {formatDate(item.created_at)} + + )} + - {/* 底部操作栏 */} + {/* ─── 底部操作栏 ─── */} {isOwner ? ( - /* 卖家管理按钮 */ - <> - - setManageModalVisible(true)}> - - 管理 - - + setManageModalVisible(true)}> + + 管理商品 + ) : ( <> - {!isOwner && item.status === 'active' && ( - <> - - - - 聊一聊 - - - )} - {!isOwner && item.status !== 'active' && ( - - - - {item.status === 'sold' ? '已售出' : item.status === 'bought' ? '已收得' : '已下架'} - - - + + + + {!isInactive ? ( + + + 聊一聊 + + ) : ( + {}}> + {statusLabel} + )} )} - {/* 管理弹窗 */} + {/* ─── 管理弹窗 ─── */} setManageModalVisible(false)} > setManageModalVisible(false)}> - + e.stopPropagation()}> + + 管理商品 + - 编辑 + + + + 编辑商品 + - - 删除 + + + + + + 删除商品 + + setManageModalVisible(false)}> 取消 - + - {/* 图片预览 */} + {/* ─── 图片预览 ─── */} ({ @@ -671,4 +973,4 @@ export function TradeDetailScreen({ tradeId }: TradeDetailScreenProps) { /> ); -} \ No newline at end of file +}