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.
149 lines
6.2 KiB
149 lines
6.2 KiB
import { useState } from 'react';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
import { colors } from '../../../src/theme';
|
|
import { useOnboarding, useRegisterFinish } from '../../../src/hooks';
|
|
import { onboardingStepLabel } from '../../../src/utils';
|
|
import { ScreenShell } from '../ui/ScreenShell';
|
|
import { SearchInput } from '../ui/SearchInput';
|
|
import { Tag, TagGroup } from '../ui/Tag';
|
|
import { PrimaryButton } from '../ui/PrimaryButton';
|
|
|
|
const CATEGORIES = ['高级管理', '采购贸易', '生产制造', '互联网AI', '设计', '金融', '客服运营', '咨询翻译法律', '房地产建筑', '医疗健康'];
|
|
const POSITIONS: Record<string, string[]> = {
|
|
高级管理: ['CEO', 'CTO', '产品经理', '项目负责人'],
|
|
采购贸易: ['采购专员', '贸易跟单', '供应链专员'],
|
|
生产制造: ['工艺工程师', '质量工程师', '生产主管'],
|
|
互联网AI: ['前端开发工程师', '鸿蒙开发工程师', '全栈工程师', 'Java工程师', '测试工程师', '运维工程师', '数据分析师', '算法工程师'],
|
|
设计: ['UI设计师', '视觉设计师', '交互设计师'],
|
|
金融: ['风控专员', '投资经理', '财务分析'],
|
|
客服运营: ['客服专员', '用户运营', '内容运营'],
|
|
咨询翻译法律: ['咨询顾问', '翻译', '法务专员'],
|
|
房地产建筑: ['建筑设计师', '土木工程师', '房产经纪'],
|
|
医疗健康: ['临床医师', '药剂师', '健康管理'],
|
|
};
|
|
|
|
/** 全部分类的职位去重展开,供搜索跨分类匹配 */
|
|
const ALL_POSITIONS: string[] = Array.from(new Set(Object.values(POSITIONS).flat()));
|
|
|
|
export function P6ExpectedPosition() {
|
|
const { data, setData, navigate, back } = useOnboarding();
|
|
const finish = useRegisterFinish();
|
|
const [cat, setCat] = useState('互联网AI');
|
|
const [query, setQuery] = useState('');
|
|
const positions = data.expectedPositions;
|
|
|
|
const step = onboardingStepLabel('P6');
|
|
const keyword = query.trim();
|
|
// 搜索态跨分类匹配:只搜当前分类时,在「互联网AI」下搜「UI设计师」会得到空结果,
|
|
// 看起来像平台没有这个职位,实际只是没切分类
|
|
const visible = keyword ? ALL_POSITIONS.filter((p) => p.includes(keyword)) : POSITIONS[cat];
|
|
|
|
const toggle = (p: string) =>
|
|
setData({
|
|
expectedPositions: positions.includes(p) ? positions.filter((x) => x !== p) : [...positions, p],
|
|
});
|
|
|
|
return (
|
|
<ScreenShell showBack onBack={back}>
|
|
<View style={styles.header}>
|
|
<Text style={styles.title}>期望职位</Text>
|
|
{/* 快速通道:填完意向即可落地,剩余资料后续再补。文案据实写「跳过」,
|
|
不再叫「保存」——它并不保存,而是直接结束注册流程 */}
|
|
<Pressable onPress={() => void finish('candidate')} hitSlop={6}>
|
|
<Text style={styles.save}>跳过,直接进入</Text>
|
|
</Pressable>
|
|
</View>
|
|
|
|
{step ? (
|
|
<View style={styles.progress}>
|
|
<Text style={styles.progressText}>{step}</Text>
|
|
</View>
|
|
) : null}
|
|
|
|
<SearchInput value={query} onChangeText={setQuery} placeholder="搜索职位" onClear={() => setQuery('')} />
|
|
|
|
<View style={styles.body}>
|
|
<View style={styles.cats}>
|
|
{CATEGORIES.map((c) => (
|
|
<Pressable
|
|
key={c}
|
|
style={[styles.catItem, c === cat && styles.catItemActive]}
|
|
onPress={() => {
|
|
// 搜索态下分类不参与过滤,只切分类看不出任何变化 —— 一并清掉关键词,
|
|
// 让「点分类」这个动作始终有可见结果
|
|
setQuery('');
|
|
setCat(c);
|
|
}}
|
|
>
|
|
<Text style={[styles.catText, c === cat && styles.catTextActive]}>{c}</Text>
|
|
</Pressable>
|
|
))}
|
|
</View>
|
|
|
|
<View style={styles.posCol}>
|
|
{positions.length > 0 && (
|
|
<View style={styles.chips}>
|
|
{positions.map((p) => (
|
|
<View key={p} style={styles.chip}>
|
|
<Text style={styles.chipText}>{p}</Text>
|
|
<Pressable onPress={() => toggle(p)} hitSlop={6}>
|
|
<Ionicons name="close" size={14} color={colors.textInverse} />
|
|
</Pressable>
|
|
</View>
|
|
))}
|
|
</View>
|
|
)}
|
|
{visible.length > 0 ? (
|
|
<TagGroup>
|
|
{visible.map((p) => (
|
|
<Tag key={p} label={p} selected={positions.includes(p)} onPress={() => toggle(p)} />
|
|
))}
|
|
</TagGroup>
|
|
) : (
|
|
<Text style={styles.empty}>没有匹配「{keyword}」的职位,换个关键词试试</Text>
|
|
)}
|
|
</View>
|
|
</View>
|
|
|
|
<View style={styles.footer}>
|
|
<PrimaryButton label="下一步" active={positions.length > 0} onPress={() => navigate('P7')} />
|
|
</View>
|
|
</ScreenShell>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 },
|
|
title: { fontSize: 20, fontWeight: '800', color: colors.textPrimary },
|
|
progress: {
|
|
alignSelf: 'flex-start',
|
|
backgroundColor: colors.primaryLight,
|
|
paddingHorizontal: 10,
|
|
paddingVertical: 3,
|
|
borderRadius: 10,
|
|
marginBottom: 12,
|
|
},
|
|
progressText: { fontSize: 12, fontWeight: '700', color: colors.primaryText },
|
|
save: { fontSize: 15, fontWeight: '700', color: colors.primary },
|
|
empty: { fontSize: 13, color: colors.textHint, lineHeight: 20 },
|
|
body: { flexDirection: 'row', gap: 14, marginTop: 8 },
|
|
cats: { width: 92 },
|
|
catItem: { paddingVertical: 12, borderRadius: 10 },
|
|
catItemActive: { backgroundColor: colors.primaryLight },
|
|
catText: { fontSize: 13, color: colors.textSecondary, textAlign: 'center' },
|
|
catTextActive: { color: colors.primaryText, fontWeight: '700' },
|
|
posCol: { flex: 1 },
|
|
chips: { flexDirection: 'row', flexWrap: 'wrap', gap: 8, marginBottom: 14 },
|
|
chip: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 6,
|
|
backgroundColor: colors.primary,
|
|
paddingHorizontal: 10,
|
|
paddingVertical: 6,
|
|
borderRadius: 14,
|
|
},
|
|
chipText: { fontSize: 13, color: colors.textInverse },
|
|
footer: { marginTop: 28 },
|
|
});
|
|
|