This commit is contained in:
2025-11-12 12:20:58 +08:00
parent 8764849cd6
commit 1468002fe2
14 changed files with 856 additions and 217 deletions

View File

@@ -42,6 +42,9 @@
<text>查询职业发展路径</text>
<uni-icons type="search" size="18" color="#FFFFFF"></uni-icons>
</button>
<view v-if="totalPathCount > 0" class="path-summary">
系统已收录 {{ totalPathCount }} 条职业路径
</view>
</view>
<!-- 职业发展路径区域 -->
@@ -113,75 +116,141 @@
<script setup>
import { ref, onMounted } from 'vue';
import { getJobPathPage, getJobPathDetail, getJobPathNum } from '@/apiRc/jobPath.js';
// 当前职位(从接口获取,只读)
const currentPosition = ref('前端开发工程师');
// 目标职业选项(根据当前职位动态获取)
const targetCareerOptions = ref([
{ label: '互联网/IT', value: 'internet_it' },
{ label: '高级前端开发工程师', value: 'senior_frontend' },
{ label: '前端架构师', value: 'frontend_architect' },
{ label: '技术总监', value: 'tech_director' }
]);
// 目标职业选项列表
const targetCareerOptions = ref([]);
const selectedTargetIndex = ref(-1);
const selectedJobPathId = ref(null);
// 职业路径数据(后续从接口获取)
const pathData = ref({
// 职业路径数
const totalPathCount = ref(0);
// 初始路径数据
const emptyPathData = {
start: {
title: '初级网络安全管理员',
skills: ['React', 'Node.js', 'Typescript', '数据库']
title: '暂无数据',
skills: []
},
steps: [
{
title: '中级网络安全工程师',
skills: ['Vue3', '微前端', '性能优化', '团队管理']
},
{
title: '资深安全顾问(横向发展)',
skills: ['架构设计', '技术选型', '工程化', '团队领导']
},
{
title: '高级网络安全架构师',
skills: ['架构设计', '技术选型', '工程化', '团队领导']
},
{
title: '技术部门经理',
skills: ['架构设计', '技术选型', '工程化', '团队领导']
}
],
steps: [],
end: {
title: 'IT 项目总监',
skills: ['架构设计', '技术选型', '工程化', '团队领导']
title: '暂无数据',
skills: []
}
});
};
// 获取当前职位信息(从接口获取)
async function getCurrentPosition() {
// TODO: 调用接口获取当前职位
// const response = await getCareerCurrentPosition();
// if (response && response.code === 200) {
// currentPosition.value = response.data?.position || '';
// // 根据当前职位获取目标职业选项
// await getTargetCareerOptions(currentPosition.value);
// }
const pathData = ref({ ...emptyPathData });
const isLoadingPath = ref(false);
function parseSkillList(skillString) {
if (!skillString) {
return [];
}
return skillString
.split(/[,]/)
.map(item => item.trim())
.filter(item => item.length > 0);
}
// 根据当前职位获取目标职业选项
async function getTargetCareerOptions(position) {
// TODO: 调用接口获取目标职业选项
// const response = await getTargetCareers(position);
// if (response && response.code === 200) {
// targetCareerOptions.value = response.data || [];
// }
function resetPathData() {
pathData.value = {
start: { ...emptyPathData.start },
steps: [],
end: { ...emptyPathData.end }
};
}
async function fetchTargetCareerOptions(keyword = '') {
try {
const response = await getJobPathPage({
jobName: keyword,
pageNo: 1,
pageSize: 100
});
const list = response?.data?.list || [];
targetCareerOptions.value = list.map(item => ({
label: item.endJob || item.startJob || '未知职位',
value: item.id,
startJob: item.startJob,
endJob: item.endJob,
jobOrder: item.jobOrder
}));
if (targetCareerOptions.value.length === 0) {
selectedTargetIndex.value = -1;
selectedJobPathId.value = null;
}
} catch (error) {
console.error('获取职业路径列表失败:', error);
targetCareerOptions.value = [];
selectedTargetIndex.value = -1;
selectedJobPathId.value = null;
uni.showToast({
title: '职业路径列表获取失败',
icon: 'none'
});
}
}
async function fetchPathCount() {
try {
const response = await getJobPathNum();
totalPathCount.value = response?.data ?? 0;
} catch (error) {
console.error('获取职业路径数量失败:', error);
totalPathCount.value = 0;
}
}
async function loadPathDetail(jobPathId) {
try {
const response = await getJobPathDetail({
jobPathId
});
const details = Array.isArray(response?.data) ? response.data : [];
if (details.length === 0) {
resetPathData();
uni.showToast({
title: '暂无职业路径数据',
icon: 'none'
});
return;
}
const normalized = details.map(item => ({
title: item?.name || '未命名职位',
skills: parseSkillList(item?.skillNameList)
}));
const start = normalized[0] || { title: '暂无数据', skills: [] };
const end = normalized[normalized.length - 1] || { title: '暂无数据', skills: [] };
const steps = normalized.slice(1, normalized.length - 1);
pathData.value = {
start,
steps,
end
};
} catch (error) {
console.error('获取职业路径详情失败:', error);
uni.showToast({
title: '获取路径详情失败',
icon: 'none'
});
}
}
function handleTargetChange(e) {
selectedTargetIndex.value = e.detail.value;
const index = Number(e.detail.value);
selectedTargetIndex.value = index;
const option = targetCareerOptions.value[index];
selectedJobPathId.value = option ? option.value : null;
}
function handleQuery() {
async function handleQuery() {
if (selectedTargetIndex.value < 0) {
uni.showToast({
title: '请选择目标职业',
@@ -189,13 +258,72 @@ function handleQuery() {
});
return;
}
const selectedTarget = targetCareerOptions.value[selectedTargetIndex.value];
console.log('查询职业发展路径', currentPosition.value, selectedTarget);
// TODO: 调用接口查询职业路径
const option = targetCareerOptions.value[selectedTargetIndex.value];
if (!option) {
uni.showToast({
title: '目标职业数据异常',
icon: 'none'
});
return;
}
let jobPathId = option.value;
isLoadingPath.value = true;
uni.showLoading({
title: '加载中...',
mask: true
});
try {
if (!jobPathId) {
const response = await getJobPathPage({
jobName: option.label,
pageNo: 1,
pageSize: 100
});
jobPathId = response?.data?.list?.[0]?.id || null;
}
if (!jobPathId) {
uni.showToast({
title: '未找到职业路径',
icon: 'none'
});
resetPathData();
return;
}
selectedJobPathId.value = jobPathId;
await loadPathDetail(jobPathId);
} catch (error) {
console.error('查询职业路径失败:', error);
uni.showToast({
title: '查询失败,请重试',
icon: 'none'
});
} finally {
isLoadingPath.value = false;
uni.hideLoading();
}
}
onMounted(() => {
getCurrentPosition();
// 获取当前职位信息(从接口获取)
async function getCurrentPosition() {
// TODO: 调用接口获取当前职位
// const response = await getCareerCurrentPosition();
// if (response && response.code === 200) {
// currentPosition.value = response.data?.position || '';
// }
}
onMounted(async () => {
await getCurrentPosition();
await Promise.all([
fetchTargetCareerOptions(),
fetchPathCount()
]);
});
</script>
@@ -291,6 +419,13 @@ onMounted(() => {
padding: 0;
}
.path-summary {
margin-top: 16rpx;
font-size: 24rpx;
color: #666666;
text-align: center;
}
.path-section {
background-color: #FFFFFF;
border-radius: 16rpx;