fix: 修复

This commit is contained in:
2025-11-12 19:31:46 +08:00
parent 1468002fe2
commit 967317367c
17 changed files with 1002 additions and 560 deletions

View File

@@ -16,10 +16,21 @@ export function getJobPathPage(params) {
// 根据职业路径ID获取详情 // 根据职业路径ID获取详情
export function getJobPathDetail(params) { export function getJobPathDetail(params) {
const requestParams = {};
if (params?.jobPathId !== undefined && params?.jobPathId !== null && params?.jobPathId !== '') {
requestParams.id = params.jobPathId;
} else if (params?.id !== undefined && params?.id !== null && params?.id !== '') {
requestParams.id = params.id;
}
if (!requestParams.id) {
return Promise.reject('缺少必需的 id 参数');
}
return request({ return request({
url: '/jobPath/getJobPathDetail', url: '/jobPath/getJobPathById',
method: 'get', method: 'get',
params, params: requestParams,
baseUrlType: 'zytp' baseUrlType: 'zytp'
}) })
} }
@@ -33,24 +44,3 @@ export function getJobPathNum() {
}) })
} }
// 导入职业路径
export function importJobPath(data) {
return request({
url: '/jobPath/importJobPath',
method: 'post',
data,
baseUrlType: 'zytp'
})
}
// 导出职业路径
export function exportJobPath(params) {
return request({
url: '/jobPath/exportJobPath',
method: 'get',
params,
baseUrlType: 'zytp',
responseType: 'arraybuffer'
})
}

View File

@@ -19,46 +19,15 @@ function createFormData(payload = {}) {
} }
export function recommendJob(data) { export function recommendJob(data) {
const formData = createFormData({ const params = {};
jobId: data?.jobId if (data?.jobName !== undefined && data?.jobName !== null && data?.jobName !== '') {
}) params.jobName = String(data.jobName);
}
return request({ return request({
url: '/job/recommendJob', url: '/job/recommendJobByJobName',
method: 'post',
data: formData,
baseUrlType: 'zytp',
header: {
'content-type': 'multipart/form-data'
}
})
}
export function countJobRecommendRecords(data) {
const formData = createFormData({
jobId: data?.jobId,
jobName: data?.jobName,
recommendType: data?.recommendType,
startDate: data?.startDate,
endDate: data?.endDate
})
return request({
url: '/jobRecommendRecord/countJobRecommendRecords',
method: 'post',
data: formData,
baseUrlType: 'zytp',
header: {
'content-type': 'multipart/form-data'
}
})
}
export function getJobRecommendRecords(params) {
return request({
url: '/jobRecommendRecord/getJobRecommendRecords',
method: 'get', method: 'get',
params, params: params,
baseUrlType: 'zytp' baseUrlType: 'zytp'
}) })
} }

View File

@@ -13,65 +13,33 @@ export function getJobSkillDetail(params) {
}) })
} }
export function getJobPathSkill(data) { // 暂未使用 - 如果需要在 CareerPath.vue 中点击路径职位查看详细技能信息时使用
let formData // 使用场景:获取职业路径中某个职位的详细技能信息(包含技能分数、类型等)
if (typeof FormData !== 'undefined') { // export function getJobPathSkill(data) {
formData = new FormData() // let formData
if (data?.pathId !== undefined && data?.pathId !== null) { // if (typeof FormData !== 'undefined') {
formData.append('pathId', data.pathId) // formData = new FormData()
} // if (data?.pathId !== undefined && data?.pathId !== null) {
if (data?.currentJobName !== undefined && data?.currentJobName !== null) { // formData.append('pathId', data.pathId)
formData.append('currentJobName', data.currentJobName) // }
} // if (data?.currentJobName !== undefined && data?.currentJobName !== null) {
} else { // formData.append('currentJobName', data.currentJobName)
formData = { // }
pathId: data?.pathId ?? '', // } else {
currentJobName: data?.currentJobName ?? '' // formData = {
} // pathId: data?.pathId ?? '',
} // currentJobName: data?.currentJobName ?? ''
// }
// }
return request({ // return request({
url: '/jobSkillDet/getJobPathSkill', // url: '/jobSkillDet/getJobPathSkill',
method: 'post', // method: 'post',
data: formData, // data: formData,
baseUrlType: 'zytp', // baseUrlType: 'zytp',
header: { // header: {
'content-type': 'multipart/form-data' // 'content-type': 'multipart/form-data'
} // }
}) // })
} // }
// 获取技能热度分析列表
export function getSkillsHeatAnalysisList(params) {
return request({
url: '/skillsHeatAnalysis/list',
method: 'get',
params,
baseUrlType: 'zytp'
})
}
// 获取技能数量
export function getSkillNum(data) {
let formData
if (typeof FormData !== 'undefined') {
formData = new FormData()
if (data?.skillType !== undefined && data?.skillType !== null) {
formData.append('skillType', data.skillType)
}
} else {
formData = {
skillType: data?.skillType ?? ''
}
}
return request({
url: '/skill/getSkillNum',
method: 'post',
data: formData,
baseUrlType: 'zytp',
header: {
'content-type': 'multipart/form-data'
}
})
}

View File

@@ -8,7 +8,7 @@ import request from '@/utilsRc/request'
// 获取用户信息(职业规划推荐用) // 获取用户信息(职业规划推荐用)
export function appUserInfo() { export function appUserInfo() {
return request({ return request({
fullUrl: 'http://222.80.110.161:11111/api/ks/app/user/appUserInfo', url: '/app/user/appUserInfo',
method: 'get' method: 'get'
}) })
} }

View File

@@ -4,7 +4,8 @@
class="tabbar-item" class="tabbar-item"
v-for="(item, index) in tabbarList" v-for="(item, index) in tabbarList"
:key="index" :key="index"
@click="switchTab(item, index)" @click.stop="switchTab(item, index)"
@tap.stop="switchTab(item, index)"
> >
<view class="tabbar-icon"> <view class="tabbar-icon">
<image <image
@@ -154,6 +155,8 @@ watch(() => userInfo.value, (newUserInfo, oldUserInfo) => {
// 切换tab // 切换tab
const switchTab = (item, index) => { const switchTab = (item, index) => {
console.log('switchTab called', item, index);
// 检查是否为"发布岗位"页面,需要判断企业信息是否完整 // 检查是否为"发布岗位"页面,需要判断企业信息是否完整
if (item.path === '/pages/job/publishJob') { if (item.path === '/pages/job/publishJob') {
// 检查用户是否已登录 // 检查用户是否已登录
@@ -270,8 +273,9 @@ onMounted(() => {
display: flex; display: flex;
align-items: center; align-items: center;
padding-bottom: env(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom);
z-index: 999; z-index: 9999;
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1); box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
pointer-events: auto;
} }
.tabbar-item { .tabbar-item {
@@ -285,6 +289,8 @@ onMounted(() => {
font-size: 22rpx; font-size: 22rpx;
position: relative; position: relative;
cursor: pointer; cursor: pointer;
pointer-events: auto;
-webkit-tap-highlight-color: transparent;
} }
.tabbar-icon { .tabbar-icon {

View File

@@ -0,0 +1,237 @@
# 职业图谱功能接口说明
## 📋 目录
- [一、职业路径相关接口](#一职业路径相关接口)
- [二、职业技能相关接口](#二职业技能相关接口)
- [三、职业推荐相关接口](#三职业推荐相关接口)
- [四、接口使用场景](#四接口使用场景)
---
## 一、职业路径相关接口
### 1. `getJobPathPage` - 根据职业名称获取路径列表
- **接口路径**: `/jobPath/getJobPathPage`
- **请求方法**: `GET`
- **接口类型**: `zytp`
- **参数**:
- `jobName` (可选): 职业名称,用于搜索
- `pageNo`: 页码
- `pageSize`: 每页数量
- **返回数据**:
```json
{
"code": 0,
"data": {
"list": [
{
"id": 1,
"startJobId": 1,
"startJob": "AI产品经理",
"endJobId": 1,
"endJob": "推荐算法",
"jobOrder": "AI产品经理AI训练师图像识别导航算法推荐算法",
"jobCount": 5
}
],
"total": 16
}
}
```
- **使用场景**:
- ✅ **CareerPath.vue**: 获取目标职业选项列表(下拉选择器)
- ✅ **CareerRecommend.vue**: 通过 `jobName` 查询获取 `jobId`(当缺少 jobId 时)
- ✅ **CareerPath.vue**: 查询时如果没有 jobPathId通过 jobName 查找
---
### 2. ``getJobPathById`- 根据职业路径ID获取详情
- **接口路径**: `/jobPath/getJobPathById`
- **请求方法**: `GET`
- **接口类型**: `zytp`
- **参数**:
- `jobPathId`: 职业路径ID
- **返回数据**:
```json
{
"data": [
{
"name": "职位名称",
"skillNameList": "技能1,技能2,技能3"
}
]
}
```
- **使用场景**:
- ✅ **CareerPath.vue**: 获取职业路径的详细信息(起点、中间步骤、终点及每个职位的技能列表)
- 用于显示完整的职业发展路径时间线
---
### 3. `getJobPathNum` - 获取职业路径数量
- **接口路径**: `/jobPath/getJobPathNum`
- **请求方法**: `GET`
- **接口类型**: `zytp`
- **参数**: 无
- **返回数据**:
```json
{
"data": 16 // 路径总数
}
```
- **使用场景**:
- ✅ **CareerPath.vue**: 显示"系统已收录 X 条职业路径"
---
## 二、职业技能相关接口
### 4. `getJobSkillDetail` - 获取职位技能详情
- **接口路径**: `/jobSkillDet/getJobSkillDet`
- **请求方法**: `GET`
- **接口类型**: `zytp`
- **参数**:
- `jobId` (必需): 职位ID
- `jobName` (可选): 职位名称
- **返回数据**:
```json
{
"data": [
{
"skillName": "技能名称",
"skillScore": "技能分数"
}
]
}
```
- **使用场景**:
- ✅ **career-planning.vue**: 点击推荐职位卡片时,获取该职位的技能详情(用于技能详情弹窗 `SkillDetailPopup`
- **调用位置**: `handleJobCardClick` 函数中
---
### 5. `getJobPathSkill` - 获取职业路径技能(已隐藏,暂未使用)
- **接口路径**: `/jobSkillDet/getJobPathSkill`
- **请求方法**: `POST`
- **接口类型**: `zytp`
- **参数**:
- `pathId`: 路径ID
- `currentJobName`: 当前职位名称
- **返回数据**: `List<JobSkillDetVO>` (包含技能分数、类型等详细信息)
- **使用场景**:
- ❌ 暂未在代码中使用
- 💡 **潜在使用场景**: 在 `CareerPath.vue` 中,如果用户点击路径中的某个职位,需要查看该职位在路径中的详细技能信息(包含技能分数、类型等)时,可以使用此接口
- **当前状态**: 接口已注释隐藏,如需使用请取消注释
---
## 三、职业推荐相关接口
### 8. `recommendJob` - 推荐职位
- **接口路径**: `/job/recommendJobByJobName`
- **请求方法**: `GET`
- **接口类型**: `zytp`
- **参数**:
- `jobName` (必需): 当前职位名称(从缓存中获取),通过 URL 参数传递,格式:`/job/recommendJobByJobName?jobName=职位名称`
- **返回数据**:
```json
{
"data": [
{
"jobId": 123,
"jobName": "推荐职位名称",
"skillList": [
{
"skillName": "技能名称"
}
]
}
]
}
```
- **使用场景**:
- ✅ **CareerRecommend.vue**: 根据当前职位名称(从缓存中获取),获取相似推荐职位列表(显示在"相似推荐职位"区域)
---
## 四、接口使用场景
### 📍 页面结构
```
career-planning.vue (主页面)
├── Tab 0: 职业推荐 (CareerRecommend.vue)
├── Tab 1: 职业路径 (CareerPath.vue)
└── Tab 2: 技能发展 (SkillDevelopment.vue)
```
### 📍 职业推荐 Tab (CareerRecommend.vue)
1. **进入页面时**:
- `getJobSkillDetail` - 获取当前职位的技能标签(需要 `jobId`,如果没有 `jobId` 则跳过)
- `recommendJob` - 获取相似推荐职位(需要 `jobId`
2. **点击职位卡片时**:
- `getJobSkillDetail` - 获取该职位的技能详情(显示在技能详情弹窗中)
**注意**: `getJobPathPage` 接口**只在职业路径流程中使用**,不在职业推荐流程中使用。
### 📍 职业路径 Tab (CareerPath.vue)
1. **进入页面时**:
- `getJobPathPage` - 获取所有职业路径列表(填充目标职业下拉选择器)
- `getJobPathNum` - 获取职业路径总数(显示"系统已收录 X 条职业路径"
2. **选择目标职业并点击查询时**:
- `getJobPathPage` - 如果没有 `jobPathId`,通过 `jobName` 查找
- `getJobPathDetail` (实际: `getJobPathById`) - 获取职业路径详情(显示完整路径时间线)
### 📍 技能发展 Tab (SkillDevelopment.vue)
1. **进入页面时**:
- 暂无接口调用
---
## 🔑 关键接口调用流程
### 流程1: 获取当前职位技能
```
CareerRecommend.vue
└── getJobSkillDetail(jobId, jobName) → 获取技能列表
(如果没有 jobId则跳过获取技能
```
### 流程2: 查询职业路径
```
CareerPath.vue
├── getJobPathPage() → 获取路径列表(填充下拉选择器)
├── 用户选择目标职业
└── getJobPathById(jobPathId) → 获取路径详情(显示时间线)
```
### 流程3: 获取推荐职位
```
CareerRecommend.vue
└── recommendJob(jobId) → 获取相似推荐职位列表
```
---
## ⚠️ 注意事项
1. **接口返回码**:
- `code: 0` 和 `code: 200` 都表示成功
- 已在 `request.js` 中处理
2. **参数要求**:
- `getJobSkillDetail` 必须提供 `jobId`,如果没有 `jobId` 则跳过获取技能
- `getJobPathPage` **只在职业路径流程中使用**,不在职业推荐流程中使用
3. **数据格式**:
- `getJobPathPage` 返回的 `list` 在 `response.data.list` 中
- `getJobPathById` 返回的详情在 `response.data` 中(数组格式)
4. **接口使用范围**:
- `getJobPathPage` **只在职业路径流程CareerPath.vue中使用**
- 职业推荐流程CareerRecommend.vue**不使用** `getJobPathPage` 接口
5. **接口前缀**:
- 所有 `zytp` 类型的接口使用: `http://ks.zhaopinzao8dian.com/api/ks_zytp/admin-api/zytp`

View File

@@ -177,7 +177,7 @@ footer-height = 98rpx
/* 页面容器 */ /* 页面容器 */
.container { .container {
position: fixed; position: fixed;
z-index: 1000; z-index: 1;
width: 100vw; width: 100vw;
height: calc(100% - var(--window-bottom)); height: calc(100% - var(--window-bottom));
overflow: hidden; overflow: hidden;

View File

@@ -40,9 +40,20 @@
:current-job-id="currentJobId" :current-job-id="currentJobId"
:current-job-name="currentJobName" :current-job-name="currentJobName"
@job-card-click="handleJobCardClick" @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> </scroll-view>
</view> </view>
@@ -56,8 +67,8 @@
<script setup> <script setup>
import { ref, inject, nextTick, onMounted } from 'vue'; import { ref, inject, nextTick, onMounted } from 'vue';
import { onLoad } from '@dcloudio/uni-app'; import { onLoad } from '@dcloudio/uni-app';
import { appUserInfo } from '@/apiRc/user/user.js';
import { getJobSkillDetail } from '@/apiRc/jobSkill.js'; import { getJobSkillDetail } from '@/apiRc/jobSkill.js';
import { appUserInfo } from '@/apiRc/user/user.js';
import RemindPopup from './components/RemindPopup.vue'; import RemindPopup from './components/RemindPopup.vue';
import PageHeader from './components/PageHeader.vue'; import PageHeader from './components/PageHeader.vue';
import SkillDetailPopup from './components/SkillDetailPopup.vue'; import SkillDetailPopup from './components/SkillDetailPopup.vue';
@@ -66,7 +77,7 @@ import CareerPath from './components/CareerPath.vue';
import SkillDevelopment from './components/SkillDevelopment.vue'; import SkillDevelopment from './components/SkillDevelopment.vue';
import CustomTabBar from '@/components/CustomTabBar/CustomTabBar.vue'; import CustomTabBar from '@/components/CustomTabBar/CustomTabBar.vue';
const { navBack } = inject('globalFunction'); const { navBack, navTo } = inject('globalFunction');
// 弹窗引用 // 弹窗引用
const remindPopup = ref(null); const remindPopup = ref(null);
@@ -85,80 +96,150 @@ const isLoadingJobSkill = ref(false);
const currentJobId = ref(null); const currentJobId = ref(null);
const currentJobName = ref(''); const currentJobName = ref('');
// 技能发展所需的数据
const recommendSkillsData = ref({
currentJobSkills: [],
recommendedJobs: []
});
const pathSkillsData = ref({
pathData: {
start: { title: '', skills: [] },
steps: [],
end: { title: '', skills: [] }
},
targetCareer: ''
});
// 打开弹窗 // 打开弹窗
function openRemindPopup() { function openRemindPopup() {
nextTick(() => { nextTick(() => {
if (remindPopup.value) { if (remindPopup.value) {
remindPopup.value.open(); try {
remindPopup.value.open();
} catch (error) {
// 静默处理错误
}
} else { } else {
setTimeout(() => { setTimeout(() => {
if (remindPopup.value) { if (remindPopup.value) {
remindPopup.value.open(); try {
remindPopup.value.open();
} catch (error) {
// 静默处理错误
}
} else { } else {
setTimeout(() => { setTimeout(() => {
remindPopup.value?.open(); if (remindPopup.value) {
}, 200); try {
remindPopup.value.open();
} catch (error) {
// 静默处理错误
}
}
}, 500);
} }
}, 300); }, 500);
} }
}); });
} }
// 获取提醒信息的接口 // 检查用户是否完善了个人信息(调用接口获取)
let hasCheckedRemindInfo = false;
async function getRemindInfo() { async function getRemindInfo() {
if (hasCheckedRemindInfo) {
return;
}
hasCheckedRemindInfo = true;
try { try {
const response = await appUserInfo(); const response = await appUserInfo();
if (response && response.code === 200) { const userInfo = response?.data || {};
const data = response.data || {};
const reminders = [];
currentJobId.value = data?.jobId ?? data?.currentJobId ?? null; // 优先从接口数据中获取 idCard
currentJobName.value = data?.jobName ?? data?.currentJobName ?? ''; let idCard = userInfo?.resume?.idCard ?? userInfo?.idCard ?? null;
if (Array.isArray(data.remindList) && data.remindList.length > 0) { // 如果接口返回的数据中没有 idCard则从缓存中读取
reminders.push( const cachedUserInfo = uni.getStorageSync('userInfo') || {};
...data.remindList if (!idCard || idCard === null || idCard === '') {
.filter(item => typeof item === 'string' && item.trim().length > 0) idCard = cachedUserInfo?.resume?.idCard ?? cachedUserInfo?.idCard ?? null;
.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;
} }
throw new Error('接口返回异常'); // 优先从接口数据中获取职位信息
} catch (error) { currentJobId.value = userInfo?.jobId ??
console.error('获取提醒信息失败:', error); userInfo?.currentJobId ??
currentJobId.value = null; 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) { 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(); 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; showContent.value = true;
} }
// 切换tab // 切换tab
function switchTab(index) { function switchTab(index) {
activeTab.value = 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() { function handleSearchClick() {
// TODO: 跳转到搜索页面 navTo('/pages/search/search');
console.log('搜索点击');
} }
// 菜单点击 // 菜单点击
function handleMenuClick() { function handleMenuClick() {
console.log('菜单点击'); // TODO: 实现菜单功能
} }
// 更多点击 // 更多点击
function handleMoreClick() { function handleMoreClick() {
console.log('更多点击'); // TODO: 实现更多功能
} }
function normalizeSkillLevel(score) { function normalizeSkillLevel(score) {
@@ -278,7 +416,6 @@ async function handleJobCardClick(job) {
} }
skillDetailPopup.value?.open(); skillDetailPopup.value?.open();
} catch (error) { } catch (error) {
console.error('获取职位技能详情失败:', error);
if (fallbackSkills.length > 0) { if (fallbackSkills.length > 0) {
const fallbackSplit = splitSkillListByScore(fallbackSkills); const fallbackSplit = splitSkillListByScore(fallbackSkills);
selectedJobPossessedSkills.value = fallbackSplit.possessed; 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(() => { onLoad(() => {
getRemindInfo(); getRemindInfo();
}); });
onMounted(() => { onMounted(() => {
if (remindList.value.length > 0 && !showContent.value) { if (remindList.value.length > 0 && !showContent.value) {
openRemindPopup(); setTimeout(() => {
if (remindPopup.value) {
openRemindPopup();
}
}, 300);
} }
}); });
</script> </script>
@@ -349,7 +510,6 @@ onMounted(() => {
position: relative; position: relative;
z-index: 1; z-index: 1;
overflow: hidden; overflow: hidden;
padding-bottom: 88rpx;
} }
@@ -357,6 +517,8 @@ onMounted(() => {
flex: 1; flex: 1;
height: 0; height: 0;
width: 100%; width: 100%;
padding-bottom: calc(88rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
} }
.tabbar-wrapper { .tabbar-wrapper {

View File

@@ -13,7 +13,7 @@
<input <input
class="input-field" class="input-field"
:value="currentPosition" :value="currentPosition"
placeholder="前端开发工程师" placeholder="市场专员"
placeholder-style="color: #999999" placeholder-style="color: #999999"
disabled disabled
/> />
@@ -115,11 +115,21 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import { getJobPathPage, getJobPathDetail, getJobPathNum } from '@/apiRc/jobPath.js'; 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([]); const targetCareerOptions = ref([]);
@@ -170,7 +180,9 @@ async function fetchTargetCareerOptions(keyword = '') {
pageNo: 1, pageNo: 1,
pageSize: 100 pageSize: 100
}); });
const list = response?.data?.list || [];
const list = response?.data?.list || response?.list || [];
targetCareerOptions.value = list.map(item => ({ targetCareerOptions.value = list.map(item => ({
label: item.endJob || item.startJob || '未知职位', label: item.endJob || item.startJob || '未知职位',
value: item.id, value: item.id,
@@ -184,7 +196,6 @@ async function fetchTargetCareerOptions(keyword = '') {
selectedJobPathId.value = null; selectedJobPathId.value = null;
} }
} catch (error) { } catch (error) {
console.error('获取职业路径列表失败:', error);
targetCareerOptions.value = []; targetCareerOptions.value = [];
selectedTargetIndex.value = -1; selectedTargetIndex.value = -1;
selectedJobPathId.value = null; selectedJobPathId.value = null;
@@ -200,17 +211,29 @@ async function fetchPathCount() {
const response = await getJobPathNum(); const response = await getJobPathNum();
totalPathCount.value = response?.data ?? 0; totalPathCount.value = response?.data ?? 0;
} catch (error) { } catch (error) {
console.error('获取职业路径数量失败:', error);
totalPathCount.value = 0; totalPathCount.value = 0;
} }
} }
async function loadPathDetail(jobPathId) { async function loadPathDetail(jobPathId) {
try { if (!jobPathId || jobPathId === null || jobPathId === undefined || jobPathId === '') {
const response = await getJobPathDetail({ uni.showToast({
jobPathId title: '职业路径ID无效',
icon: 'none'
}); });
resetPathData();
return;
}
try {
const requestParams = {
jobPathId: jobPathId
};
const response = await getJobPathDetail(requestParams);
const details = Array.isArray(response?.data) ? response.data : []; const details = Array.isArray(response?.data) ? response.data : [];
if (details.length === 0) { if (details.length === 0) {
resetPathData(); resetPathData();
uni.showToast({ uni.showToast({
@@ -234,12 +257,22 @@ async function loadPathDetail(jobPathId) {
steps, steps,
end end
}; };
// 通知父组件路径数据已更新
emit('path-data-updated', {
pathData: pathData.value,
targetCareer: targetCareerOptions.value[selectedTargetIndex.value]?.label || ''
});
} catch (error) { } catch (error) {
console.error('获取职业路径详情失败:', error);
uni.showToast({ uni.showToast({
title: '获取路径详情失败', title: '获取路径详情失败',
icon: 'none' icon: 'none'
}); });
resetPathData();
emit('path-data-updated', {
pathData: { ...emptyPathData },
targetCareer: ''
});
} }
} }
@@ -298,7 +331,6 @@ async function handleQuery() {
selectedJobPathId.value = jobPathId; selectedJobPathId.value = jobPathId;
await loadPathDetail(jobPathId); await loadPathDetail(jobPathId);
} catch (error) { } catch (error) {
console.error('查询职业路径失败:', error);
uni.showToast({ uni.showToast({
title: '查询失败,请重试', title: '查询失败,请重试',
icon: 'none' icon: 'none'

View File

@@ -27,7 +27,6 @@
<!-- 相似推荐职位 --> <!-- 相似推荐职位 -->
<view class="section-title"> <view class="section-title">
相似推荐职位 相似推荐职位
<text v-if="recommendRecordCount > 0" class="recommend-count">{{ recommendRecordCount }}条记录</text>
</view> </view>
<view v-if="!isLoadingRecommend && recommendedJobs.length === 0" class="empty-text">暂无推荐职位</view> <view v-if="!isLoadingRecommend && recommendedJobs.length === 0" class="empty-text">暂无推荐职位</view>
<view <view
@@ -54,9 +53,9 @@
</template> </template>
<script setup> <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 { getJobSkillDetail } from '@/apiRc/jobSkill.js';
import { recommendJob, countJobRecommendRecords, getJobRecommendRecords } from '@/apiRc/jobRecommend.js';
const props = defineProps({ const props = defineProps({
currentJobId: { 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 skillTags = ref([]);
const recommendedJobs = ref([]); const recommendedJobs = ref([]);
const recommendRecordCount = ref(0);
const recommendRecords = ref([]);
const isLoadingSkillTags = ref(false); const isLoadingSkillTags = ref(false);
const isLoadingRecommend = 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 : []) return (Array.isArray(skillList) ? skillList : [])
.map(item => item?.skillName) .map(item => item?.skillName || '')
.filter(name => !!name); .filter(name => !!name && name.trim().length > 0);
} }
// 获取当前职位的技能标签
async function fetchCurrentJobSkills() { 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; return;
} }
// 优先调用接口获取技能数据
isLoadingSkillTags.value = true; isLoadingSkillTags.value = true;
try { try {
const params = {}; const response = await getJobSkillDetail({
if (props.currentJobId !== null && props.currentJobId !== undefined && props.currentJobId !== '') { jobName: props.currentJobName
params.jobId = props.currentJobId; });
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; // 通知父组件技能数据已更新
} emit('skills-updated', {
const response = await getJobSkillDetail(params); currentJobSkills: skillTags.value,
const list = Array.isArray(response?.data) ? response.data : []; recommendedJobs: recommendedJobs.value
skillTags.value = normalizeSkillListForDisplay(list); });
} catch (error) { } 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 { } finally {
isLoadingSkillTags.value = false; isLoadingSkillTags.value = false;
} }
} }
// 获取推荐职位列表
async function fetchRecommendedJobs() { async function fetchRecommendedJobs() {
const hasJobId = props.currentJobId !== null && props.currentJobId !== undefined && props.currentJobId !== '';
if (!hasJobId) {
recommendedJobs.value = [];
return;
}
isLoadingRecommend.value = true; isLoadingRecommend.value = true;
try { try {
const response = await recommendJob({ const response = await recommendJob({
jobId: props.currentJobId jobName: props.currentJobName
}); });
const list = Array.isArray(response?.data) ? response.data : []; const list = Array.isArray(response?.data) ? response.data : [];
recommendedJobs.value = list.map((item, index) => { 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 { return {
id: item?.jobId ?? index, id: item?.jobId ?? index,
jobId: item?.jobId ?? null, jobId: item?.jobId ?? null,
title: item?.jobName || `推荐职位${index + 1}`, title: item?.jobName || `推荐职位${index + 1}`,
jobName: item?.jobName || '', jobName: item?.jobName || '',
skills: normalizeSkillListForDisplay(rawSkills), skills: skillNames,
rawSkills rawSkills: skillList
}; };
}); });
// 通知父组件推荐职位数据已更新
emit('skills-updated', {
currentJobSkills: skillTags.value,
recommendedJobs: recommendedJobs.value
});
} catch (error) { } catch (error) {
console.error('获取推荐职位失败:', error);
recommendedJobs.value = []; recommendedJobs.value = [];
emit('skills-updated', {
currentJobSkills: skillTags.value,
recommendedJobs: []
});
} finally { } finally {
isLoadingRecommend.value = false; isLoadingRecommend.value = false;
} }
} }
async function fetchRecommendRecordInfo() { // 组件挂载时检查并调用
const hasJobId = props.currentJobId !== null && props.currentJobId !== undefined && props.currentJobId !== ''; onMounted(() => {
const hasJobName = !!props.currentJobName; setTimeout(() => {
if (!hasJobId && !hasJobName) { if (props.currentJobName) {
recommendRecordCount.value = 0; fetchCurrentJobSkills();
recommendRecords.value = []; fetchRecommendedJobs();
return; }
} }, 100);
});
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;
}
}
// 监听 props 变化,自动获取推荐职位和技能标签
watch( watch(
() => [props.currentJobId, props.currentJobName], () => [props.currentJobId, props.currentJobName],
() => { () => {
fetchCurrentJobSkills(); fetchCurrentJobSkills();
fetchRecommendedJobs(); fetchRecommendedJobs();
fetchRecommendRecordInfo();
}, },
{ immediate: true } { immediate: true }
); );
// 事件处理
function handleJobSearch(job) { function handleJobSearch(job) {
console.log('搜索职位:', job.title);
// TODO: 实现职位搜索跳转 // TODO: 实现职位搜索跳转
} }

View File

@@ -16,7 +16,7 @@
</view> </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> <uni-icons class="search-icon" type="search" size="18" color="#999999"></uni-icons>
<text class="search-placeholder">职位名称薪资要求等</text> <text class="search-placeholder">职位名称薪资要求等</text>
</view> </view>
@@ -27,21 +27,24 @@
<view <view
class="tab-item" class="tab-item"
:class="{ 'active': activeTab === 0 }" :class="{ 'active': activeTab === 0 }"
@click="handleTabClick(0)" @click.stop="handleTabClick(0)"
@tap.stop="handleTabClick(0)"
> >
职业推荐 职业推荐
</view> </view>
<view <view
class="tab-item" class="tab-item"
:class="{ 'active': activeTab === 1 }" :class="{ 'active': activeTab === 1 }"
@click="handleTabClick(1)" @click.stop="handleTabClick(1)"
@tap.stop="handleTabClick(1)"
> >
职业路径 职业路径
</view> </view>
<view <view
class="tab-item" class="tab-item"
:class="{ 'active': activeTab === 2 }" :class="{ 'active': activeTab === 2 }"
@click="handleTabClick(2)" @click.stop="handleTabClick(2)"
@tap.stop="handleTabClick(2)"
> >
技能发展 技能发展
</view> </view>
@@ -156,6 +159,11 @@ function handleMoreClick() {
gap: 16rpx; gap: 16rpx;
height: 88rpx; height: 88rpx;
box-shadow: none; box-shadow: none;
position: relative;
z-index: 10;
pointer-events: auto;
-webkit-tap-highlight-color: transparent;
cursor: pointer;
} }
.search-icon { .search-icon {
@@ -175,6 +183,9 @@ function handleMoreClick() {
padding: 6rpx 20rpx; padding: 6rpx 20rpx;
margin-bottom: 10rpx; margin-bottom: 10rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
position: relative;
z-index: 10;
pointer-events: auto;
} }
.tab-nav { .tab-nav {
@@ -191,6 +202,10 @@ function handleMoreClick() {
background-color: transparent; background-color: transparent;
text-align: center; text-align: center;
transition: all 0.3s; transition: all 0.3s;
position: relative;
pointer-events: auto;
-webkit-tap-highlight-color: transparent;
z-index: 10;
} }
.tab-item.active { .tab-item.active {

View File

@@ -43,13 +43,17 @@ const popupRef = ref(null);
// 打开弹窗 // 打开弹窗
function open() { function open() {
if (popupRef.value) { if (popupRef.value) {
popupRef.value.open('center'); try {
popupRef.value.open();
} catch (error) {
// 静默处理错误
}
} }
} }
// 关闭弹窗 // 关闭弹窗
function close() { function close() {
popupRef.value?.close('center'); popupRef.value?.close();
} }
// 取消按钮 // 取消按钮

View File

@@ -46,45 +46,103 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from 'vue'; import { ref, computed, watch } from 'vue';
import SkillWeightPopup from './SkillWeightPopup.vue'; import SkillWeightPopup from './SkillWeightPopup.vue';
import { getSkillNum, getSkillsHeatAnalysisList } from '@/apiRc/jobSkill.js';
// 技能列表(后续从接口获取) const props = defineProps({
const skillList = ref([ // 来自职业推荐 tab 的数据
{ currentJobSkills: {
name: '项目管理(PMP)', type: Array,
weight: '0.98', default: () => []
tags: ['核心技能', '管理能力'],
currentLevel: 3
}, },
{ recommendedJobs: {
name: '团队领导力', type: Array,
weight: '0.90', default: () => []
tags: ['核心技能', '软技能'],
currentLevel: 2
}, },
{ // 来自职业路径 tab 的数据
name: '云安全架构', pathData: {
weight: '0.85', type: Object,
tags: ['技术技能', '网络安全'], default: () => ({
currentLevel: 4 start: { title: '', skills: [] },
steps: [],
end: { title: '', skills: [] }
})
}, },
{ targetCareer: {
name: '财务预算规划', type: String,
weight: '0.60', default: ''
tags: ['软技能', '管理能力'],
currentLevel: 1
} }
]); });
// 技能数量 // 综合技能列表(基于前两个 tab 的数据)
const skillCount = ref(0); const skillList = computed(() => {
const isLoadingSkillCount = ref(false); const skillMap = new Map();
// 技能热度分析列表 // 1. 收集当前职位技能(已有技能,权重较低)
const heatAnalysisList = ref([]); props.currentJobSkills.forEach(skill => {
const isLoadingHeatAnalysis = ref(false); 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); const skillWeightPopup = ref(null);
@@ -94,52 +152,6 @@ const selectedSkillName = ref('');
const selectedSkillWeight = ref(''); const selectedSkillWeight = ref('');
const selectedSkillLevel = ref(0); 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) { function handleSkillItemClick(skill) {
selectedSkillName.value = skill.name || ''; selectedSkillName.value = skill.name || '';
@@ -152,27 +164,6 @@ function handleSkillItemClick(skill) {
function handlePopupClose() { 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> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -4,7 +4,7 @@
* @Date: 2023-07-27 15:55:08 * @Date: 2023-07-27 15:55:08
* @LastEditors: lip * @LastEditors: lip
*/ */
const TokenKey = 'App-Token' const TokenKey = 'token' // 与微信登录时存储的 key 保持一致
export function getToken() { export function getToken() {
return uni.getStorageSync(TokenKey) return uni.getStorageSync(TokenKey)

View File

@@ -5,8 +5,12 @@
* @LastEditors: shirlwang * @LastEditors: shirlwang
*/ */
// 应用全局配置 // 应用全局配置
import config from '@/config.js'
let exports = { let exports = {
// 引用根目录config.js的baseUrl避免重复配置
baseUrl: config.baseUrl,
// baseUrl: 'http://127.0.0.1:8903', // 本地开发 // baseUrl: 'http://127.0.0.1:8903', // 本地开发
@@ -19,8 +23,8 @@ let exports = {
// baseUrl: 'http://10.160.0.5:8903', // 演示环境外网 // baseUrl: 'http://10.160.0.5:8903', // 演示环境外网
// baseUrl: 'http://111.34.80.140:8081/prod-api', // 正式环境(不要轻易连接) // baseUrl: 'http://111.34.80.140:8081/prod-api', // 正式环境(不要轻易连接)
baseUrl: 'http://ks.zhaopinzao8dian.com/api/ks', // baseUrl: 'http://ks.zhaopinzao8dian.com/api/ks', // 已从根目录config.js引用不再重复配置
zytpBaseUrl: 'http://ks.zhaopinzao8dian.com/api/ks', zytpBaseUrl: 'http://ks.zhaopinzao8dian.com/api/ks_zytp/admin-api/zytp',

View File

@@ -18,10 +18,11 @@ const request = config => {
// 是否需要设置 token // 是否需要设置 token
const isToken = (config.headers || {}).isToken === false const isToken = (config.headers || {}).isToken === false
config.header = config.header || {} config.header = config.header || {}
if (getToken() && !isToken) { // 从存储中获取微信登录的 token
config.header['Authorization'] = 'Bearer ' + getToken() const token = getToken()
if (token && !isToken) {
config.header['Authorization'] = 'Bearer ' + token
} }
config.header['Authorization'] = 'Bearer ' + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJzeXNfdXNlcjoxIiwicm5TdHIiOiJVMDRocERSZjdZMXJUbUxXb05uOUpzYUdDZzBNazJJQSIsInVzZXJJZCI6MX0.LZ29vvA4tK3b9Hki4nU9Jb1himXZM2AEOue3CMRY95w'
// get请求映射params参数 // get请求映射params参数
const baseType = config.baseUrlType const baseType = config.baseUrlType
const requestBaseUrl = baseType === 'zytp' && zytpBaseUrl ? zytpBaseUrl : baseUrl const requestBaseUrl = baseType === 'zytp' && zytpBaseUrl ? zytpBaseUrl : baseUrl
@@ -34,6 +35,26 @@ const request = config => {
requestUrl += (requestUrl.includes('?') ? '&' : '?') + url requestUrl += (requestUrl.includes('?') ? '&' : '?') + url
} }
} }
// 如果是 getJobPathById 接口,打印完整 URL
if (config.url && config.url.includes('getJobPathById')) {
console.log('[请求URL] getJobPathById 完整请求URL:', requestUrl);
console.log('[请求URL] baseUrl:', requestBaseUrl);
console.log('[请求URL] 接口路径:', config.url);
console.log('[请求URL] 请求参数:', config.params);
}
// 如果是 recommendJob 接口,打印详细信息
if (config.url && config.url.includes('recommendJob')) {
console.log('[请求URL] recommendJob 完整请求URL:', requestUrl);
console.log('[请求URL] baseUrl:', requestBaseUrl);
console.log('[请求URL] 接口路径:', config.url);
console.log('[请求URL] 请求方法:', config.method);
console.log('[请求URL] 请求参数 (params):', config.params);
console.log('[请求URL] 请求数据 (data):', config.data);
console.log('[请求URL] Content-Type:', config.header?.['content-type']);
}
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
uni.request({ uni.request({
method: config.method || 'get', method: config.method || 'get',
@@ -52,11 +73,12 @@ const request = config => {
reject('网络出小差,请稍后再试') reject('网络出小差,请稍后再试')
return return
} }
const code = res.code || 200 // 处理 code0 和 200 都表示成功
const code = res.code !== undefined && res.code !== null ? res.code : 200
console.log(code, 'const code = res.code || 200') console.log(code, 'const code = res.code || 200')
const msg = errorCode[code] || res.msg || errorCode['default'] const msg = errorCode[code] || res.msg || errorCode['default']
const isShowModel = getApp().globalData.isShowModel const isShowModel = getApp().globalData.isShowModel
if (code === 200) { if (code === 200 || code === 0) {
resolve(res) resolve(res)
}else if (code === 401) { }else if (code === 401) {
if(isShowModel === false) { if(isShowModel === false) {
@@ -89,12 +111,15 @@ const request = config => {
else if (code === 500) { else if (code === 500) {
toast(msg) toast(msg)
reject('500') reject('500')
} else if (code !== 200 && code !== 9999) { } else if (code !== 200 && code !== 0 && code !== 9999) {
// 9999是正常的业务状态码不应该被当作错误处理 // 9999是正常的业务状态码不应该被当作错误处理
// 0 和 200 都表示成功
toast(msg) toast(msg)
reject(code) reject(code)
} }
resolve(res.data) // 如果 code 是 0 或 200返回完整响应对象而不是 res.data
// 因为有些接口的 data 在 res.data 中,有些在 res 中
resolve(res)
}) })
.catch(error => { .catch(error => {
console.log(error, 'error') console.log(error, 'error')