feat(ui): 新增 ListRow 列表行组件并接入我的页/设备详情

This commit is contained in:
ozh 2026-09-09 11:22:11 +08:00
parent 9679e4062b
commit 240c235921
6 changed files with 90 additions and 54 deletions

View File

@ -0,0 +1,45 @@
.group {
background: $color-bg-white;
border-radius: $radius-lg;
box-shadow: $shadow-card;
overflow: hidden;
}
.row {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 104px;
padding: 0 32px;
background: $color-bg-white;
border-bottom: 1px solid $color-border;
}
.group .row:last-child {
border-bottom: none;
}
.rowPressed {
background: $color-bg-press;
}
.label {
font-size: 30px;
color: $color-text;
}
.rowDanger .label {
color: $color-danger-deep;
}
.value {
margin-left: 24px;
font-size: 28px;
color: $color-text;
}
.arrow {
margin-left: 16px;
font-size: 36px;
color: $color-text-placeholder;
}

View File

@ -0,0 +1,32 @@
import { View, Text } from '@tarojs/components'
import type { ReactNode } from 'react'
import styles from './index.module.scss'
interface ListRowProps {
label: string
value?: string
arrow?: boolean
onClick?: () => void
danger?: boolean
}
export function ListRow({ label, value, arrow, onClick, danger }: ListRowProps) {
const cls = [styles.row, danger ? styles.rowDanger : ''].filter(Boolean).join(' ')
return (
<View
className={cls}
hoverClass={onClick ? styles.rowPressed : 'none'}
onClick={onClick}
>
<Text className={styles.label}>{label}</Text>
{value && <Text className={styles.value}>{value}</Text>}
{arrow && <Text className={styles.arrow}>›</Text>}
</View>
)
}
// 分组容器:白卡外观 + 最后一条分割线由本模块组合选择器去除
// (CSS Modules 行组件无法感知父级,:last-child 必须写在同模块内)
export function ListRowGroup({ children }: { children: ReactNode }) {
return <View className={styles.group}>{children}</View>
}

View File

@ -106,21 +106,4 @@
.infoCard {
margin: 4px 24px 24px;
padding: 8px 32px;
background: $color-bg-white;
border-radius: $radius-lg;
box-shadow: $shadow-card;
}
.infoRow {
min-height: 104px;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid $color-border;
}
.infoRow:last-child { border-bottom: none; }
.infoLabel { font-size: 28px; color: $color-text-secondary; }
.infoValue { font-size: 28px; color: $color-text; }

View File

@ -2,6 +2,7 @@ import { useState, useEffect, useRef, useMemo } from 'react'
import Taro, { useRouter, useDidShow, useDidHide } from '@tarojs/taro'
import { View, Text } from '@tarojs/components'
import { Navbar } from '@/components/navbar'
import { ListRow, ListRowGroup } from '@/components/list-row'
import { Loading } from '@/components/loading'
import { StateView } from '@/components/state-view'
import { VitalWave } from '@/components/vital-wave'
@ -140,14 +141,10 @@ export default function Detail() {
</View>
<View className={styles.infoCard}>
<View className={styles.infoRow}>
<Text className={styles.infoLabel}>设备型号</Text>
<Text className={styles.infoValue}>{deviceModel || '-'}</Text>
</View>
<View className={styles.infoRow}>
<Text className={styles.infoLabel}>设备 ID</Text>
<Text className={styles.infoValue}>{deviceId || '-'}</Text>
</View>
<ListRowGroup>
<ListRow label="设备型号" value={deviceModel || '-'} />
<ListRow label="设备 ID" value={deviceId || '-'} />
</ListRowGroup>
</View>
</>
)}

View File

@ -38,21 +38,6 @@
color: $color-text-secondary;
}
.menu { margin-top: 20px; }
.item {
height: 104px;
padding: 0 32px;
background: $color-bg-white;
border-bottom: 1px solid $color-border;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 30px;
color: $color-text;
}
.arrow {
font-size: 36px;
color: $color-text-placeholder;
.menuCard {
margin: 20px 24px 0;
}

View File

@ -3,6 +3,7 @@ import { View, Text } from '@tarojs/components'
import { useAppDispatch, useAppSelector } from '@/store/hooks'
import { clearAuth } from '@/store/authSlice'
import { Navbar } from '@/components/navbar'
import { ListRow, ListRowGroup } from '@/components/list-row'
import { getUserInfo, type UserInfo } from '@/api/user'
import { useToast } from '@/hooks/useToast'
import { reLaunch, navigateTo } from '@/utils/navigation'
@ -36,18 +37,11 @@ export default function Mine() {
</View>
</View>
<View className={styles.menu}>
<View
className={styles.item}
onClick={() => navigateTo(ROUTES.DEVICE_ADD)}
>
<Text>添加设备</Text>
<Text className={styles.arrow}>›</Text>
</View>
<View className={styles.item} onClick={logout}>
<Text>退出登录</Text>
<Text className={styles.arrow}>›</Text>
</View>
<View className={styles.menuCard}>
<ListRowGroup>
<ListRow label="添加设备" arrow onClick={() => navigateTo(ROUTES.DEVICE_ADD)} />
<ListRow label="退出登录" arrow danger onClick={logout} />
</ListRowGroup>
</View>
</View>
)