22 Commits

Author SHA1 Message Date
冯辉
2df9502640 用户信息完善接口加密 2026-05-02 21:39:41 +08:00
冯辉
023644da0e 11 2026-05-01 20:03:11 +08:00
FengHui
dcb280042d 1 2026-05-01 12:23:05 +08:00
冯辉
7ad59aeeab 111 2026-05-01 04:02:50 +08:00
冯辉
57b18c0a65 取消字典数据加密 2026-05-01 02:48:55 +08:00
冯辉
6e63f81ede Merge branch 'main' of http://124.243.245.42:3000/sdz/ks-app-employment-service 2026-04-30 17:46:21 +08:00
冯辉
aa66011a16 111 2026-04-30 17:46:19 +08:00
9393e9a624 feat(index): add custom navigation and new job list components
- Updated the index page to include a custom navigation style for H5.
- Introduced a new component `IndexYtj` for enhanced job listing features.
- Added a new job list page `jobListYtj` with improved layout and functionality.
- Integrated a WeChat authorization login component for better user experience.
- Included several new static assets for UI enhancements.
2026-04-30 17:44:54 +08:00
冯辉
c417b1b86b 增加加密接口 2026-04-30 15:12:33 +08:00
冯辉
7aa8761ea8 聊天数据加密 2026-04-30 14:55:25 +08:00
冯辉
af800b4f63 Merge branch 'main' of http://124.243.245.42:3000/sdz/ks-app-employment-service 2026-04-30 13:28:51 +08:00
冯辉
e40f0ebab8 接口加密 2026-04-30 13:28:49 +08:00
hanguangpu01
738e73df70 fix(login): 添加登录验证检查到页面跳转功能
- 在招聘会模块跳转前添加登录验证
- 在通知页面跳转前添加登录验证
- 在机构相关页面跳转前添加登录验证
- 确保未登录用户无法访问受保护的页面
- 统一页面跳转逻辑的登录验证处理
2026-04-30 10:36:56 +08:00
f806ea49cd fix(navigation): include encryptJobId in job detail navigation URL 2026-04-29 10:31:39 +08:00
冯辉
5007c3ca4e 我的页面无法滚动问题修复 2026-04-27 15:20:52 +08:00
ltt
264d8c884c Merge branch 'main' of http://124.243.245.42:3000/sdz/ks-app-employment-service 2026-04-24 15:47:02 +08:00
ltt
1d10f5c75a 日志记录功能 2026-04-24 15:46:57 +08:00
hanguangpu01
4f590d12a7 feat(index): 添加招聘会服务权限控制
- 在招聘会服务项上添加 isFourLevelLinkagePurview 权限判断
- 确保只有具备四级联动权限的用户才能看到招聘会功能入口
- 保持原有的点击事件处理逻辑不变
2026-04-24 14:39:09 +08:00
hanguangpu01
e7222e93d8 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	packageB/login2.vue
2026-04-24 14:35:44 +08:00
hanguangpu01
4e57363b4a feat(login): 重构登录页面并优化认证流程
- 重新设计登录界面UI,增加装饰元素和动画效果
- 更新登录表单布局,添加图标和标签
- 修改存储的token名称为inspur-admin-Token和fourLevelLinkage-token
- 在帮助筛选页面添加Bearer前缀到授权头
- 从帮助筛选页面传递goal_person_id参数到跟进页面
- 禁用智能推荐按钮并注释相关代码
- 移除首页招聘会服务项的权限检查条件
- 在跟进页面保存成功后刷新列表数据
- 从路由参数获取goal_person_id并设置到人员信息中
2026-04-24 14:35:05 +08:00
85e5061a02 帮扶任务屏蔽 2026-04-24 11:38:48 +08:00
FengHui
c60119c369 职位相关页面encryptJobId字段添加 2026-04-22 21:59:21 +08:00
42 changed files with 3693 additions and 227 deletions

View File

@@ -1,4 +1,6 @@
import useUserStore from "../stores/useUserStore";
import { sm4Encrypt, sm4Decrypt } from '@/utils/crypto';
import {
request,
createRequest,
@@ -384,6 +386,14 @@ const formatTotal = (total) => {
return `${roundedTotal}+`;
};
export function sm2_Decrypt(word, key) {
return SM.decrypt(word, key);
}
export function sm2_Encrypt(word, key) {
return SM.encrypt(word, key);
}
export function formatDate(isoString) {
const date = new Date(isoString);
const year = date.getFullYear();
@@ -1041,4 +1051,8 @@ export default {
insertSortData,
isInWechatMiniProgramWebview,
isEmptyObject,
sm4Decrypt,
sm4Encrypt,
sm2_Decrypt,
sm2_Encrypt,
}

View File

@@ -77,7 +77,7 @@ function nextDetail(job) {
const recordData = recommedIndexDb.JobParameter(job);
recommedIndexDb.addRecord(recordData);
}
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}`);
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}&encryptJobId=${encodeURIComponent(job.encryptJobId)}`);
}
</script>

View File

@@ -103,7 +103,7 @@ function nextDetail(job) {
const recordData = recommedIndexDb.JobParameter(job);
recommedIndexDb.addRecord(recordData);
}
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}`);
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}&encryptJobId=${encodeURIComponent(job.encryptJobId)}`);
}
function toggleSelect(jobId) {
@@ -122,7 +122,7 @@ function handleCardClick(job, e) {
const recordData = recommedIndexDb.JobParameter(job);
recommedIndexDb.addRecord(recordData);
}
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}`);
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}&encryptJobId=${encodeURIComponent(job.encryptJobId)}`);
}
// 新增:提供选中状态和切换方法给父组件

View File

@@ -88,5 +88,12 @@ export default {
title: '找工作,用 AI 更高效|青岛市智能求职平台',
desc: '融合海量岗位、智能简历匹配、竞争力分析,助你精准锁定理想职位!',
imgUrl: 'https://qd.zhaopinzao8dian.com/file/csn/qd_shareLogo.jpg',
}
},
// SM4 加密配置
sm4Config: {
key: '86C63180C1306ABC4D8F989E0A0BC9F3',
mode: 'ECB',
iv: 'UISwD9fW6cFh9SNS',
cipherType: 'base64',
},
}

View File

@@ -580,6 +580,15 @@ function extractSpeechText(markdown) {
console.log('📝 Input markdown length:', markdown ? markdown.length : 0);
console.log('📝 Input markdown preview:', markdown ? markdown.substring(0, 200) + '...' : 'No markdown');
// 过滤AI推理内容如DeepSeek的<think>标签)
// 这些是AI的内部推理过程不应朗读给用户
let cleanedMarkdown = markdown.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
console.log('🧹 After removing think tags, length:', cleanedMarkdown.length);
if (cleanedMarkdown.length === 0 && markdown.length > 0) {
console.warn('⚠️ 所有内容都是think标签将使用原始文本');
cleanedMarkdown = markdown;
}
const jobRegex = /``` job-json\s*({[\s\S]*?})\s*```/g;
const jobs = [];
let match;
@@ -587,7 +596,7 @@ function extractSpeechText(markdown) {
let firstJobStartIndex = -1;
// 提取岗位 json 数据及前后位置
while ((match = jobRegex.exec(markdown)) !== null) {
while ((match = jobRegex.exec(cleanedMarkdown)) !== null) {
const jobStr = match[1];
try {
const job = JSON.parse(jobStr);
@@ -608,12 +617,12 @@ function extractSpeechText(markdown) {
// 提取引导语(第一个 job-json 之前的文字)
const guideText = firstJobStartIndex > 0 ?
markdown.slice(0, firstJobStartIndex).trim() :
cleanedMarkdown.slice(0, firstJobStartIndex).trim() :
'';
// 提取结束语(最后一个 job-json 之后的文字)
const endingText = lastJobEndIndex < markdown.length ?
markdown.slice(lastJobEndIndex).trim() :
const endingText = lastJobEndIndex < cleanedMarkdown.length ?
cleanedMarkdown.slice(lastJobEndIndex).trim() :
'';
console.log('📝 Guide text:', guideText);

View File

@@ -41,8 +41,8 @@ onReachBottom(() => {
getJobList();
});
function navToPost(jobId) {
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(jobId)}`);
function navToPost(job) {
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}&encryptJobId=${encodeURIComponent(job.encryptJobId)}`);
}
function getJobList(type = 'add') {

View File

@@ -83,8 +83,8 @@ function toSelectDate() {
});
}
function navToPost(jobId) {
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(jobId)}`);
function navToPost(job) {
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}&encryptJobId=${encodeURIComponent(job.encryptJobId)}`);
}
function searchCollection(e) {

View File

@@ -47,8 +47,8 @@ onReachBottom(() => {
getJobList();
});
function navToPost(jobId) {
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(jobId)}`);
function navToPost(job) {
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}&encryptJobId=${encodeURIComponent(job.encryptJobId)}`);
}
function getJobList(type = 'add') {

View File

@@ -673,14 +673,15 @@ const scrollToBottom = throttle(function () {
}, 500);
function getGuess() {
// $api.chatRequest('/guest', { sessionId: chatSessionID.value }, 'POST').then((res) => {
$api.chatRequest('/guest', undefined, 'POST').then((res) => {
$api.chatRequest('/guest', { sessionId: chatSessionID.value }, 'POST').then((res) => {
console.log('getGuess ---- res:', res);
guessList.value = res.data;
showGuess.value = true;
nextTick(() => {
scrollToBottom();
});
}).catch((err) => {
console.warn('getGuess 请求失败:', err);
});
}

View File

@@ -271,6 +271,7 @@ const jobInfo = ref({});
const state = reactive({});
const mapCovers = ref([]);
const jobIdRef = ref();
const jobId = ref();
// 竞争力分析数据,初始化为包含默认值的完整结构,确保雷达图能正常渲染
const raderData = ref({
matchScore: 0,
@@ -313,6 +314,9 @@ onShow(() => {
});
function initLoad(option) {
const encryptJobId = decodeURIComponent(option.encryptJobId);
if (option.jobId) {
jobId.value = decodeURIComponent(option.jobId);
}
if (encryptJobId !== jobIdRef.value) {
jobIdRef.value = encryptJobId;
getDetail(encryptJobId);
@@ -458,7 +462,8 @@ function confirmAction() {
const encryptJobId = jobIdRef.value;
if (jobInfo.value.isApply === 1) {
// 取消投递
$api.createRequest(`/app/job/applyJobCencal`, { encryptJobId }, 'DELETE').then((resData) => {
const cancelJobId = jobId.value || jobInfo.value.jobId;
$api.createRequest(`/app/job/applyJobCencal`, { jobId: cancelJobId }, 'DELETE').then((resData) => {
$api.msg('取消投递成功');
getDetail(encryptJobId); // 刷新职位信息
showConfirmDialog.value = false;
@@ -486,8 +491,8 @@ function confirmApply() {
// 取消投递
function cancelApply() {
const encryptJobId = jobIdRef.value;
$api.createRequest(`/app/job/applyJobCencal`, { encryptJobId }, 'DELETE').then((resData) => {
const cancelJobId = jobId.value || jobInfo.value.jobId;
$api.createRequest(`/app/job/applyJobCencal`, { jobId: cancelJobId }, 'DELETE').then((resData) => {
$api.msg('取消投递成功');
showConfirmDialog.value = false;
});

View File

@@ -80,20 +80,20 @@
name: ""
}
}
$api.myRequest('/auth/login2/ks',form,'post',10100).then((res) => {
if (res.code=='200') {
uni.setStorageSync('Padmin-Token', res.data.access_token)
uni.navigateBack({
delta:2
})
}
}).catch(() => {
uni.hideLoading()
uni.showToast({
icon: 'none',
title: '登录失败,请重试'
})
})
// $api.myRequest('/auth/login2/ks',form,'post',10100).then((res) => {
// if (res.code=='200') {
// uni.setStorageSync('Padmin-Token', res.data.access_token)
// uni.navigateBack({
// delta:2
// })
// }
// }).catch(() => {
// uni.hideLoading()
// uni.showToast({
// icon: 'none',
// title: '登录失败,请重试'
// })
// })
})
function register() {

View File

@@ -1,18 +1,64 @@
<template>
<AppLayout title="" :use-scroll-view="false">
<view class="wrap">
<view class="login_index">
<input class="input" placeholder="请输入账号" placeholder-class="inputplace" v-model="form.username" />
<view class="login_yzm">
<input class="input" type="password" placeholder="请输入密码" placeholder-class="inputplace"
v-model="form.password" />
<view class="login-container">
<!-- 顶部装饰 -->
<view class="header-decoration">
<view class="decoration-circle circle-1"></view>
<view class="decoration-circle circle-2"></view>
</view>
<!-- Logo区域 -->
<view class="logo-section">
<view class="logo-wrapper">
<text class="logo-icon"></text>
</view>
<view class="login_yzm">
<input class="input" placeholder="请输入验证码" placeholder-class="inputplace" v-model="form.code" />
<image class="yzm" :src="codeUrl" @click="getCodeImg"></image>
<text class="logo-title">欢迎回来</text>
<text class="logo-subtitle">请登录您的账号</text>
</view>
<!-- 登录表单 -->
<view class="form-section">
<view class="form-item">
<view class="form-label">账号</view>
<view class="input-wrapper">
<text class="input-icon">👤</text>
<input class="form-input" placeholder="请输入账号" placeholder-class="inputplace" v-model="form.username" />
</view>
</view>
<button class="com-btn" @click="register"> </button>
<view class="form-item">
<view class="form-label">密码</view>
<view class="input-wrapper">
<text class="input-icon">🔒</text>
<input class="form-input" type="password" placeholder="请输入密码" placeholder-class="inputplace" v-model="form.password" />
</view>
</view>
<view class="form-item">
<view class="form-label">验证码</view>
<view class="input-wrapper verify-wrapper">
<text class="input-icon"></text>
<input class="form-input verify-input" placeholder="请输入验证码" placeholder-class="inputplace" v-model="form.code" />
<image class="verify-code" :src="codeUrl" @click="getCodeImg"></image>
</view>
</view>
</view>
<!-- 登录按钮 -->
<view class="button-section">
<button class="login-btn" @click="register">
<text class="btn-text"> </text>
<text class="btn-arrow"></text>
</button>
</view>
<!-- 底部装饰 -->
<view class="footer-decoration">
<view class="decoration-dots">
<view class="dot"></view>
<view class="dot dot-active"></view>
<view class="dot"></view>
</view>
</view>
</view>
</AppLayout>
@@ -49,15 +95,12 @@
code: '',
uuid: ''
})
const jumpUrl=ref('')
onLoad((option) => {
console.log("111",option)
console.log("111")
if(option.flag){
flag.value=option.flag
}
if(option.jump){
jumpUrl.value=option.jump
}
})
onMounted(() => {
@@ -142,13 +185,11 @@
})
}else if(flag.value=='nw'){
$api.myRequest('/auth/login',form,'post',9100).then((res) => {
uni.setStorageSync('Padmin-Token', res.data.access_token)
// 临时修改,现在有多个跳转页面
// uni.reLaunch({
// url: '/packageB/priority/helpFilter'
// })
uni.setStorageSync('inspur-admin-Token', res.data.access_token)
uni.setStorageSync('fourLevelLinkage-token', res.data.access_token)
uni.reLaunch({
url:jumpUrl.value
url: '/packageB/priority/helpFilter'
})
codeUrl.value = 'data:image/gif;base64,' + res.img
}).catch(() => {
@@ -179,130 +220,220 @@
</script>
<style scoped lang="stylus">
.wrap {
background-color: #ffffff;
height: 100vh;
position: relative;
/* 主题色变量 */
$primary-color = #46ca98
$primary-light = #e8f8f0
$primary-dark = #3ab882
$text-primary = #1a1a1a
$text-secondary = #666666
$text-placeholder = #b5b5b5
$bg-light = #f8faf9
$border-color = #e8e8e8
.lg-head {
height: 480rpx;
background: #46ca98;
position: relative;
.login-container
background: linear-gradient(180deg, #f8faf9 0%, #ffffff 100%)
min-height: 100vh
display: flex
flex-direction: column
align-items: center
position: relative
overflow: hidden
.view_logo {
text-align: center;
/* 顶部装饰 */
.header-decoration
position: absolute
top: 0
left: 0
right: 0
height: 400rpx
pointer-events: none
.login_logo {
width: 300rpx;
height: 300rpx;
margin-top: 100rpx;
}
}
.decoration-circle
position: absolute
border-radius: 50%
background: linear-gradient(135deg, rgba(70, 202, 152, 0.1) 0%, rgba(70, 202, 152, 0.05) 100%)
.bg-cover {
position: absolute;
bottom: -4rpx;
left: 0;
right: 0;
height: 30rpx;
background-size: 100% 100%;
z-index: 1;
}
}
}
.circle-1
width: 300rpx
height: 300rpx
top: -100rpx
right: -80rpx
.login_index {
font-size: 36rpx;
font-weight: 500;
width: 596rpx;
margin: 0 auto;
.circle-2
width: 200rpx
height: 200rpx
top: 60rpx
left: -60rpx
background: linear-gradient(135deg, rgba(70, 202, 152, 0.08) 0%, rgba(70, 202, 152, 0.02) 100%)
::v-deep .is-input-border {
border: 0;
border-bottom: 1px solid #dcdfe6 !important;
border-radius: 0;
}
/* Logo区域 */
.logo-section
margin-top: 160rpx
display: flex
flex-direction: column
align-items: center
animation: fadeInUp 0.6s ease-out
::v-deep .uni-input-input {
font-size: 32rpx;
padding-left: 10rpx;
}
.logo-wrapper
width: 140rpx
height: 140rpx
background: linear-gradient(145deg, $primary-color 0%, $primary-dark 100%)
border-radius: 36rpx
display: flex
align-items: center
justify-content: center
box-shadow: 0 16rpx 40rpx rgba(70, 202, 152, 0.3)
margin-bottom: 40rpx
::v-deep .uniui-contact-filled:before {
color: #46ca98;
font-size: 50rpx;
}
.logo-icon
font-size: 60rpx
color: #ffffff
::v-deep .uniui-locked-filled:before {
color: #46ca98;
font-size: 50rpx;
}
.logo-title
font-size: 48rpx
font-weight: 600
color: $text-primary
letter-spacing: 2rpx
margin-bottom: 12rpx
.login_yzm {
margin-top: 40rpx;
display: flex;
align-items: center;
.logo-subtitle
font-size: 28rpx
color: $text-secondary
letter-spacing: 1rpx
.yzm {
width: 200rpx;
height: 80rpx;
}
}
/* 表单区域 */
.form-section
width: 600rpx
margin-top: 80rpx
animation: fadeInUp 0.6s ease-out 0.15s backwards
.com-btn {
height: 100rpx;
background: #46ca98;
border-radius: 50rpx;
color: #fff;
margin-top: 100rpx;
}
.form-item
margin-bottom: 40rpx
.login_wt {
margin: 0 auto;
text-align: right;
font-size: 24rpx;
color: rgba(134, 134, 136, 1);
}
}
.form-label
font-size: 26rpx
color: $text-secondary
margin-bottom: 16rpx
padding-left: 8rpx
letter-spacing: 1rpx
.lg-bottom {
position: absolute;
bottom: -3px;
left: 0;
width: 100%;
.input-wrapper
display: flex
align-items: center
background: #ffffff
border-radius: 24rpx
padding: 0 32rpx
height: 100rpx
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.04)
border: 2rpx solid transparent
transition: all 0.3s ease
.bottom-svg {
position: absolute;
bottom: -3px;
left: 0;
width: 100%;
}
}
&:focus-within
border-color: $primary-color
box-shadow: 0 4rpx 24rpx rgba(70, 202, 152, 0.15)
.login_tongyi {
.input-icon
font-size: 36rpx
margin-right: 20rpx
opacity: 0.7
font-size: 26rpx;
color: rgba(196, 196, 196, 1);
width: 620rpx;
margin: 32rpx auto;
text-align: center;
.form-input
flex: 1
height: 100%
font-size: 30rpx
color: $text-primary
text {
color: rgba(86, 176, 236, 1);
}
}
.verify-wrapper
padding-right: 16rpx
.input {
padding: 0 30rpx 0 80rpx;
height: 80rpx;
background: #FFFFFF;
border-radius: 75rpx 75rpx 75rpx 75rpx;
font-size: 28rpx;
}
.verify-input
flex: 1
.inputplace {
font-weight: 400;
font-size: 28rpx;
color: #B5B5B5;
}
.verify-code
width: 180rpx
height: 72rpx
border-radius: 16rpx
margin-left: 16rpx
cursor: pointer
transition: transform 0.2s ease
&:active
transform: scale(0.95)
/* 输入框占位符 */
.inputplace
font-weight: 400
font-size: 28rpx
color: $text-placeholder
/* 按钮区域 */
.button-section
width: 600rpx
margin-top: 60rpx
animation: fadeInUp 0.6s ease-out 0.3s backwards
.login-btn
width: 100%
height: 108rpx
background: linear-gradient(135deg, $primary-color 0%, $primary-dark 100%)
border-radius: 54rpx
display: flex
align-items: center
justify-content: center
box-shadow: 0 12rpx 32rpx rgba(70, 202, 152, 0.35)
transition: all 0.3s ease
border: none
&:active
transform: translateY(2rpx)
box-shadow: 0 8rpx 24rpx rgba(70, 202, 152, 0.3)
.btn-text
font-size: 34rpx
font-weight: 500
color: #ffffff
letter-spacing: 8rpx
.btn-arrow
font-size: 32rpx
color: #ffffff
margin-left: 16rpx
transition: transform 0.3s ease
.login-btn:active .btn-arrow
transform: translateX(8rpx)
/* 底部装饰 */
.footer-decoration
position: absolute
bottom: 60rpx
display: flex
flex-direction: column
align-items: center
animation: fadeInUp 0.6s ease-out 0.45s backwards
.decoration-dots
display: flex
align-items: center
gap: 16rpx
.dot
width: 12rpx
height: 12rpx
border-radius: 50%
background: rgba(70, 202, 152, 0.3)
.dot-active
width: 36rpx
border-radius: 6rpx
background: $primary-color
/* 动画 */
@keyframes fadeInUp
from
opacity: 0
transform: translateY(30rpx)
to
opacity: 1
transform: translateY(0)
</style>

View File

@@ -158,7 +158,7 @@
<view class="form-btns">
<button class="mini-btn form-box-btn detail-btn" size="mini" v-if="false">详情</button>
<button class="mini-btn form-box-btn follow-btn" size="mini" @click="goFollow(item)">跟进</button>
<button class="mini-btn form-box-btn recommend-btn" size="mini" @click="goRecommend(item)">智能推荐</button>
<!-- <button class="mini-btn form-box-btn recommend-btn" size="mini" @click="goRecommend(item)">智能推荐</button> -->
</view>
</view>
</view>
@@ -267,7 +267,7 @@ function getTaskTypeLabelByValue(value) {
// 加载某一级的数据parentId 为空表示根)
async function loadLevelData(parentId,node) {
let header = {
'Authorization': uni.getStorageSync('fourLevelLinkage-token'),
'Authorization': 'Bearer ' + uni.getStorageSync('fourLevelLinkage-token'),
'Content-Type': "application/x-www-form-urlencoded"
};
let params = { parentId };
@@ -384,7 +384,7 @@ function getDataList(type = 'add') {
}
}
function goFollow(item) {
navTo(`/packageB/priority/helpFollow?task_id=${item.task_id}&person_id=${item.person_id}&&name=${item.name}&&taskType=${getTaskTypeLabelByValue(item.task_type)}`);
navTo(`/packageB/priority/helpFollow?task_id=${item.task_id}&person_id=${item.person_id}&goal_person_id=${item.goal_person_id}&name=${item.name}&&taskType=${getTaskTypeLabelByValue(item.task_type)}`);
}
//智能推荐
const goRecommend = (item) => {

View File

@@ -162,7 +162,7 @@ const onDateChange = ( e) => {
}
function getFollowList(){
let header={
'Authorization':uni.getStorageSync('fourLevelLinkage-token'),
'Authorization':'Bearer ' + uni.getStorageSync('fourLevelLinkage-token'),
'Content-Type': "application/x-www-form-urlencoded"
}
let params={
@@ -211,13 +211,14 @@ const handleSubmit = () => {
formRef.value?.validate()
.then(() => {
let header={
'Authorization':uni.getStorageSync('fourLevelLinkage-token')
'Authorization':'Bearer ' + uni.getStorageSync('fourLevelLinkage-token')
}
formData.goalPersonId=personInfo.value.goalPersonId
$api.myRequest('/dispatch/assist/records/addRecords', formData,'post',9100,header).then((resData) => {
console.log("resData",resData)
if(resData && resData.code == 200){
handleReset()
getFollowList()
uni.showToast({
title: '保存成功',
icon: 'success',
@@ -247,6 +248,8 @@ const handleReset = () => {
formData.nextContactDate = '';
}
onLoad((options) => {
console.log(options)
personInfo.value.goalPersonId=options.goal_person_id
personInfo.value.person_id=options.person_id
personInfo.value.name=options.name
personInfo.value.taskType=options.taskType

View File

@@ -10,6 +10,12 @@ api.queryAIUrl = (idCard,name) => request.globalRequest(`/Home/QueryAIUrl?userId
// 获取个人档案
api.queryStudentProfile = () => request.globalRequest(`/StudentResource/QueryStudentProfile`,'GET', {})
// 保存操作日志
api.saveUserOperationLog = (data) => request.globalRequest(`/UserOperationLog/SaveUserOperationLog`,'POST', data)
// 获取操作日志
api.getUserOperationLogList = (data) => request.globalRequest(`/UserOperationLog/GetUserOperationLogList`,'POST', data)
export default api

View File

@@ -53,6 +53,7 @@
<script>
import api from "@/packageCa/apiCa/testManage.js"
import apiuser from "@/packageCa/apiCa/user.js"
export default {
data() {
return {
@@ -179,6 +180,27 @@
}, 300)
}
},
// 添加日志
postLog(operationType, remarks, beforeData = "", afterData = ""){
try {
const data = {
OperationType: operationType,
Remarks: remarks,
BeforeOperationJson: beforeData,
AfterOperationJson: afterData
};
console.log(data);
// return;
// 异步记录日志,不阻塞主流程
apiuser.saveUserOperationLog(data).then((res) => {
console.log('[Operation Log] 记录成功', res);
}).catch((err) => {
console.error('[Operation Log] 记录失败', err);
});
} catch (e) {
console.error('[Operation Log] 记录异常', e);
}
},
// 提交题目
submitTitle() {
let testStr = "";
@@ -250,7 +272,11 @@
})
}
})
}
this.postLog(201,`【新增】保存${this.testTitle}`,"",JSON.stringify({
TestType: this.testType,
TestStr: testStr
}))
}
}
}
</script>

View File

@@ -61,6 +61,7 @@
</template>
<script>
import api from "@/packageCa/apiCa/testManage.js"
import apiuser from "@/packageCa/apiCa/user.js"
export default {
data() {
return {
@@ -249,6 +250,27 @@
},400)
},
// 添加日志
postLog(operationType, remarks, beforeData = "", afterData = ""){
try {
const data = {
OperationType: operationType,
Remarks: remarks,
BeforeOperationJson: beforeData,
AfterOperationJson: afterData
};
console.log(data);
// return;
// 异步记录日志,不阻塞主流程
apiuser.saveUserOperationLog(data).then((res) => {
console.log('[Operation Log] 记录成功', res);
}).catch((err) => {
console.error('[Operation Log] 记录失败', err);
});
} catch (e) {
console.error('[Operation Log] 记录异常', e);
}
},
// 提交题目
submitTitle() {
let testStr = "";
@@ -282,6 +304,10 @@
})
}
})
this.postLog(201,`【新增】保存职业兴趣测评`,"",JSON.stringify({
TestType: 11,
TestStr: testStr
}))
}
}
}

View File

@@ -45,6 +45,7 @@
<script>
import api from "@/packageCa/apiCa/testManage.js"
import apiuser from "@/packageCa/apiCa/user.js"
export default {
data() {
return {
@@ -142,6 +143,27 @@
},400)
}
},
// 添加日志
postLog(operationType, remarks, beforeData = "", afterData = ""){
try {
const data = {
OperationType: operationType,
Remarks: remarks,
BeforeOperationJson: beforeData,
AfterOperationJson: afterData
};
console.log(data);
// return;
// 异步记录日志,不阻塞主流程
apiuser.saveUserOperationLog(data).then((res) => {
console.log('[Operation Log] 记录成功', res);
}).catch((err) => {
console.error('[Operation Log] 记录失败', err);
});
} catch (e) {
console.error('[Operation Log] 记录异常', e);
}
},
// 提交题目
submitTitle() {
let testStr = "";
@@ -195,6 +217,10 @@
})
}
})
this.postLog(201,`【新增】保存人格测评`,"",JSON.stringify({
TestType: 15,
TestStr: testStr
}))
}
}
}

View File

@@ -44,6 +44,7 @@
<script>
import api from "@/packageCa/apiCa/testManage.js"
import apiuser from "@/packageCa/apiCa/user.js"
export default {
data() {
return {
@@ -145,6 +146,27 @@
},300)
}
},
// 添加日志
postLog(operationType, remarks, beforeData = "", afterData = ""){
try {
const data = {
OperationType: operationType,
Remarks: remarks,
BeforeOperationJson: beforeData,
AfterOperationJson: afterData
};
console.log(data);
// return;
// 异步记录日志,不阻塞主流程
apiuser.saveUserOperationLog(data).then((res) => {
console.log('[Operation Log] 记录成功', res);
}).catch((err) => {
console.error('[Operation Log] 记录失败', err);
});
} catch (e) {
console.error('[Operation Log] 记录异常', e);
}
},
// 提交题目
submitTitle() {
let testStr = "";
@@ -197,6 +219,10 @@
})
}
})
this.postLog(201,`【新增】保存工作测评`,"",JSON.stringify({
TestType: 17,
TestStr: testStr
}))
}
}
}

View File

@@ -46,6 +46,7 @@
<script>
import api from "@/packageCa/apiCa/user.js"
import apiuser from "@/packageCa/apiCa/user.js"
export default {
data() {
return {
@@ -103,7 +104,7 @@
url: "/packageCa/userCenter/smartTarget"
})
break;
}
}
}
},
@@ -116,10 +117,32 @@
user: res.Data.userInfo
};
uni.setStorageSync('CAuserInfo',params);
this.postLog(101,`【用户登入】【小程序】${res.Data.userInfo}登录成功`,"",JSON.stringify(params))
}else {
return null
}
},
// 添加日志
postLog(operationType, remarks, beforeData = "", afterData = ""){
try {
const data = {
OperationType: operationType,
Remarks: remarks,
BeforeOperationJson: beforeData,
AfterOperationJson: afterData
};
console.log(data);
// return;
// 异步记录日志,不阻塞主流程
apiuser.saveUserOperationLog(data).then((res) => {
console.log('[Operation Log] 记录成功', res);
}).catch((err) => {
console.error('[Operation Log] 记录失败', err);
});
} catch (e) {
console.error('[Operation Log] 记录异常', e);
}
},
}
}
</script>
@@ -482,6 +505,7 @@
align-items: center;
justify-content: center;
margin-right: 55rpx;
margin-bottom: 30rpx;
&:nth-child(4){
margin-right: 0;
}

View File

@@ -105,6 +105,7 @@
<script>
import api from "@/packageCa/apiCa/studentProfile.js"
import apiuser from "@/packageCa/apiCa/user.js"
export default {
data() {
return {
@@ -127,6 +128,27 @@
url: `/packageCa/pagesTest/testList`
})
},
// 添加日志
postLog(operationType, remarks, beforeData = "", afterData = ""){
try {
const data = {
OperationType: operationType,
Remarks: remarks,
BeforeOperationJson: beforeData,
AfterOperationJson: afterData
};
console.log(data);
// return;
// 异步记录日志,不阻塞主流程
apiuser.saveUserOperationLog(data).then((res) => {
console.log('[Operation Log] 记录成功', res);
}).catch((err) => {
console.error('[Operation Log] 记录失败', err);
});
} catch (e) {
console.error('[Operation Log] 记录异常', e);
}
},
//选中职业添加
async checkedJob(ITEM){
uni.showLoading({
@@ -141,6 +163,7 @@
icon: "none"
})
this.getGXCareerPlanList();
this.postLog(304,`【新增】新增了${ITEM.Name}意向职业`,"",JSON.stringify(ITEM))
} else {
uni.showToast({
title: res.Message,

View File

@@ -121,6 +121,7 @@
<script>
import api from "@/packageCa/apiCa/studentProfile.js"
import apiuser from "@/packageCa/apiCa/user.js"
export default {
data() {
return {
@@ -145,6 +146,27 @@
this.queryPlanList();
},
methods: {
// 添加日志
postLog(operationType, remarks, beforeData = "", afterData = ""){
try {
const data = {
OperationType: operationType,
Remarks: remarks,
BeforeOperationJson: beforeData,
AfterOperationJson: afterData
};
console.log(data);
// return;
// 异步记录日志,不阻塞主流程
apiuser.saveUserOperationLog(data).then((res) => {
console.log('[Operation Log] 记录成功', res);
}).catch((err) => {
console.error('[Operation Log] 记录失败', err);
});
} catch (e) {
console.error('[Operation Log] 记录异常', e);
}
},
// 切换目标标签
changeTarget(ITEM){
if(ITEM.EncodeId == this.checkedTargetCode){
@@ -221,6 +243,7 @@
})
this.queryPlanList();
this.delIds=[];
this.postLog(302,`【新增】新增了学习计划`,"",JSON.stringify(data))
} else {
uni.showToast({
title: res.Message,

View File

@@ -127,6 +127,7 @@
<script>
import api from "@/packageCa/apiCa/studentProfile.js"
import apiuser from "@/packageCa/apiCa/user.js"
export default {
data() {
return {
@@ -192,6 +193,7 @@
this.jobSkill = JSON.parse(data.JobSkill).slice(0,5);
this.professionalRequire = JSON.parse(data.ProfessionalRequire).slice(0,5);
this.isLoadingEnd = true;
this.postLog(303,`【新增】查看了${data.Name}的职业发展路径`,"",JSON.stringify(res.Data))
} else {
uni.showToast({
title: res.Message,
@@ -199,6 +201,27 @@
})
}
},
// 添加日志
postLog(operationType, remarks, beforeData = "", afterData = ""){
try {
const data = {
OperationType: operationType,
Remarks: remarks,
BeforeOperationJson: beforeData,
AfterOperationJson: afterData
};
console.log(data);
// return;
// 异步记录日志,不阻塞主流程
apiuser.saveUserOperationLog(data).then((res) => {
console.log('[Operation Log] 记录成功', res);
}).catch((err) => {
console.error('[Operation Log] 记录失败', err);
});
} catch (e) {
console.error('[Operation Log] 记录异常', e);
}
},
// 去测评
navTest(){
uni.navigateTo({

View File

@@ -175,6 +175,7 @@
<script>
import api from "@/packageCa/apiCa/studentProfile.js"
import apiuser from "@/packageCa/apiCa/user.js"
export default {
data() {
return {
@@ -199,6 +200,27 @@
this.querySmartTargets();
},
methods: {
// 添加日志
postLog(operationType, remarks, beforeData = "", afterData = ""){
try {
const data = {
OperationType: operationType,
Remarks: remarks,
BeforeOperationJson: beforeData,
AfterOperationJson: afterData
};
console.log(data);
// return;
// 异步记录日志,不阻塞主流程
apiuser.saveUserOperationLog(data).then((res) => {
console.log('[Operation Log] 记录成功', res);
}).catch((err) => {
console.error('[Operation Log] 记录失败', err);
});
} catch (e) {
console.error('[Operation Log] 记录异常', e);
}
},
goPlan(){
if(this.targetList.length==0){
uni.showToast({
@@ -248,6 +270,7 @@
icon: "success"
})
this.querySmartTargets();
this.postLog(301,`【新增】保存SMART目标`,"",JSON.stringify(this.targetForm))
} else {
uni.showToast({
title: res.Message,
@@ -300,6 +323,7 @@
Timeliness: "",
};
this.querySmartTargets();
this.postLog(301,`【删除】删除SMART目标`,"",JSON.stringify(this.targetForm))
} else {
uni.showToast({
title: res.Message,

View File

@@ -1,4 +1,4 @@
// const baseUrl = "https://localhost:7026/career";
// const baseUrl = "https://ksrs.51xuanxiao.com/career";
const baseUrl = "https://www.xjksly.cn/career";
const request = {}
const headers = {}

View File

@@ -5,6 +5,7 @@
-->
<template>
<!-- @scroll="handleScroll" @scrolltolower="scrollBottom" -->
<!-- #ifdef MP-WEIXIN -->
<scroll-view :scroll-y="true" class="container" :class="{'h5-pc-container': isH5}" :show-scrollbar="false" style="background-image: url(../../../packageRc/static/pageBgIndex.png);">
<view style="padding: 40rpx 28rpx;">
<!-- #ifdef MP-WEIXIN -->
@@ -97,6 +98,10 @@
</template>
</view>
</scroll-view>
<!-- #endif -->
<!-- #ifdef H5 -->
<IndexYtj />
<!-- #endif -->
</template>
<script setup>
@@ -226,6 +231,7 @@ function changeJobType(val){
}
// 登录检查函数
import { storeToRefs } from 'pinia';
import IndexYtj from './indexYtj.vue';
const { userInfo, hasLogin, token } = storeToRefs(useUserStore());
const checkLogin = () => {
const tokenValue = uni.getStorageSync('token') || '';
@@ -240,7 +246,7 @@ const checkLogin = () => {
function nextDetail(job) {
// 登录检查
if (checkLogin()) {
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}`);
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}&encryptJobId=${job.encryptJobId}`);
}
}

View File

@@ -0,0 +1,815 @@
<!--
* @Date: 2025-10-16 15:15:47
* @LastEditors: shirlwang
* @LastEditTime: 2026-01-27 09:30:18
-->
<template>
<!-- @scroll="handleScroll" @scrolltolower="scrollBottom" -->
<scroll-view :scroll-y="true" class="container" :class="{'h5-pc-container': isH5}" :show-scrollbar="false">
<!-- 自定义导航栏 -->
<view class="custom-nav" :style="{paddingTop: statusBarHeight + 'px'}">
<view class="nav-content">
<view class="nav-back" @click="back"><text class="iconfont"><</text></view>
<view class="nav-title">高校毕业生智慧就业</view>
<view class="nav-placeholder"></view>
</view>
</view>
<view class="main-content">
<!-- #ifdef MP-WEIXIN -->
<view class="kinggang">
<view @click="navTo('/packageA/pages/myResume/myResume')">
<image src="../../../packageRc/static/kinggang1.png"/>
<view>信息维护</view>
</view>
<view @click="navTo('/packageA/pages/Intendedposition/Intendedposition')">
<image src="../../../packageRc/static/kinggang5.png"/>
<view>投递记录</view>
</view>
<view @click="tiao()">
<image src="../../../packageRc/static/kinggang2.png"/>
<view>需求上报</view>
</view>
<view>
<image @click="goAiAu" src="../../../packageRc/static/kinggang3.png"/>
<view>虚拟面试</view>
</view>
<view @click="goCa">
<image src="../../../packageRc/static/kinggang4.png"/>
<view>素质测评</view>
</view>
</view>
<!-- #endif -->
<!-- 岗位类型切换 -->
<view class="tabs">
<view class="tab" :class="{active: pageState.type == ''}" @click="changeJobType('')">岗位列表</view>
<view class="tab" :class="{active: pageState.type == 2}" @click="changeJobType(2)">实习实训</view>
<view class="tab" :class="{active: pageState.type == 3}" @click="changeJobType(3)">社区实践</view>
</view>
<!-- 子选项卡 -->
<view class="titles">
<view class="title-item" :class="{active: activeTitle == 1}" @click="activeTitle = 1,getJobRecommed()">
<view>推荐<text class="accent">岗位</text></view>
</view>
<view class="title-item" :class="{active: activeTitle == 2}" @click="activeTitle = 2,getJobList()">
<view>热门<text class="accent">岗位</text></view>
</view>
</view>
<!-- 岗位列表改为网格布局 -->
<view class="job-grid">
<view v-for="(item, index) in jobList" :key="index" @click="nextDetail(item)" class="job-card-box">
<view class="job-top">
<view class="job-name">{{ item.jobTitle }}</view>
<view class="job-salary">{{item.minSalary}}-{{item.maxSalary}}/</view>
</view>
<view class="job-tags">
<view v-if="item.jobLocationAreaCode" class="tag"><dict-Label dictType="jobLocationAreaCode" :value="item.jobLocationAreaCode"></dict-Label></view>
<view class="tag"><dict-Label dictType="education" :value="item.education"></dict-Label></view>
<view class="tag"><dict-Label dictType="experience" :value="item.experience"></dict-Label></view>
</view>
<view class="job-desc">
{{ vacanciesTo(item.vacancies) }} | {{item.jobCategory}} | {{ item.jobCategory }}
</view>
<view class="company-link">
<image class="comp-icon" src="../../../packageRc/static/dmsc/gs.png" />
<view class="comp-name">{{ item.companyName }}</view>
</view>
<view class="delivery-btn" @click.stop="nextDetail(item)">简历投递</view>
</view>
</view>
<view class="view-more-btn" @click="viewMore">查看更多内容</view>
<!-- 政策专区改为常驻显示 -->
<view class="titles section-title" style="justify-content: space-between; margin-top: 36rpx;">
<view class="title-item active"><view>政策<text class="accent">专区</text></view></view>
<view class="more-link" @click="toPolicyList">{{'查看更多 >'}}</view>
</view>
<view v-for="(item, index) in policyList" :key="index" class="policy-list-card" @click="toPolicyDetail(item)">
<view class="card-left">
<image class="clock-icon" src="../../../packageRc/static/dmsc/sj.png" />
<view class="date-md">{{ formatMD(item.publishTime || item.createTime) }}</view>
<view class="date-year">{{ formatYear(item.publishTime || item.createTime) }}</view>
</view>
<view class="card-right">
<view class="card-title">{{ item.zcmc }}</view>
<view class="card-infos">
<view v-if="item.zcLevel" class="info-tag">{{ item.zcLevel }}</view>
<view v-if="item.sourceUnit" class="info-tag">{{ item.sourceUnit }}</view>
</view>
</view>
</view>
</view>
</scroll-view>
</template>
<script setup>
import { reactive, inject, watch, ref, onMounted, watchEffect, nextTick } from 'vue';
const { $api, navTo, vacanciesTo, formatTotal, config } = inject('globalFunction');
const isH5 = ref(false);
const uniIconSize = ref(18);
// #ifdef H5
isH5.value = true;
uniIconSize.value = 20;
// #endif
// 状态栏高度(用于自定义导航栏)
const statusBarHeight = ref(0);
try {
const sysInfo = uni.getSystemInfoSync();
statusBarHeight.value = sysInfo.statusBarHeight || 0;
} catch(e) {}
import { getPolicyList } from '@/packageRc/apiRc/policy';
let policyList = ref([])
function getPolicy() {
getPolicyList({pageNum: 1, pageSize: 4,zclx:'1'}).then(res => {
if (res.code == 200) {
policyList.value = res.rows
} else {
throw new Error();
}
})
}
let tabType = ref(1)
function changeType(type) {
tabType.value = type
}
function toPolicyList() {
navTo(`/packageRc/pages/policy/policyList?zclx=1`)
}
function toPolicyDetail(item) {
navTo(`/packageRc/pages/policy/policyDetail?id=${item.id}`)
}
let activeTab = ref(1)
let activeTitle = ref(1)
function back() {
// uni.navigateBack({
// delta: 1
// })
window.location.href='https://www.xjksly.cn/mechine-single-vue/'
// uni.reLaunch({
// url: '/pages/index/index'
// })
}
onMounted(()=>{
getJobRecommed()
getPolicy();
})
function goCa(){
if (checkLogin()) {
const userInfo = uni.getStorageSync('userInfo')
navTo(`/packageCa/search/search?userId=${userInfo.userId}&name=${userInfo.name}`);
}
}
// 跳转AI智能面试
function goAiAu(){
if (checkLogin()) {
const userInfo = uni.getStorageSync('userInfo')
navTo(`/packageCa/search/AIAudition?userId=${userInfo.userId}&name=${userInfo.name}`);
}
}
function viewMore() {
navTo(`/packageRc/pages/jobList/jobList`);
}
function tiao(){
console.log('尝试导航到待办详情页面');
// 尝试直接使用uni.navigateTo使用正确的格式
uni.navigateTo({
url: `/packageRc/pages/needs/personNeeds`,
success: function() {
console.log('导航成功');
},
fail: function(err) {
console.error('导航失败:', err);
}
});
}
import useUserStore from '@/stores/useUserStore';
const conditionSearch = ref({});
const pageState = reactive({
page: 0,
total: 0,
maxPage: 2,
pageSize: 4,
search: {
order: 0,
},
type:'',
});
let jobList = ref([])
// 获取推荐岗位
function getJobRecommed(){
let params = {
pageSize: pageState.pageSize,
sessionId: useUserStore().seesionId,
...pageState.search,
...conditionSearch.value,
isPublish: 1,
type:pageState.type
};
$api.createRequest('/app/job/recommend', params).then((resData) => {
if (resData.code == 200 && resData.data.length) {
jobList.value = resData.data
} else {
throw new Error();
}
}).catch(() => {
// 造一些测试数据
const mock = { jobTitle: '计算机网络运维员', companyName: '新疆天山人才智汇发展有限责任公司', minSalary: '面议', maxSalary: '面议' };
jobList.value = [mock, mock, mock, mock];
});
}
// 获取岗位列表
function getJobList(){
let params = {
current: pageState.page,
pageSize: pageState.pageSize,
...pageState.search,
// ...conditionSearch.value,
type:pageState.type
};
$api.createRequest('/app/job/list', params).then((resData) => {
jobList.value = resData.rows
pageState.total = 0;
});
}
// 更改实习实训等
function changeJobType(val){
pageState.type = val
if(activeTitle.value == 1){
getJobRecommed()
}else{
getJobList()
}
}
// 登录检查函数
import { storeToRefs } from 'pinia';
const { userInfo, hasLogin, token } = storeToRefs(useUserStore());
const checkLogin = () => {
const tokenValue = uni.getStorageSync('token') || '';
if (!tokenValue || !hasLogin.value) {
// 未登录,打开授权弹窗
wxAuthLoginRef.value?.open();
return false;
}
return true;
};
// 跳转到详情页面
function nextDetail(job) {
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}&encryptJobId=${job.encryptJobId}`);
// 登录检查
// if (checkLogin()) {
// }
}
function formatMD(dateStr) {
if (!dateStr) return '--';
const parts = dateStr.split('-').length > 1 ? dateStr.split('-') : dateStr.split(' ');
// 处理 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss
let d = parts[0].includes('-') ? parts[0].split('-') : parts;
if (d.length >= 3) {
return `${d[1]}-${d[2].substring(0,2)}`;
}
return dateStr;
}
function formatYear(dateStr) {
if (!dateStr) return '';
const parts = dateStr.split('-');
if (parts.length >= 1) {
return parts[0].substring(0, 4);
}
return '';
}
</script>
<style lang="less" scoped>
/* 隐藏滚动条 */
::-webkit-scrollbar {
display: none;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
}
view{box-sizing: border-box;display: block;}
.container{
background-color: #FFFFFF;
min-height: 1920px;
min-width: 1080px;
box-sizing: border-box;
}
/* 自定义导航栏 */
.custom-nav {
background: #107AFD;
width: 100%;
.nav-content {
height: 120rpx;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24rpx;
.nav-back {
width: 72rpx;
height: 120rpx;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-weight: 300;
.iconfont{
font-size: 40px!important;
}
}
.nav-title {
color: #fff;
font-size: 43rpx;
font-weight: bold;
}
.nav-placeholder {
width: 72rpx;
}
}
}
.main-content {
position: relative;
z-index: 2;
/* 页面全局边距加倍 */
padding: 38rpx 29rpx;
}
.kinggang{
display: flex;
justify-content: space-around;
align-items: center;
padding: 14rpx 10rpx 29rpx 10rpx;
font-size: 31rpx;
background: #FFFFFF;
border-radius: 12rpx;
margin-bottom: 19rpx;
>view{
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
}
image{
width: 96rpx;
height: 96rpx;
margin-bottom: 12rpx;
}
}
.tabs{
/* 调大上方选项卡的边距 */
margin: 38rpx auto 38rpx;
border-radius: 72rpx;
display: flex;
background: #F4F6F9;
color: #878787;
text-align: center;
width: 80%;
overflow: hidden;
padding: 5rpx;
box-sizing: border-box;
.tab{
flex: 1;
line-height: 72rpx;
position: relative;
font-size: 43rpx;
font-weight: 500;
transition: all 0.25s;
border-radius: 72rpx;
&.active{
color: #fff;
background: #107AFD;
box-shadow: none;
}
}
}
.titles{
display: flex;
/* 调大标题下边距 */
margin-bottom: 43rpx;
align-items: flex-end;
.title-item{
font-size: 72rpx;
font-weight: bold;
color: #282828;
margin-right: 34rpx;
position: relative;
>view{
position: relative;
z-index: 2;
padding: 0 5rpx;
.accent {
color: #EC7737;
margin-left: 2rpx;
}
}
&.active::after{
content: '';
position: absolute;
z-index: 1;
bottom: -5rpx;
left: 10%;
width: 80%;
height: 12rpx;
border-radius: 50px;
background: linear-gradient(90deg, rgba(82, 149, 255, 0.4) 0%, rgba(24, 116, 255, 0) 100%);
}
}
}
.job-list{
width: 100%;
margin: 0 auto;
color: #333333;
border-radius: 7rpx;
background: #FFFFFF;
padding: 19rpx;
margin-bottom: 14rpx;
position: relative;
/* 去掉阴影,保持扁平统一 */
.sign{
position: absolute;
font-size: 17rpx;
right: 0;
top: 0;
padding: 5rpx 12rpx;
border: 1rpx solid #EC4827;
background: rgba(227, 79, 49, 0.09);
border-top-right-radius: 14rpx;
border-bottom-left-radius: 14rpx;
color: #EC4827;
}
.top-line{
display: flex;
justify-content: space-between;
font-size: 14rpx;
color: #A2A2A2;
margin-bottom: 10rpx;
.salary{
font-size: 19rpx;
color: #4C6EFB;
font-weight: bold;
}
}
.title{
font-size: 19rpx;
font-weight: bold;
color: #282828;
margin-bottom: 10rpx;
display: flex;
image{
width: 28rpx;
height: 28rpx;
margin-right: 7rpx;
}
}
.infos{
display: flex;
flex-wrap: wrap;
font-size: 14rpx;
margin-bottom: 10rpx;
line-height: 25rpx;
view{
padding: 0 10rpx;
margin-right: 6rpx;
background: #F2F2F2;
}
}
.bottom-line{
display: flex;
justify-content: space-between;
font-size: 14rpx;
color: #A2A2A2;
margin-top: 7rpx;
}
}
.view-more-btn{
padding: 6rpx 34rpx;
background: #FFFFFF;
color: #4C6EFB;
border: 1rpx solid #4C6EFB;
text-align: center;
border-radius: 24rpx;
width: fit-content;
margin: 0 auto;
margin-bottom: 12rpx;
}
.job-grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
/* 列表前边距调大 */
margin-top: 29rpx;
.job-card-box {
/* 缩小宽度比例以增加瀑布流列间距 */
width: calc(50% - 14rpx);
background: #FFFFFF;
background-image: url(../../../packageRc/static/dmsc/kpbj.png);
background-size: 100% 100%;
/* 加大卡片下边距 */
margin-bottom: 29rpx;
border: 1px solid #D1E5FF;
border-radius: 10rpx;
/* 加大卡片内边距 */
padding: 29rpx;
box-sizing: border-box;
display: flex;
flex-direction: column;
.job-top {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 14rpx;
.job-salary {
color: #EC7737;
font-weight: bold;
font-size: 38rpx;
flex-shrink: 0;
}
.job-name {
font-size: 43rpx;
font-weight: bold;
color: #333;
flex: 1;
margin-top: 0;
margin-right: 7rpx;
/* 只保留单行溢出,以适应不同宽度 */
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.job-tags {
display: flex;
flex-wrap: wrap;
margin-bottom: 19rpx;
.tag {
background: #7DA6FF;
color: #FFFFFF;
font-size: 29rpx;
padding: 5rpx 12rpx;
border-radius: 7rpx;
margin-right: 10rpx;
margin-bottom: 10rpx;
}
}
.job-desc {
font-size: 29rpx;
color: #4C6EFB;
margin-bottom: 26rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.company-link {
display: flex;
align-items: center;
margin-top: auto;
margin-bottom: 29rpx;
.comp-icon {
width: 34rpx;
height: 34rpx;
margin-right: 10rpx;
flex-shrink: 0;
}
.comp-name {
font-size: 29rpx;
color: #666;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.delivery-btn {
width: 75%;
margin: 0 auto;
height: 58rpx;
line-height: 58rpx;
background: #2591FF; /* 与设计图一致的亮蓝色 */
color: #FFFFFF;
text-align: center;
font-size: 31rpx;
font-weight: 500;
border-radius: 7rpx;
/* 移除阴影以贴合扁平化设计稿 */
}
}
}
.policy-list-card {
width: 100%;
margin: 0 auto;
color: #333333;
/* 政策卡片大边距与内边距 */
margin-bottom: 29rpx;
box-sizing: border-box;
display: flex;
background: linear-gradient(180deg, #F0F8FF 0%, #FFFFFF 100%);
padding: 38rpx 29rpx;
border-radius: 10rpx;
border: 1px solid #D1E5FF;
box-shadow: 0px 2rpx 7rpx 0px rgba(16, 122, 253, 0.05);
.card-left {
/* 加宽左侧保护不再折行 */
width: 132rpx;
flex-shrink: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-right: 1px solid #E5EEFA;
/* 增大左右空隙 */
margin-right: 29rpx;
.clock-icon {
width: 31rpx;
height: 31rpx;
margin-bottom: 7rpx;
}
.date-md {
font-size: 36rpx;
font-weight: bold;
color: #107afd;
line-height: 1;
margin-bottom: 7rpx;
}
.date-year {
font-size: 24rpx;
color: #107afd;
line-height: 1;
}
}
.card-right {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
.card-title {
font-size: 38rpx;
font-weight: bold;
color: #333;
margin-bottom: 14rpx;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.card-infos {
display: flex;
flex-wrap: wrap;
.info-tag {
font-size: 29rpx;
color: #999;
margin-right: 14rpx;
}
}
}
}
/* #ifdef H5 */
.h5-pc-container {
& > view {
width: 100% !important;
margin: 0 auto !important;
padding-left: 32px !important;
padding-right: 32px !important;
padding-top: 0 !important; /* 彻底移除顶部补白 */
box-sizing: border-box !important;
}
.showtab {
margin-top: 0 !important; /* 移除卡片顶部间距 */
margin-bottom: 72rpx;
height: 204rpx;
.tabItem {
height: 204rpx !important;
image:first-child {
width: 100%;
height: 100%;
object-fit: contain;
}
}
.activeImg {
width: 96rpx !important;
height: 12rpx !important;
bottom: -24rpx !important;
}
}
.tabs {
margin-bottom: 48rpx;
background-color: #eee;
border-radius: 60px;
padding: 10px;
.tab {
width: 33.3% !important;
line-height: 108rpx !important;
font-size: 36px !important;
border-radius: 60rpx;
}
}
.titles {
margin-top: 24rpx;
margin-bottom: 60px;
.title-item {
font-size: 40px;
font-weight: 600;
margin-right: 100px !important;
>view {
padding: 0 10rpx !important;
}
&::after {
height: 12rpx !important;
bottom: -16px !important;
width: 20% !important;
left: 40% !important;
background: orange;
border-radius: 0;
}
}
.more-link {
font-size: 20px !important;
color: #A2A2A2;
}
}
.job-list {
padding: 29rpx 24rpx !important;
margin-bottom: 19rpx !important;
border-radius: 14rpx !important;
border: 1px solid #f0f0f0;
box-shadow: 0px 1rpx 6rpx rgba(0, 0, 0, 0.02);
.sign {
font-size: 20px !important;
padding: 5rpx 12rpx !important;
}
}
.title {
font-size: 24px !important;
font-weight: 600;
margin-bottom: 14rpx !important;
}
.infos view {
font-size: 20px !important;
line-height: 1.5 !important;
padding: 6rpx 14rpx !important;
margin-bottom: 7rpx;
background: #f5f5f5 !important;
border-radius: 7rpx !important;
}
.salary {
font-size: 24px !important;
font-weight: 600;
}
.time {
font-size: 20px !important; /* 发布日期字号放大 */
}
.bottom-line {
font-size: 20px !important;
margin-top: 12rpx !important;
}
.view-more-btn {
font-size: 24px !important; /* 查看更多字号放大 */
padding: 12rpx 48rpx !important;
border-radius: 36rpx !important;
}
}
/* #endif */
</style>

View File

@@ -400,7 +400,11 @@
<!-- 筛选 -->
<select-filter ref="selectFilterModel"></select-filter>
<!-- 微信授权登录弹窗 -->
<WxAuthLogin
ref="wxAuthLoginRef"
@success="handleLoginSuccess"
></WxAuthLogin>
<!-- <view class="maskFristEntry" v-if="maskFristEntry">
<view class="entry-content">
@@ -527,7 +531,7 @@ import {
} from "@/stores/useRecommedIndexedDBStore.js";
import { useScrollDirection } from "@/hook/useScrollDirection";
import { useColumnCount } from "@/hook/useColumnCount";
import WxAuthLogin from "@/components/WxAuthLogin/WxAuthLogin.vue";
import IconfontIcon from "@/components/IconfontIcon/IconfontIcon.vue";
// 企业卡片组件已内联到模板中
// 滚动状态管理
@@ -580,7 +584,7 @@ const loadmoreRef = ref(null);
const conditionSearch = ref({});
const waterfallcolumn = ref(2);
const maskFristEntry = ref(false);
const wxAuthLoginRef = ref(null);
const state = reactive({
tabIndex: "all",
});
@@ -680,7 +684,7 @@ onMounted(() => {
// 监听退出登录事件,显示微信登录弹窗
uni.$on("showLoginModal", () => {
uni.navigateTo({ url: '/pages/login/wx-login' });
wxAuthLoginRef.value?.open();
});
});
@@ -708,8 +712,8 @@ watch(
const checkLogin = () => {
const tokenValue = uni.getStorageSync("token") || "";
if (!tokenValue || !hasLogin.value) {
// 未登录,跳转到登录页面
uni.navigateTo({ url: '/pages/login/wx-login' });
// 未登录,打开授权弹窗
wxAuthLoginRef.value?.open();
return false;
}
return true;

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 B

View File

@@ -660,7 +660,10 @@
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "高校毕业生智慧就业"
"navigationBarTitleText": "高校毕业生智慧就业",
// #ifdef H5
"navigationStyle": "custom"
// #endif
}
},
{

View File

@@ -161,12 +161,12 @@
</view>
<view class="service-title">帮扶</view>
</view>
<view class="service-item press-button" v-if="isFourLevelLinkagePurview" @click="helpTaskClick">
<!-- <view class="service-item press-button" v-if="isFourLevelLinkagePurview" @click="helpTaskClick">
<view class="service-icon service-icon-1">
<uni-icons type="shop" size="32" color="#FFFFFF"></uni-icons>
</view>
<view class="service-title">帮扶任务</view>
</view>
</view> -->
<view class="service-item press-button" @click="handleNoticeClick">
<view class="service-icon service-icon-10">
<uni-icons type="sound" size="32" color="#FFFFFF"></uni-icons>
@@ -756,7 +756,9 @@ const helpTaskClick = () =>{
}
//招聘会模块跳转
const handleJobFairClick = () => {
navTo('/pages/careerfair/careerfair');
if (checkLogin()) {
navTo('/pages/careerfair/careerfair');
}
};
const list = ref([]);
const pageState = reactive({
@@ -784,6 +786,7 @@ const rangeOptions = ref([
]);
const isLoaded = ref(false);
const isInitialized = ref(false); // 添加初始化标志
const isRecommendLoading = ref(false); // 请求锁,防止重复调用
const { columnCount, columnSpace } = useColumnCount(() => {
pageState.pageSize = 10 * (columnCount.value - 1) + 10;
@@ -948,20 +951,27 @@ const handleNearbyClick = (options ) => {
// #endif
};
const handleNoticeClick = () =>{
uni.navigateTo({
url:'/packageB/notice/index'
})
}
function handleInstitutionClick(type){
if(type=='evaluate'){
if (checkLogin()) {
uni.navigateTo({
url:'/packageB/institution/evaluationAgency'
})
}else if (type=='training'){
uni.navigateTo({
url:'/packageB/institution/trainingInstitution'
url:'/packageB/notice/index'
})
}
}
function handleInstitutionClick(type){
if (checkLogin()) {
if(type=='evaluate'){
uni.navigateTo({
url:'/packageB/institution/evaluationAgency'
})
}else if (type=='training'){
uni.navigateTo({
url:'/packageB/institution/trainingInstitution'
})
}
}
}
// 处理服务功能点击
@@ -1092,7 +1102,7 @@ function clearfindJob(job) {
}
function nextDetail(job) {
navTo(`/packageA/pages/post/post?encryptJobId=${encodeURIComponent(job.encryptJobId)}`);
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}&encryptJobId=${encodeURIComponent(job.encryptJobId)}`);
}
function navToService(serviceType) {
@@ -1234,10 +1244,12 @@ function handelHostestSearch(val) {
}
function getJobRecommend(type = 'add') {
if (isRecommendLoading.value) return;
if (type === 'refresh') {
list.value = [];
if (waterfallsFlowRef.value) waterfallsFlowRef.value.refresh();
}
isRecommendLoading.value = true;
let params = {
pageSize: pageState.pageSize + 10,
sessionId: useUserStore().seesionId,
@@ -1311,6 +1323,8 @@ function getJobRecommend(type = 'add') {
if (!data.length) {
useUserStore().initSeesionId();
}
}).finally(() => {
isRecommendLoading.value = false;
});
}

View File

@@ -1,5 +1,6 @@
<template>
<AppLayout back-gorund-color="#F4F4F4">
<view class="mine-content">
<!-- 自定义tabbar -->
<CustomTabBar :currentPage="4" />
<!-- 企业用户信息卡片 -->
@@ -174,6 +175,7 @@
<template #footer>
<!-- 统一使用系统tabBar -->
</template>
</view>
</AppLayout>
</template>
@@ -358,6 +360,11 @@ function submitFeedback() {
.card-top.tilt {
transform: perspective(600px) rotateY(8deg) rotateX(4deg);
}
.mine-content{
padding: 28rpx 28rpx 90rpx 28rpx;
height: 100%;
overflow-y: auto;
}
.mini-cards{
padding: 28rpx
.card-top{

View File

@@ -134,7 +134,7 @@ function nextDetail(job) {
const recordData = recommedIndexDb.JobParameter(job);
recommedIndexDb.addRecord(recordData);
}
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}`);
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(job.jobId)}&encryptJobId=${encodeURIComponent(job.encryptJobId)}`);
}
function nextVideo(job) {

View File

@@ -29,6 +29,7 @@ function buildIndex(tree) {
const useDictStore = defineStore("dict", () => {
// 定义状态
const complete = ref(false)
const dictLoading = ref(false)
const state = reactive({
education: [],
experience: [],
@@ -43,13 +44,16 @@ const useDictStore = defineStore("dict", () => {
})
// political_affiliation
const getDictData = async (dictType, dictName) => {
if (dictType && dictName) {
return getDictSelectOption(dictType).then((data) => {
state[dictName] = data
return data
})
}
if (complete.value) return
if (dictLoading.value) return
dictLoading.value = true
try {
if (dictType && dictName) {
return getDictSelectOption(dictType).then((data) => {
state[dictName] = data
return data
})
}
const [education, experience, area, scale, sex, affiliation, nature, noticeType] =
await Promise.all([
getDictSelectOption('education'),
@@ -75,16 +79,16 @@ const useDictStore = defineStore("dict", () => {
} catch (error) {
console.error('Error fetching dictionary data:', error);
// 确保即使出错也能返回空数组
if (!dictType && !dictName) {
state.education = [];
state.experience = [];
state.area = [];
state.scale = [];
state.sex = [];
state.affiliation = [];
state.nature = [];
state.noticeType = [];
}
state.education = [];
state.experience = [];
state.area = [];
state.scale = [];
state.sex = [];
state.affiliation = [];
state.nature = [];
state.noticeType = [];
} finally {
dictLoading.value = false
}
};

37
utils/crypto.js Normal file
View File

@@ -0,0 +1,37 @@
import { sm4 } from 'sm-crypto';
export function sm4Decrypt(key, value, mode = "hex") {
try {
if (key.length !== 32) {
uni.showToast({ title: '密钥必须是32位16进制字符串128位', icon: 'none' });
return;
}
const decrypted = sm4.decrypt(value, key, {
mode: 'ecb',
cipherType: mode === 'hex' ? 'hex' : 'base64',
padding: 'pkcs#5'
});
return decrypted;
} catch (e) {
console.error('sm4 decrypt error:', e);
return value;
}
}
export function sm4Encrypt(key, value, mode = "hex") {
try {
if (key.length !== 32) {
uni.showToast({ title: '密钥必须是32位16进制字符串128位', icon: 'none' });
return;
}
const encrypted = sm4.encrypt(value, key, {
mode: 'ecb',
cipherType: mode === 'hex' ? 'hex' : 'base64',
padding: 'pkcs#5'
});
return encrypted;
} catch (e) {
console.error('sm4 encrypt error:', e);
return value;
}
}

View File

@@ -1,5 +1,80 @@
import config from "@/config.js"
import { sm4Encrypt, sm4Decrypt } from '@/utils/crypto';
import useUserStore from '@/stores/useUserStore';
const needToEncryptSet = new Set([
'POST:/app/login',
'GET:/app/user/resume',
'POST:/app/user/resume',
'POST:/app/user/experience/edit',
'POST:/app/user/experience/delete',
'GET:/app/user/experience/getSingle',
'GET:/app/user/experience/list',
'POST:/app/user/cert',
'POST:/app/user/getUserArchives',
]);
const encryptPathPrefixes = [
// '/app/common/',
'/app/chat/',
// '/app/speech/',
'/app/job/',
'/app/company/',
'/app/companycontact/',
'/app/appskill/',
'/app/userworkexperiences/',
'/app/appWxphoneSmsCode',
'/app/sendSmsAgain',
'/app/user/',
'/registerUser',
'/app/user/resume/',
'/cms/job/recommen/',
'/app/appLoginPhone',
'/app/notice/',
'/app/idCardLogin',
'/app/phoneLogin',
];
const isEncryptNeeded = (method, url) => {
const key = `${method.toUpperCase()}:${url}`;
if (needToEncryptSet.has(key)) return true;
for (const encryptKey of needToEncryptSet) {
const [encryptMethod, encryptUrl] = encryptKey.split(':');
if (encryptMethod === method.toUpperCase() && url.startsWith(encryptUrl.split('/{')[0])) {
return true;
}
}
for (const prefix of encryptPathPrefixes) {
if (url.startsWith(prefix)) {
return true;
}
}
return false;
};
const encryptRequestData = (data) => {
const jsonData = JSON.stringify(data);
// const jsonData = JSON.stringify({a: '1'});
// console.log('[请求] 加密前:', jsonData)
return {
encrypted: true,
encryptedData: sm4Encrypt(config.sm4Config.key, jsonData),
timestamp: Date.now(),
};
};
const handleResponseData = (resData) => {
try {
if (resData?.encrypted) {
const decrypted = sm4Decrypt(config.sm4Config.key, resData.encryptedData);
resData = JSON.parse(decrypted);
// console.log('[请求] 解密后数据:', resData);
}
} catch (e) {
console.error('[请求] 解密失败:', e.message);
}
return resData;
};
export function request({
url,
method = 'GET',
@@ -89,25 +164,27 @@ export function createRequest(url, data = {}, method = 'GET', loading = false, h
if(needHeader){
header["Authorization"] = encodeURIComponent(Authorization);
}
const requestData = isEncryptNeeded(method, url) ? encryptRequestData(data) : data;
return new Promise((resolve, reject) => {
uni.request({
url: config.baseUrl + url,
method: method,
data: data,
data: requestData,
header,
success: resData => {
// 响应拦截
if (resData.statusCode === 200) {
const responseData = handleResponseData(resData.data)
const {
code,
msg
} = resData.data
} = responseData
if (code === 200) {
resolve(resData.data)
resolve(responseData)
return
}
// 处理业务错误
if (resData.data?.code === 401 || resData.data?.code === 402) {
if (responseData?.code === 401 || responseData?.code === 402) {
useUserStore().logOut()
}
// 显示具体的错误信息

View File

@@ -1,5 +1,6 @@
import config from "@/config.js"
import useUserStore from '@/stores/useUserStore';
import { sm4Encrypt, sm4Decrypt } from '@/utils/crypto';
/**
* @param url String请求的地址默认none
@@ -25,14 +26,23 @@ function StreamRequestMiniProgram(url, data = {}, onDataReceived, onError, onCom
const userStore = useUserStore();
const Authorization = userStore.token ? encodeURIComponent(userStore.token) : '';
const requestBody = data && Object.keys(data).length > 0
? {
encrypted: true,
encryptedData: sm4Encrypt(config.sm4Config.key, JSON.stringify(data)),
timestamp: Date.now(),
}
: data;
return new Promise((resolve, reject) => {
let buffer = '';
let hasReceivedContent = false;
let isCompleted = false;
const requestTask = uni.request({
url: config.StreamBaseURl + url,
method: 'POST',
data: data,
data: requestBody,
header: {
"Authorization": Authorization,
"Accept": "text/event-stream",
@@ -41,8 +51,11 @@ function StreamRequestMiniProgram(url, data = {}, onDataReceived, onError, onCom
enableChunked: true, // 启用分块传输
success: (res) => {
console.log('📡 Stream request completed');
onComplete && onComplete();
resolve();
if (!isCompleted) {
isCompleted = true;
onComplete && onComplete();
resolve();
}
},
fail: (err) => {
console.error('Stream 请求失败:', err);
@@ -172,16 +185,30 @@ function StreamRequestMiniProgram(url, data = {}, onDataReceived, onError, onCom
console.log('📄 提取的JSON数据:', jsonData);
if (jsonData === "[DONE]") {
console.log('✅ 收到结束标记 [DONE]');
onComplete && onComplete();
resolve();
if (!isCompleted) {
isCompleted = true;
onComplete && onComplete();
resolve();
}
return;
}
if (jsonData && jsonData.trim()) {
try {
const parsedData = JSON.parse(jsonData);
let parsedData = JSON.parse(jsonData);
console.log('🔧 解析后的JSON:', parsedData);
if (parsedData?.encrypted && typeof parsedData?.encryptedData === 'string') {
const decryptedStr = sm4Decrypt(config.sm4Config.key, parsedData.encryptedData);
if (decryptedStr && decryptedStr !== parsedData.encryptedData) {
try {
parsedData = JSON.parse(decryptedStr);
} catch (e) {
console.error('SSE解密数据JSON解析失败:', e.message);
}
}
}
// 检查是否有错误信息
const finishReason = parsedData?.choices?.[0]?.finish_reason;
if (finishReason === "error") {
@@ -279,12 +306,21 @@ function StreamRequestH5(url, data = {}, onDataReceived, onError, onComplete) {
"Accept": "text/event-stream",
"Content-Type": "application/json;charset=UTF-8"
};
const requestBody = data && Object.keys(data).length > 0
? {
encrypted: true,
encryptedData: sm4Encrypt(config.sm4Config.key, JSON.stringify(data)),
timestamp: Date.now(),
}
: data;
return new Promise(async (resolve, reject) => {
try {
const response = await fetch(config.StreamBaseURl + url, {
method: "POST",
headers,
body: JSON.stringify(data)
body: JSON.stringify(requestBody)
});
if (!response.ok) {
@@ -347,9 +383,21 @@ function StreamRequestH5(url, data = {}, onDataReceived, onError, onComplete) {
try {
// 检查JSON数据是否完整
if (jsonData && jsonData.trim() && jsonData !== "[DONE]") {
const parsedData = JSON.parse(jsonData);
let parsedData = JSON.parse(jsonData);
console.log('🔧 解析后的JSON:', parsedData);
if (parsedData?.encrypted && typeof parsedData?.encryptedData === 'string') {
const decryptedStr = sm4Decrypt(config.sm4Config.key, parsedData.encryptedData);
if (decryptedStr && decryptedStr !== parsedData.encryptedData) {
try {
const decrypted = JSON.parse(decryptedStr);
parsedData = decrypted;
} catch (e) {
console.error('SSE解密数据JSON解析失败:', e.message);
}
}
}
// 检查是否有错误信息
const finishReason = parsedData?.choices?.[0]?.finish_reason;
if (finishReason === "error") {
@@ -458,9 +506,21 @@ function StreamRequestH5(url, data = {}, onDataReceived, onError, onComplete) {
console.log('📄 提取的剩余JSON数据:', jsonData);
if (jsonData && jsonData !== "[DONE]") {
try {
const parsedData = JSON.parse(jsonData);
let parsedData = JSON.parse(jsonData);
console.log('🔧 解析后的剩余JSON:', parsedData);
if (parsedData?.encrypted && typeof parsedData?.encryptedData === 'string') {
const decryptedStr = sm4Decrypt(config.sm4Config.key, parsedData.encryptedData);
if (decryptedStr && decryptedStr !== parsedData.encryptedData) {
try {
const decrypted = JSON.parse(decryptedStr);
parsedData = decrypted;
} catch (e) {
console.error('SSE解密数据JSON解析失败:', e.message);
}
}
}
// 检查是否有错误信息
const finishReason = parsedData?.choices?.[0]?.finish_reason;
if (finishReason === "error") {
@@ -573,33 +633,49 @@ export function chatRequest(url, data = {}, method = 'GET', loading = false, hea
const header = headers || {};
header["Authorization"] = encodeURIComponent(Authorization);
const isEncryptedMethod = method.toUpperCase() === 'POST' || method.toUpperCase() === 'PUT';
const requestData = isEncryptedMethod && data && Object.keys(data).length > 0
? {
encrypted: true,
encryptedData: sm4Encrypt(config.sm4Config.key, JSON.stringify(data)),
timestamp: Date.now(),
}
: data;
return new Promise((resolve, reject) => {
uni.request({
url: config.StreamBaseURl + url,
method: method,
data: data,
data: requestData,
header,
success: resData => {
// 响应拦截
if (resData.statusCode === 200) {
let responseData = resData.data;
try {
if (responseData?.encrypted) {
const decrypted = sm4Decrypt(config.sm4Config.key, responseData.encryptedData);
responseData = JSON.parse(decrypted);
}
} catch (e) {
console.error('[chatRequest] 解密失败:', e.message);
}
const {
code,
msg
} = resData.data
} = responseData
if (code === 200) {
resolve(resData.data)
resolve(responseData)
return
}
uni.showToast({
title: msg || '请求失败',
icon: 'none'
})
// 拒绝Promise并提供详细错误信息
const err = new Error(msg || '请求失败,服务器返回错误码: ' + code)
err.error = resData
reject(err)
} else {
// 处理非200状态码
const errorMsg = `请求失败HTTP状态码: ${resData.statusCode}`
uni.showToast({
title: errorMsg,