Browse Source
- 薪资计算器:新增城市社保/公积金基数上下限表,选城市后 clamp 社保基数并计入计算(断点②) - 文书模板:新增模板正文与预览页 /legal/template,正文 selectable 长按可复制(断点③) - 分层:types/constants/api/页面;tsc --noEmit 0 错误、eslint 0 警告、路由审计 0 死链master
8 changed files with 383 additions and 14 deletions
@ -0,0 +1,145 @@ |
|||
import { Ionicons } from '@expo/vector-icons'; |
|||
import { useRouter, useLocalSearchParams } from 'expo-router'; |
|||
import { Pressable, ScrollView, StyleSheet, Text, View } from 'react-native'; |
|||
import { SafeAreaView } from 'react-native-safe-area-context'; |
|||
import { useLegalData } from '../../src/hooks'; |
|||
import { LoadingState, ErrorState, EmptyState } from '../../src/components/StateView'; |
|||
import { colors } from '../../src/theme'; |
|||
|
|||
/* ===================== 顶部导航 ===================== */ |
|||
|
|||
function Header({ onBack }: { onBack: () => void }) { |
|||
return ( |
|||
<View style={styles.header}> |
|||
<Pressable style={styles.headerBtn} onPress={onBack} hitSlop={8}> |
|||
<Ionicons name="chevron-back" size={24} color={colors.textPrimary} /> |
|||
</Pressable> |
|||
<Text style={styles.headerTitle}>文书预览</Text> |
|||
<View style={styles.headerBtn} /> |
|||
</View> |
|||
); |
|||
} |
|||
|
|||
/* ===================== 页面 ===================== */ |
|||
|
|||
export default function LegalTemplateScreen() { |
|||
const router = useRouter(); |
|||
const { id } = useLocalSearchParams(); |
|||
const { templates, loading, error, refresh } = useLegalData(); |
|||
|
|||
const templateId = Array.isArray(id) ? id[0] : id; |
|||
const template = templateId ? templates.find((t) => t.id === templateId) : undefined; |
|||
|
|||
return ( |
|||
<SafeAreaView style={styles.safeArea} edges={['top']}> |
|||
<Header onBack={() => router.back()} /> |
|||
{loading ? ( |
|||
<LoadingState text="加载模板中…" /> |
|||
) : error ? ( |
|||
<ErrorState message="加载失败,请重试" onRetry={refresh} /> |
|||
) : !template ? ( |
|||
<EmptyState icon="document-text-outline" title="未找到该模板" subtitle="请返回重新选择" /> |
|||
) : ( |
|||
<ScrollView |
|||
style={styles.scroll} |
|||
contentContainerStyle={styles.content} |
|||
showsVerticalScrollIndicator={false} |
|||
> |
|||
<View style={styles.headCard}> |
|||
<Ionicons name={template.icon as never} size={28} color={colors.primary} /> |
|||
<View style={styles.headBody}> |
|||
<Text style={styles.name}>{template.name}</Text> |
|||
<Text style={styles.desc}>{template.description}</Text> |
|||
</View> |
|||
</View> |
|||
|
|||
<View style={styles.contentCard}> |
|||
{/* selectable:长按正文即可复制,无需额外原生模块(mock 阶段) */} |
|||
<Text style={styles.contentText} selectable> |
|||
{template.content} |
|||
</Text> |
|||
</View> |
|||
|
|||
<Text style={styles.tip}> |
|||
长按正文即可复制;正式下载 / 导出为 Word·PDF 需后端文件支持,当前为内容预览。 |
|||
</Text> |
|||
</ScrollView> |
|||
)} |
|||
</SafeAreaView> |
|||
); |
|||
} |
|||
|
|||
const styles = StyleSheet.create({ |
|||
safeArea: { |
|||
flex: 1, |
|||
backgroundColor: colors.pageBg, |
|||
}, |
|||
header: { |
|||
flexDirection: 'row', |
|||
alignItems: 'center', |
|||
justifyContent: 'space-between', |
|||
paddingHorizontal: 8, |
|||
height: 48, |
|||
backgroundColor: colors.white, |
|||
borderBottomWidth: 1, |
|||
borderBottomColor: colors.borderLight, |
|||
}, |
|||
headerBtn: { |
|||
width: 40, |
|||
height: 40, |
|||
alignItems: 'center', |
|||
justifyContent: 'center', |
|||
}, |
|||
headerTitle: { |
|||
fontSize: 17, |
|||
fontWeight: '700', |
|||
color: colors.textPrimary, |
|||
}, |
|||
scroll: { |
|||
flex: 1, |
|||
}, |
|||
content: { |
|||
padding: 12, |
|||
paddingBottom: 24, |
|||
}, |
|||
headCard: { |
|||
flexDirection: 'row', |
|||
alignItems: 'center', |
|||
padding: 16, |
|||
borderRadius: 12, |
|||
backgroundColor: colors.white, |
|||
marginBottom: 12, |
|||
}, |
|||
headBody: { |
|||
flex: 1, |
|||
marginLeft: 12, |
|||
}, |
|||
name: { |
|||
fontSize: 16, |
|||
fontWeight: '700', |
|||
color: colors.textPrimary, |
|||
}, |
|||
desc: { |
|||
marginTop: 2, |
|||
fontSize: 12, |
|||
color: colors.textSecondary, |
|||
}, |
|||
contentCard: { |
|||
padding: 16, |
|||
borderRadius: 12, |
|||
backgroundColor: colors.white, |
|||
borderWidth: 1, |
|||
borderColor: colors.borderLight, |
|||
}, |
|||
contentText: { |
|||
fontSize: 14, |
|||
lineHeight: 22, |
|||
color: colors.textPrimary, |
|||
}, |
|||
tip: { |
|||
marginTop: 12, |
|||
fontSize: 12, |
|||
color: colors.textHint, |
|||
lineHeight: 18, |
|||
}, |
|||
}); |
|||
Loading…
Reference in new issue