轻松聘
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

265 lines
7.4 KiB

import { Ionicons } from '@expo/vector-icons';
import { useRouter } from 'expo-router';
import { Image, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { EmptyState, ErrorState, LoadingState } from '../../src/components/StateView';
import { useQualifications } from '../../src/hooks';
import { colors , spacing } from '../../src/theme';
import type { QualificationLicense } from '../../src/types';
/* ===================== 子组件:顶部导航 ===================== */
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>
);
}
/* ===================== 子组件:信息行 ===================== */
/**
* 证照信息行。值为 `null`(信息尚未提供)时显示「待补充」,
* 不使用 `--` 或空白 —— 空白会被误读成「本条不适用」,而实际是「还没填」。
*/
function InfoRow({ label, value }: { label: string; value: string | null }) {
return (
<View style={styles.infoRow}>
<Text style={styles.infoLabel}>{label}</Text>
{value ? (
<Text style={styles.infoValue}>{value}</Text>
) : (
<Text style={styles.infoPending}>待补充</Text>
)}
</View>
);
}
/* ===================== 子组件:单张证照卡片 ===================== */
function LicenseCard({ license }: { license: QualificationLicense }) {
return (
<View style={styles.card}>
<View style={styles.cardHeader}>
<Ionicons name="ribbon-outline" size={18} color={colors.primaryDark} />
<Text style={styles.cardTitle}>{license.name}</Text>
</View>
{/* 证照图:有图渲染图;没图渲染占位块,并写明这里需要补哪张图 */}
{license.imageUrl ? (
<Image source={{ uri: license.imageUrl }} style={styles.licenseImage} resizeMode="contain" />
) : (
<View style={styles.imagePlaceholder}>
<Ionicons name="image-outline" size={28} color={colors.actionText} />
<Text style={styles.placeholderText}>{license.imagePlaceholder}</Text>
</View>
)}
<View style={styles.infoList}>
<InfoRow label={license.numberLabel} value={license.number} />
<InfoRow label="发证机关" value={license.issuer} />
<InfoRow label="有效期" value={license.validPeriod} />
{license.scope ? <InfoRow label="经营范围" value={license.scope} /> : null}
</View>
</View>
);
}
/* ===================== 页面 ===================== */
export default function QualificationsScreen() {
const router = useRouter();
const { info, loading, error, refresh, isEmpty } = useQualifications();
return (
<SafeAreaView style={styles.safeArea} edges={['top']}>
<Header onBack={() => router.back()} />
{loading ? (
<LoadingState text="证照信息加载中…" />
) : error ? (
<ErrorState onRetry={refresh} />
) : !info || isEmpty ? (
<EmptyState
icon="ribbon-outline"
title="暂无资质证照"
subtitle="平台证照信息尚未公示,请稍后再试"
actionLabel="重新加载"
onAction={refresh}
/>
) : (
<ScrollView
style={styles.scroll}
contentContainerStyle={styles.content}
showsVerticalScrollIndicator={false}
>
{/* 运营主体 */}
<View style={styles.companyCard}>
<Text style={styles.companyLabel}>运营主体</Text>
<Text style={styles.companyName}>{info.company}</Text>
<Text style={styles.companyDesc}>
以下证照为本平台经营所持有的资质文件,供求职者与招聘方核验。
</Text>
</View>
{info.licenses.map((license) => (
<LicenseCard key={license.id} license={license} />
))}
<Text style={styles.verifyTip}>{info.verifyTip}</Text>
</ScrollView>
)}
</SafeAreaView>
);
}
const styles = StyleSheet.create({
safeArea: {
flex: 1,
backgroundColor: colors.pageBg,
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: spacing.card,
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: spacing.card,
paddingBottom: 32,
gap: 8,
},
companyCard: {
backgroundColor: colors.primaryLight,
borderRadius: spacing.card,
borderWidth: 1,
borderColor: colors.primaryBorder,
padding: spacing.card,
},
companyLabel: {
fontSize: 12,
color: colors.primaryText,
opacity: 0.8,
},
companyName: {
marginTop: 6,
fontSize: 18,
fontWeight: '700',
color: colors.primaryText,
},
companyDesc: {
marginTop: 8,
fontSize: 13,
lineHeight: 20,
color: colors.primaryText,
opacity: 0.85,
},
card: {
backgroundColor: colors.surface,
borderRadius: spacing.card,
borderWidth: 1,
borderColor: colors.border,
padding: spacing.card,
},
cardHeader: {
flexDirection: 'row',
alignItems: 'center',
gap: 6,
},
cardTitle: {
fontSize: 16,
fontWeight: '700',
color: colors.textPrimary,
},
licenseImage: {
marginTop: 8,
width: '100%',
height: 180,
borderRadius: spacing.card,
backgroundColor: colors.pageBg,
},
/* 图片占位:用「提醒卡片底 + 弱警示描边」语义色,一眼看出「这里是待办」 */
imagePlaceholder: {
marginTop: 8,
height: 132,
borderRadius: spacing.card,
borderWidth: 1,
borderStyle: 'dashed',
borderColor: colors.actionBorder,
backgroundColor: colors.actionLight,
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: spacing.card,
gap: 8,
},
placeholderText: {
fontSize: 12,
lineHeight: 18,
color: colors.actionText,
textAlign: 'center',
},
infoList: {
marginTop: 12,
},
infoRow: {
flexDirection: 'row',
alignItems: 'flex-start',
paddingVertical: 7,
borderTopWidth: 1,
borderTopColor: colors.borderLight,
},
/*
* 标签列不写死宽度:原写 `width: 96` 时「统一社会信用代码」八个字折成两行,
* 行高被撑开、右侧「待补充」位置错乱。改为按内容撑开(flexShrink: 0),
* 再用 minWidth 让短标签(发证机关 / 有效期)与长标签左对齐。
*/
infoLabel: {
minWidth: 96,
marginRight: 12,
flexShrink: 0,
fontSize: 13,
color: colors.textSecondary,
},
infoValue: {
flex: 1,
fontSize: 13,
fontWeight: '600',
color: colors.textPrimary,
},
infoPending: {
flex: 1,
fontSize: 13,
fontWeight: '600',
color: colors.actionText,
},
verifyTip: {
marginTop: 4,
fontSize: 12,
lineHeight: 18,
color: colors.textHint,
textAlign: 'center',
},
});