fix: 修复
This commit is contained in:
@@ -40,9 +40,20 @@
|
||||
:current-job-id="currentJobId"
|
||||
:current-job-name="currentJobName"
|
||||
@job-card-click="handleJobCardClick"
|
||||
@skills-updated="handleRecommendSkillsUpdated"
|
||||
/>
|
||||
<CareerPath
|
||||
v-else-if="activeTab === 1"
|
||||
:current-job-name="currentJobName"
|
||||
@path-data-updated="handlePathDataUpdated"
|
||||
/>
|
||||
<SkillDevelopment
|
||||
v-else
|
||||
:current-job-skills="recommendSkillsData.currentJobSkills"
|
||||
:recommended-jobs="recommendSkillsData.recommendedJobs"
|
||||
:path-data="pathSkillsData.pathData"
|
||||
:target-career="pathSkillsData.targetCareer"
|
||||
/>
|
||||
<CareerPath v-else-if="activeTab === 1" />
|
||||
<SkillDevelopment v-else />
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
@@ -56,8 +67,8 @@
|
||||
<script setup>
|
||||
import { ref, inject, nextTick, onMounted } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { appUserInfo } from '@/apiRc/user/user.js';
|
||||
import { getJobSkillDetail } from '@/apiRc/jobSkill.js';
|
||||
import { appUserInfo } from '@/apiRc/user/user.js';
|
||||
import RemindPopup from './components/RemindPopup.vue';
|
||||
import PageHeader from './components/PageHeader.vue';
|
||||
import SkillDetailPopup from './components/SkillDetailPopup.vue';
|
||||
@@ -66,7 +77,7 @@ import CareerPath from './components/CareerPath.vue';
|
||||
import SkillDevelopment from './components/SkillDevelopment.vue';
|
||||
import CustomTabBar from '@/components/CustomTabBar/CustomTabBar.vue';
|
||||
|
||||
const { navBack } = inject('globalFunction');
|
||||
const { navBack, navTo } = inject('globalFunction');
|
||||
|
||||
// 弹窗引用
|
||||
const remindPopup = ref(null);
|
||||
@@ -85,80 +96,150 @@ const isLoadingJobSkill = ref(false);
|
||||
const currentJobId = ref(null);
|
||||
const currentJobName = ref('');
|
||||
|
||||
// 技能发展所需的数据
|
||||
const recommendSkillsData = ref({
|
||||
currentJobSkills: [],
|
||||
recommendedJobs: []
|
||||
});
|
||||
|
||||
const pathSkillsData = ref({
|
||||
pathData: {
|
||||
start: { title: '', skills: [] },
|
||||
steps: [],
|
||||
end: { title: '', skills: [] }
|
||||
},
|
||||
targetCareer: ''
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
function openRemindPopup() {
|
||||
nextTick(() => {
|
||||
if (remindPopup.value) {
|
||||
remindPopup.value.open();
|
||||
try {
|
||||
remindPopup.value.open();
|
||||
} catch (error) {
|
||||
// 静默处理错误
|
||||
}
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
if (remindPopup.value) {
|
||||
remindPopup.value.open();
|
||||
try {
|
||||
remindPopup.value.open();
|
||||
} catch (error) {
|
||||
// 静默处理错误
|
||||
}
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
remindPopup.value?.open();
|
||||
}, 200);
|
||||
if (remindPopup.value) {
|
||||
try {
|
||||
remindPopup.value.open();
|
||||
} catch (error) {
|
||||
// 静默处理错误
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
}, 300);
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 获取提醒信息的接口
|
||||
// 检查用户是否完善了个人信息(调用接口获取)
|
||||
let hasCheckedRemindInfo = false;
|
||||
|
||||
async function getRemindInfo() {
|
||||
if (hasCheckedRemindInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
hasCheckedRemindInfo = true;
|
||||
|
||||
try {
|
||||
const response = await appUserInfo();
|
||||
if (response && response.code === 200) {
|
||||
const data = response.data || {};
|
||||
const reminders = [];
|
||||
|
||||
currentJobId.value = data?.jobId ?? data?.currentJobId ?? null;
|
||||
currentJobName.value = data?.jobName ?? data?.currentJobName ?? '';
|
||||
|
||||
if (Array.isArray(data.remindList) && data.remindList.length > 0) {
|
||||
reminders.push(
|
||||
...data.remindList
|
||||
.filter(item => typeof item === 'string' && item.trim().length > 0)
|
||||
.map(item => item.trim())
|
||||
);
|
||||
} else {
|
||||
const jobTitles = Array.isArray(data.jobTitles) ? data.jobTitles : [];
|
||||
const appSkillsList = Array.isArray(data.appSkillsList) ? data.appSkillsList : [];
|
||||
|
||||
if (!currentJobName.value && jobTitles.length > 0) {
|
||||
currentJobName.value = jobTitles[0];
|
||||
}
|
||||
|
||||
if (jobTitles.length === 0) {
|
||||
reminders.push('请完善求职期望');
|
||||
}
|
||||
|
||||
if (appSkillsList.length === 0) {
|
||||
reminders.push('请完善技能信息');
|
||||
}
|
||||
}
|
||||
|
||||
if (reminders.length === 0) {
|
||||
reminders.push('暂无待完善信息');
|
||||
}
|
||||
|
||||
remindList.value = reminders;
|
||||
if (!currentJobName.value) {
|
||||
currentJobName.value = '前端开发工程师';
|
||||
}
|
||||
openRemindPopup();
|
||||
return;
|
||||
const userInfo = response?.data || {};
|
||||
|
||||
// 优先从接口数据中获取 idCard
|
||||
let idCard = userInfo?.resume?.idCard ?? userInfo?.idCard ?? null;
|
||||
|
||||
// 如果接口返回的数据中没有 idCard,则从缓存中读取
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
if (!idCard || idCard === null || idCard === '') {
|
||||
idCard = cachedUserInfo?.resume?.idCard ?? cachedUserInfo?.idCard ?? null;
|
||||
}
|
||||
|
||||
throw new Error('接口返回异常');
|
||||
} catch (error) {
|
||||
console.error('获取提醒信息失败:', error);
|
||||
currentJobId.value = null;
|
||||
|
||||
// 优先从接口数据中获取职位信息
|
||||
currentJobId.value = userInfo?.jobId ??
|
||||
userInfo?.currentJobId ??
|
||||
userInfo?.resume?.jobId ??
|
||||
userInfo?.resume?.currentJobId ??
|
||||
null;
|
||||
currentJobName.value = userInfo?.jobName ??
|
||||
userInfo?.currentJobName ??
|
||||
userInfo?.resume?.jobName ??
|
||||
userInfo?.resume?.currentJobName ??
|
||||
'';
|
||||
|
||||
// 如果接口数据中没有职位信息,从缓存中读取
|
||||
if (!currentJobId.value && !currentJobName.value) {
|
||||
currentJobId.value = cachedUserInfo?.jobId ??
|
||||
cachedUserInfo?.currentJobId ??
|
||||
cachedUserInfo?.resume?.jobId ??
|
||||
cachedUserInfo?.resume?.currentJobId ??
|
||||
null;
|
||||
currentJobName.value = cachedUserInfo?.jobName ??
|
||||
cachedUserInfo?.currentJobName ??
|
||||
cachedUserInfo?.resume?.jobName ??
|
||||
cachedUserInfo?.resume?.currentJobName ??
|
||||
'';
|
||||
}
|
||||
|
||||
// 如果还是没有职位信息,使用默认值
|
||||
if (!currentJobName.value) {
|
||||
currentJobName.value = '前端开发工程师';
|
||||
currentJobName.value = '市场专员';
|
||||
}
|
||||
remindList.value = ['获取提醒信息失败,请稍后重试'];
|
||||
openRemindPopup();
|
||||
|
||||
// 判断 idCard 是否存在(包括空字符串、undefined、null 的情况)
|
||||
const hasIdCard = idCard !== null && idCard !== undefined && idCard !== '';
|
||||
|
||||
if (!hasIdCard) {
|
||||
remindList.value = ['请完善个人信息'];
|
||||
} else {
|
||||
remindList.value = ['暂无待完善信息'];
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
openRemindPopup();
|
||||
}, 500);
|
||||
} catch (error) {
|
||||
// 接口调用失败时,使用缓存作为降级方案
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
const idCard = cachedUserInfo?.resume?.idCard ?? cachedUserInfo?.idCard ?? null;
|
||||
|
||||
// 从缓存中获取职位信息
|
||||
currentJobId.value = cachedUserInfo?.jobId ??
|
||||
cachedUserInfo?.currentJobId ??
|
||||
cachedUserInfo?.resume?.jobId ??
|
||||
cachedUserInfo?.resume?.currentJobId ??
|
||||
null;
|
||||
currentJobName.value = cachedUserInfo?.jobName ??
|
||||
cachedUserInfo?.currentJobName ??
|
||||
cachedUserInfo?.resume?.jobName ??
|
||||
cachedUserInfo?.resume?.currentJobName ??
|
||||
'';
|
||||
// 如果缓存中没有职位信息,使用默认值
|
||||
if (!currentJobName.value) {
|
||||
currentJobName.value = '市场专员';
|
||||
}
|
||||
|
||||
if (!idCard || idCard === null || idCard === '') {
|
||||
remindList.value = ['请完善个人信息'];
|
||||
} else {
|
||||
remindList.value = ['暂无待完善信息'];
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
openRemindPopup();
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,30 +250,87 @@ function handleCancel() {
|
||||
}
|
||||
|
||||
// 确认按钮
|
||||
function handleConfirm() {
|
||||
async function handleConfirm() {
|
||||
remindPopup.value?.close();
|
||||
|
||||
// 直接从缓存中读取 idCard(因为接口返回的数据中没有 idCard)
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
let idCard = cachedUserInfo?.resume?.idCard ?? cachedUserInfo?.idCard ?? null;
|
||||
|
||||
// 如果缓存中也没有,尝试从接口获取(虽然接口通常也没有)
|
||||
if (!idCard || idCard === null || idCard === '') {
|
||||
try {
|
||||
const response = await appUserInfo();
|
||||
const userInfo = response?.data || {};
|
||||
idCard = userInfo?.resume?.idCard ?? userInfo?.idCard ?? null;
|
||||
} catch (error) {
|
||||
// 接口调用失败,继续使用缓存数据
|
||||
}
|
||||
}
|
||||
|
||||
// 如果 idCard 为空,才跳转到完善信息页面
|
||||
if (!idCard || idCard === null || idCard === '') {
|
||||
navTo('/pages/complete-info/complete-info');
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果 idCard 存在,说明已经完善了信息,直接显示页面内容
|
||||
// 从缓存中更新职位信息
|
||||
currentJobId.value = cachedUserInfo?.jobId ??
|
||||
cachedUserInfo?.currentJobId ??
|
||||
cachedUserInfo?.resume?.jobId ??
|
||||
cachedUserInfo?.resume?.currentJobId ??
|
||||
null;
|
||||
currentJobName.value = cachedUserInfo?.jobName ??
|
||||
cachedUserInfo?.currentJobName ??
|
||||
cachedUserInfo?.resume?.jobName ??
|
||||
cachedUserInfo?.resume?.currentJobName ??
|
||||
'';
|
||||
if (!currentJobName.value) {
|
||||
currentJobName.value = '市场专员';
|
||||
}
|
||||
|
||||
showContent.value = true;
|
||||
}
|
||||
|
||||
// 切换tab
|
||||
function switchTab(index) {
|
||||
activeTab.value = index;
|
||||
|
||||
if (index === 0 && !currentJobId.value) {
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
|
||||
const newJobId = cachedUserInfo?.jobId ??
|
||||
cachedUserInfo?.currentJobId ??
|
||||
cachedUserInfo?.resume?.jobId ??
|
||||
cachedUserInfo?.resume?.currentJobId ??
|
||||
null;
|
||||
|
||||
const newJobName = currentJobName.value ||
|
||||
(cachedUserInfo?.jobName ??
|
||||
cachedUserInfo?.currentJobName ??
|
||||
cachedUserInfo?.resume?.jobName ??
|
||||
cachedUserInfo?.resume?.currentJobName ??
|
||||
'市场专员');
|
||||
|
||||
currentJobId.value = newJobId;
|
||||
currentJobName.value = newJobName;
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索点击
|
||||
function handleSearchClick() {
|
||||
// TODO: 跳转到搜索页面
|
||||
console.log('搜索点击');
|
||||
navTo('/pages/search/search');
|
||||
}
|
||||
|
||||
// 菜单点击
|
||||
function handleMenuClick() {
|
||||
console.log('菜单点击');
|
||||
// TODO: 实现菜单功能
|
||||
}
|
||||
|
||||
// 更多点击
|
||||
function handleMoreClick() {
|
||||
console.log('更多点击');
|
||||
// TODO: 实现更多功能
|
||||
}
|
||||
|
||||
function normalizeSkillLevel(score) {
|
||||
@@ -278,7 +416,6 @@ async function handleJobCardClick(job) {
|
||||
}
|
||||
skillDetailPopup.value?.open();
|
||||
} catch (error) {
|
||||
console.error('获取职位技能详情失败:', error);
|
||||
if (fallbackSkills.length > 0) {
|
||||
const fallbackSplit = splitSkillListByScore(fallbackSkills);
|
||||
selectedJobPossessedSkills.value = fallbackSplit.possessed;
|
||||
@@ -301,13 +438,37 @@ function handleSkillPopupClose() {
|
||||
// 可以在这里处理关闭后的逻辑
|
||||
}
|
||||
|
||||
// 处理职业推荐技能数据更新
|
||||
function handleRecommendSkillsUpdated(data) {
|
||||
recommendSkillsData.value = {
|
||||
currentJobSkills: data.currentJobSkills || [],
|
||||
recommendedJobs: data.recommendedJobs || []
|
||||
};
|
||||
}
|
||||
|
||||
// 处理职业路径数据更新
|
||||
function handlePathDataUpdated(data) {
|
||||
pathSkillsData.value = {
|
||||
pathData: data.pathData || {
|
||||
start: { title: '', skills: [] },
|
||||
steps: [],
|
||||
end: { title: '', skills: [] }
|
||||
},
|
||||
targetCareer: data.targetCareer || ''
|
||||
};
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
getRemindInfo();
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
if (remindList.value.length > 0 && !showContent.value) {
|
||||
openRemindPopup();
|
||||
setTimeout(() => {
|
||||
if (remindPopup.value) {
|
||||
openRemindPopup();
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -349,7 +510,6 @@ onMounted(() => {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
padding-bottom: 88rpx;
|
||||
}
|
||||
|
||||
|
||||
@@ -357,6 +517,8 @@ onMounted(() => {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
width: 100%;
|
||||
padding-bottom: calc(88rpx + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.tabbar-wrapper {
|
||||
@@ -366,4 +528,4 @@ onMounted(() => {
|
||||
right: 0;
|
||||
z-index: 999;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<input
|
||||
class="input-field"
|
||||
:value="currentPosition"
|
||||
placeholder="前端开发工程师"
|
||||
placeholder="市场专员"
|
||||
placeholder-style="color: #999999"
|
||||
disabled
|
||||
/>
|
||||
@@ -115,11 +115,21 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { getJobPathPage, getJobPathDetail, getJobPathNum } from '@/apiRc/jobPath.js';
|
||||
|
||||
// 当前职位(从接口获取,只读)
|
||||
const currentPosition = ref('前端开发工程师');
|
||||
// 接收父组件传递的当前职位名称
|
||||
const props = defineProps({
|
||||
currentJobName: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['path-data-updated']);
|
||||
|
||||
// 当前职位(从父组件获取,统一使用)
|
||||
const currentPosition = computed(() => props.currentJobName || '市场专员');
|
||||
|
||||
// 目标职业选项列表
|
||||
const targetCareerOptions = ref([]);
|
||||
@@ -170,7 +180,9 @@ async function fetchTargetCareerOptions(keyword = '') {
|
||||
pageNo: 1,
|
||||
pageSize: 100
|
||||
});
|
||||
const list = response?.data?.list || [];
|
||||
|
||||
const list = response?.data?.list || response?.list || [];
|
||||
|
||||
targetCareerOptions.value = list.map(item => ({
|
||||
label: item.endJob || item.startJob || '未知职位',
|
||||
value: item.id,
|
||||
@@ -184,7 +196,6 @@ async function fetchTargetCareerOptions(keyword = '') {
|
||||
selectedJobPathId.value = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取职业路径列表失败:', error);
|
||||
targetCareerOptions.value = [];
|
||||
selectedTargetIndex.value = -1;
|
||||
selectedJobPathId.value = null;
|
||||
@@ -200,17 +211,29 @@ async function fetchPathCount() {
|
||||
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
|
||||
if (!jobPathId || jobPathId === null || jobPathId === undefined || jobPathId === '') {
|
||||
uni.showToast({
|
||||
title: '职业路径ID无效',
|
||||
icon: 'none'
|
||||
});
|
||||
resetPathData();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const requestParams = {
|
||||
jobPathId: jobPathId
|
||||
};
|
||||
|
||||
const response = await getJobPathDetail(requestParams);
|
||||
|
||||
const details = Array.isArray(response?.data) ? response.data : [];
|
||||
|
||||
if (details.length === 0) {
|
||||
resetPathData();
|
||||
uni.showToast({
|
||||
@@ -234,12 +257,22 @@ async function loadPathDetail(jobPathId) {
|
||||
steps,
|
||||
end
|
||||
};
|
||||
|
||||
// 通知父组件路径数据已更新
|
||||
emit('path-data-updated', {
|
||||
pathData: pathData.value,
|
||||
targetCareer: targetCareerOptions.value[selectedTargetIndex.value]?.label || ''
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取职业路径详情失败:', error);
|
||||
uni.showToast({
|
||||
title: '获取路径详情失败',
|
||||
icon: 'none'
|
||||
});
|
||||
resetPathData();
|
||||
emit('path-data-updated', {
|
||||
pathData: { ...emptyPathData },
|
||||
targetCareer: ''
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,7 +331,6 @@ async function handleQuery() {
|
||||
selectedJobPathId.value = jobPathId;
|
||||
await loadPathDetail(jobPathId);
|
||||
} catch (error) {
|
||||
console.error('查询职业路径失败:', error);
|
||||
uni.showToast({
|
||||
title: '查询失败,请重试',
|
||||
icon: 'none'
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
<!-- 相似推荐职位 -->
|
||||
<view class="section-title">
|
||||
相似推荐职位
|
||||
<text v-if="recommendRecordCount > 0" class="recommend-count">共{{ recommendRecordCount }}条记录</text>
|
||||
</view>
|
||||
<view v-if="!isLoadingRecommend && recommendedJobs.length === 0" class="empty-text">暂无推荐职位</view>
|
||||
<view
|
||||
@@ -54,9 +53,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import { ref, computed, watch, onMounted } from 'vue';
|
||||
import { recommendJob } from '@/apiRc/jobRecommend.js';
|
||||
import { getJobSkillDetail } from '@/apiRc/jobSkill.js';
|
||||
import { recommendJob, countJobRecommendRecords, getJobRecommendRecords } from '@/apiRc/jobRecommend.js';
|
||||
|
||||
const props = defineProps({
|
||||
currentJobId: {
|
||||
@@ -69,127 +68,167 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['job-card-click']);
|
||||
const emit = defineEmits(['job-card-click', 'skills-updated']);
|
||||
|
||||
// 数据状态
|
||||
const skillTags = ref([]);
|
||||
const recommendedJobs = ref([]);
|
||||
const recommendRecordCount = ref(0);
|
||||
const recommendRecords = ref([]);
|
||||
const isLoadingSkillTags = ref(false);
|
||||
const isLoadingRecommend = ref(false);
|
||||
const isLoadingRecords = ref(false);
|
||||
|
||||
const currentJobDisplay = computed(() => props.currentJobName || '前端开发工程师');
|
||||
// 计算属性
|
||||
const currentJobDisplay = computed(() => props.currentJobName || '市场专员');
|
||||
|
||||
function normalizeSkillListForDisplay(skillList = []) {
|
||||
// 从技能列表中提取技能名称用于显示
|
||||
function extractSkillNames(skillList = []) {
|
||||
return (Array.isArray(skillList) ? skillList : [])
|
||||
.map(item => item?.skillName)
|
||||
.filter(name => !!name);
|
||||
.map(item => item?.skillName || '')
|
||||
.filter(name => !!name && name.trim().length > 0);
|
||||
}
|
||||
|
||||
// 获取当前职位的技能标签
|
||||
async function fetchCurrentJobSkills() {
|
||||
if (!props.currentJobId && !props.currentJobName) {
|
||||
skillTags.value = [];
|
||||
// 如果没有职位名称,从缓存中获取技能标签
|
||||
if (!props.currentJobName || props.currentJobName === '市场专员') {
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
const cachedSkills = cachedUserInfo?.resume?.skillList ??
|
||||
cachedUserInfo?.skillList ??
|
||||
cachedUserInfo?.appSkillsList ??
|
||||
[];
|
||||
|
||||
// 如果缓存中有技能数据,使用缓存的数据
|
||||
if (Array.isArray(cachedSkills) && cachedSkills.length > 0) {
|
||||
skillTags.value = extractSkillNames(cachedSkills);
|
||||
} else {
|
||||
skillTags.value = [];
|
||||
}
|
||||
|
||||
// 通知父组件技能数据已更新
|
||||
emit('skills-updated', {
|
||||
currentJobSkills: skillTags.value,
|
||||
recommendedJobs: recommendedJobs.value
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 优先调用接口获取技能数据
|
||||
isLoadingSkillTags.value = true;
|
||||
try {
|
||||
const params = {};
|
||||
if (props.currentJobId !== null && props.currentJobId !== undefined && props.currentJobId !== '') {
|
||||
params.jobId = props.currentJobId;
|
||||
const response = await getJobSkillDetail({
|
||||
jobName: props.currentJobName
|
||||
});
|
||||
|
||||
const skillList = Array.isArray(response?.data) ? response.data : [];
|
||||
const apiSkills = extractSkillNames(skillList);
|
||||
|
||||
// 如果接口返回了技能数据,使用接口数据
|
||||
if (apiSkills.length > 0) {
|
||||
skillTags.value = apiSkills;
|
||||
} else {
|
||||
// 如果接口没有返回技能数据,从缓存中读取
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
const cachedSkills = cachedUserInfo?.resume?.skillList ??
|
||||
cachedUserInfo?.skillList ??
|
||||
cachedUserInfo?.appSkillsList ??
|
||||
[];
|
||||
|
||||
if (Array.isArray(cachedSkills) && cachedSkills.length > 0) {
|
||||
skillTags.value = extractSkillNames(cachedSkills);
|
||||
} else {
|
||||
skillTags.value = [];
|
||||
}
|
||||
}
|
||||
if (props.currentJobName) {
|
||||
params.jobName = props.currentJobName;
|
||||
}
|
||||
const response = await getJobSkillDetail(params);
|
||||
const list = Array.isArray(response?.data) ? response.data : [];
|
||||
skillTags.value = normalizeSkillListForDisplay(list);
|
||||
|
||||
// 通知父组件技能数据已更新
|
||||
emit('skills-updated', {
|
||||
currentJobSkills: skillTags.value,
|
||||
recommendedJobs: recommendedJobs.value
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取当前职位技能失败:', error);
|
||||
skillTags.value = [];
|
||||
// 接口调用失败时,从缓存中读取
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
const cachedSkills = cachedUserInfo?.resume?.skillList ??
|
||||
cachedUserInfo?.skillList ??
|
||||
cachedUserInfo?.appSkillsList ??
|
||||
[];
|
||||
|
||||
if (Array.isArray(cachedSkills) && cachedSkills.length > 0) {
|
||||
skillTags.value = extractSkillNames(cachedSkills);
|
||||
} else {
|
||||
skillTags.value = [];
|
||||
}
|
||||
|
||||
emit('skills-updated', {
|
||||
currentJobSkills: skillTags.value,
|
||||
recommendedJobs: recommendedJobs.value
|
||||
});
|
||||
} finally {
|
||||
isLoadingSkillTags.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取推荐职位列表
|
||||
async function fetchRecommendedJobs() {
|
||||
const hasJobId = props.currentJobId !== null && props.currentJobId !== undefined && props.currentJobId !== '';
|
||||
if (!hasJobId) {
|
||||
recommendedJobs.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
isLoadingRecommend.value = true;
|
||||
try {
|
||||
const response = await recommendJob({
|
||||
jobId: props.currentJobId
|
||||
jobName: props.currentJobName
|
||||
});
|
||||
|
||||
const list = Array.isArray(response?.data) ? response.data : [];
|
||||
|
||||
recommendedJobs.value = list.map((item, index) => {
|
||||
const rawSkills = Array.isArray(item?.skillList) ? item.skillList : [];
|
||||
const skillList = Array.isArray(item?.skillList) ? item.skillList : [];
|
||||
const skillNames = extractSkillNames(skillList);
|
||||
|
||||
return {
|
||||
id: item?.jobId ?? index,
|
||||
jobId: item?.jobId ?? null,
|
||||
title: item?.jobName || `推荐职位${index + 1}`,
|
||||
jobName: item?.jobName || '',
|
||||
skills: normalizeSkillListForDisplay(rawSkills),
|
||||
rawSkills
|
||||
skills: skillNames,
|
||||
rawSkills: skillList
|
||||
};
|
||||
});
|
||||
|
||||
// 通知父组件推荐职位数据已更新
|
||||
emit('skills-updated', {
|
||||
currentJobSkills: skillTags.value,
|
||||
recommendedJobs: recommendedJobs.value
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取推荐职位失败:', error);
|
||||
recommendedJobs.value = [];
|
||||
emit('skills-updated', {
|
||||
currentJobSkills: skillTags.value,
|
||||
recommendedJobs: []
|
||||
});
|
||||
} finally {
|
||||
isLoadingRecommend.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchRecommendRecordInfo() {
|
||||
const hasJobId = props.currentJobId !== null && props.currentJobId !== undefined && props.currentJobId !== '';
|
||||
const hasJobName = !!props.currentJobName;
|
||||
if (!hasJobId && !hasJobName) {
|
||||
recommendRecordCount.value = 0;
|
||||
recommendRecords.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
isLoadingRecords.value = true;
|
||||
try {
|
||||
const [countRes, listRes] = await Promise.all([
|
||||
countJobRecommendRecords({
|
||||
jobId: hasJobId ? props.currentJobId : undefined,
|
||||
jobName: props.currentJobName
|
||||
}),
|
||||
getJobRecommendRecords({
|
||||
jobName: props.currentJobName || '',
|
||||
pageNo: 1,
|
||||
pageSize: 10
|
||||
})
|
||||
]);
|
||||
recommendRecordCount.value = Number(countRes?.data) || 0;
|
||||
recommendRecords.value = Array.isArray(listRes?.data?.list) ? listRes.data.list : [];
|
||||
} catch (error) {
|
||||
console.error('获取推荐记录失败:', error);
|
||||
recommendRecordCount.value = 0;
|
||||
recommendRecords.value = [];
|
||||
} finally {
|
||||
isLoadingRecords.value = false;
|
||||
}
|
||||
}
|
||||
// 组件挂载时检查并调用
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
if (props.currentJobName) {
|
||||
fetchCurrentJobSkills();
|
||||
fetchRecommendedJobs();
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
|
||||
// 监听 props 变化,自动获取推荐职位和技能标签
|
||||
watch(
|
||||
() => [props.currentJobId, props.currentJobName],
|
||||
() => {
|
||||
fetchCurrentJobSkills();
|
||||
fetchRecommendedJobs();
|
||||
fetchRecommendRecordInfo();
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 事件处理
|
||||
function handleJobSearch(job) {
|
||||
console.log('搜索职位:', job.title);
|
||||
// TODO: 实现职位搜索跳转
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 搜索栏 -->
|
||||
<view class="search-bar" @click="handleSearchClick">
|
||||
<view class="search-bar" @click.stop="handleSearchClick" @tap.stop="handleSearchClick">
|
||||
<uni-icons class="search-icon" type="search" size="18" color="#999999"></uni-icons>
|
||||
<text class="search-placeholder">职位名称、薪资要求等</text>
|
||||
</view>
|
||||
@@ -27,21 +27,24 @@
|
||||
<view
|
||||
class="tab-item"
|
||||
:class="{ 'active': activeTab === 0 }"
|
||||
@click="handleTabClick(0)"
|
||||
@click.stop="handleTabClick(0)"
|
||||
@tap.stop="handleTabClick(0)"
|
||||
>
|
||||
职业推荐
|
||||
</view>
|
||||
<view
|
||||
class="tab-item"
|
||||
:class="{ 'active': activeTab === 1 }"
|
||||
@click="handleTabClick(1)"
|
||||
@click.stop="handleTabClick(1)"
|
||||
@tap.stop="handleTabClick(1)"
|
||||
>
|
||||
职业路径
|
||||
</view>
|
||||
<view
|
||||
class="tab-item"
|
||||
:class="{ 'active': activeTab === 2 }"
|
||||
@click="handleTabClick(2)"
|
||||
@click.stop="handleTabClick(2)"
|
||||
@tap.stop="handleTabClick(2)"
|
||||
>
|
||||
技能发展
|
||||
</view>
|
||||
@@ -156,6 +159,11 @@ function handleMoreClick() {
|
||||
gap: 16rpx;
|
||||
height: 88rpx;
|
||||
box-shadow: none;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
pointer-events: auto;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
@@ -175,6 +183,9 @@ function handleMoreClick() {
|
||||
padding: 6rpx 20rpx;
|
||||
margin-bottom: 10rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.tab-nav {
|
||||
@@ -191,6 +202,10 @@ function handleMoreClick() {
|
||||
background-color: transparent;
|
||||
text-align: center;
|
||||
transition: all 0.3s;
|
||||
position: relative;
|
||||
pointer-events: auto;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.tab-item.active {
|
||||
|
||||
@@ -43,13 +43,17 @@ const popupRef = ref(null);
|
||||
// 打开弹窗
|
||||
function open() {
|
||||
if (popupRef.value) {
|
||||
popupRef.value.open('center');
|
||||
try {
|
||||
popupRef.value.open();
|
||||
} catch (error) {
|
||||
// 静默处理错误
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
function close() {
|
||||
popupRef.value?.close('center');
|
||||
popupRef.value?.close();
|
||||
}
|
||||
|
||||
// 取消按钮
|
||||
|
||||
@@ -46,45 +46,103 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import SkillWeightPopup from './SkillWeightPopup.vue';
|
||||
import { getSkillNum, getSkillsHeatAnalysisList } from '@/apiRc/jobSkill.js';
|
||||
|
||||
// 技能列表(后续从接口获取)
|
||||
const skillList = ref([
|
||||
{
|
||||
name: '项目管理(PMP)',
|
||||
weight: '0.98',
|
||||
tags: ['核心技能', '管理能力'],
|
||||
currentLevel: 3
|
||||
const props = defineProps({
|
||||
// 来自职业推荐 tab 的数据
|
||||
currentJobSkills: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
{
|
||||
name: '团队领导力',
|
||||
weight: '0.90',
|
||||
tags: ['核心技能', '软技能'],
|
||||
currentLevel: 2
|
||||
recommendedJobs: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
{
|
||||
name: '云安全架构',
|
||||
weight: '0.85',
|
||||
tags: ['技术技能', '网络安全'],
|
||||
currentLevel: 4
|
||||
// 来自职业路径 tab 的数据
|
||||
pathData: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
start: { title: '', skills: [] },
|
||||
steps: [],
|
||||
end: { title: '', skills: [] }
|
||||
})
|
||||
},
|
||||
{
|
||||
name: '财务预算规划',
|
||||
weight: '0.60',
|
||||
tags: ['软技能', '管理能力'],
|
||||
currentLevel: 1
|
||||
targetCareer: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
// 技能数量
|
||||
const skillCount = ref(0);
|
||||
const isLoadingSkillCount = ref(false);
|
||||
|
||||
// 技能热度分析列表
|
||||
const heatAnalysisList = ref([]);
|
||||
const isLoadingHeatAnalysis = ref(false);
|
||||
// 综合技能列表(基于前两个 tab 的数据)
|
||||
const skillList = computed(() => {
|
||||
const skillMap = new Map();
|
||||
|
||||
// 1. 收集当前职位技能(已有技能,权重较低)
|
||||
props.currentJobSkills.forEach(skill => {
|
||||
if (skill && skill.trim()) {
|
||||
const existing = skillMap.get(skill) || { name: skill, weight: 0, tags: [], currentLevel: 0 };
|
||||
existing.weight = Math.max(existing.weight, 0.3); // 已有技能权重较低
|
||||
existing.tags.push('当前技能');
|
||||
skillMap.set(skill, existing);
|
||||
}
|
||||
});
|
||||
|
||||
// 2. 收集推荐职位的技能(需要发展的技能,权重较高)
|
||||
props.recommendedJobs.forEach(job => {
|
||||
if (Array.isArray(job.skills)) {
|
||||
job.skills.forEach(skill => {
|
||||
if (skill && skill.trim()) {
|
||||
const existing = skillMap.get(skill) || { name: skill, weight: 0, tags: [], currentLevel: 0 };
|
||||
existing.weight = Math.max(existing.weight, 0.7); // 推荐职位技能权重较高
|
||||
if (!existing.tags.includes('推荐技能')) {
|
||||
existing.tags.push('推荐技能');
|
||||
}
|
||||
skillMap.set(skill, existing);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 3. 收集职业路径中的技能(发展路径技能,权重最高)
|
||||
const pathSkills = [];
|
||||
if (props.pathData.start && Array.isArray(props.pathData.start.skills)) {
|
||||
pathSkills.push(...props.pathData.start.skills);
|
||||
}
|
||||
if (Array.isArray(props.pathData.steps)) {
|
||||
props.pathData.steps.forEach(step => {
|
||||
if (Array.isArray(step.skills)) {
|
||||
pathSkills.push(...step.skills);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (props.pathData.end && Array.isArray(props.pathData.end.skills)) {
|
||||
pathSkills.push(...props.pathData.end.skills);
|
||||
}
|
||||
|
||||
pathSkills.forEach(skill => {
|
||||
if (skill && skill.trim()) {
|
||||
const existing = skillMap.get(skill) || { name: skill, weight: 0, tags: [], currentLevel: 0 };
|
||||
existing.weight = Math.max(existing.weight, 0.9); // 路径技能权重最高
|
||||
if (!existing.tags.includes('路径技能')) {
|
||||
existing.tags.push('路径技能');
|
||||
}
|
||||
skillMap.set(skill, existing);
|
||||
}
|
||||
});
|
||||
|
||||
// 转换为数组并按权重排序
|
||||
const result = Array.from(skillMap.values())
|
||||
.map(item => ({
|
||||
name: item.name,
|
||||
weight: item.weight.toFixed(2),
|
||||
tags: [...new Set(item.tags)], // 去重
|
||||
currentLevel: item.currentLevel || Math.floor(item.weight * 5) + 1 // 根据权重计算等级
|
||||
}))
|
||||
.sort((a, b) => parseFloat(b.weight) - parseFloat(a.weight)); // 按权重降序
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
// 弹出层引用
|
||||
const skillWeightPopup = ref(null);
|
||||
@@ -94,52 +152,6 @@ const selectedSkillName = ref('');
|
||||
const selectedSkillWeight = ref('');
|
||||
const selectedSkillLevel = ref(0);
|
||||
|
||||
// 获取技能数量
|
||||
async function fetchSkillNum(skillType = null) {
|
||||
isLoadingSkillCount.value = true;
|
||||
try {
|
||||
const response = await getSkillNum({
|
||||
skillType: skillType
|
||||
});
|
||||
skillCount.value = response?.data ?? 0;
|
||||
} catch (error) {
|
||||
console.error('获取技能数量失败:', error);
|
||||
skillCount.value = 0;
|
||||
} finally {
|
||||
isLoadingSkillCount.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取技能热度分析列表
|
||||
async function fetchSkillsHeatAnalysis(startDate, endDate) {
|
||||
isLoadingHeatAnalysis.value = true;
|
||||
try {
|
||||
const params = {};
|
||||
if (startDate) {
|
||||
params.startDate = startDate;
|
||||
}
|
||||
if (endDate) {
|
||||
params.endDate = endDate;
|
||||
}
|
||||
const response = await getSkillsHeatAnalysisList(params);
|
||||
heatAnalysisList.value = Array.isArray(response?.data) ? response.data : [];
|
||||
} catch (error) {
|
||||
console.error('获取技能热度分析失败:', error);
|
||||
heatAnalysisList.value = [];
|
||||
} finally {
|
||||
isLoadingHeatAnalysis.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取技能发展数据(从接口获取)
|
||||
async function getSkillDevelopmentData() {
|
||||
// TODO: 调用接口获取技能发展数据
|
||||
// const response = await getSkillDevelopment();
|
||||
// if (response && response.code === 200) {
|
||||
// skillList.value = response.data || [];
|
||||
// }
|
||||
}
|
||||
|
||||
// 处理技能项点击
|
||||
function handleSkillItemClick(skill) {
|
||||
selectedSkillName.value = skill.name || '';
|
||||
@@ -152,27 +164,6 @@ function handleSkillItemClick(skill) {
|
||||
function handlePopupClose() {
|
||||
// 可以在这里处理关闭后的逻辑
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getSkillDevelopmentData();
|
||||
// 获取技能数量(不传skillType获取全部)
|
||||
fetchSkillNum();
|
||||
|
||||
// 获取技能热度分析(默认查询最近7天)
|
||||
const endDate = new Date();
|
||||
const startDate = new Date();
|
||||
startDate.setDate(startDate.getDate() - 7);
|
||||
const formatDate = (date) => {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
};
|
||||
fetchSkillsHeatAnalysis(formatDate(startDate), formatDate(endDate));
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
Reference in New Issue
Block a user