18 Commits

Author SHA1 Message Date
xiebin
c01abfdd64 Merge branch 'main' of http://124.243.245.42:3000/sdz/qingdao-employment-service 2025-11-22 18:53:53 +08:00
xiebin
99f02927ac 对接招聘会接口 2025-11-22 18:53:52 +08:00
Apcallover
f515d07d2a Merge branch 'copy' 2025-11-22 17:12:19 +08:00
Apcallover
42d0451869 flat:切换应用 2025-11-22 17:11:11 +08:00
xiebin
4b8056b716 fix : 雷达图渲染 2025-11-21 15:41:47 +08:00
xiebin
a3d592eb02 remove : 职位详情-竞争力分析-雷达图的技能项 2025-11-21 15:34:38 +08:00
xiebin
41196466af 隐藏电子名片没有的字段 2025-11-21 14:50:59 +08:00
Apcallover
97a5c34e70 flat:tabbar 2025-11-21 09:39:53 +08:00
6024ae44a4 feat : 每次进入简历详情页,刷新简历信息 2025-11-20 18:58:40 +08:00
ab63143792 feat : 新增上传简历功能 2025-11-20 18:49:53 +08:00
Apcallover
29fe2aff0e flat: 暂存 2025-11-20 18:14:36 +08:00
Apcallover
90591289d0 flat: 更好aes.js 2025-11-20 17:20:55 +08:00
Apcallover
e5c5902322 flat: 合并 2025-11-20 16:34:00 +08:00
Apcallover
f1b18203ae flat:合并 2025-11-20 15:56:45 +08:00
Apcallover
5497398498 flat: ai对话提交 2025-11-20 09:17:29 +08:00
Apcallover
e67c53404b flat: 暂存 2025-11-18 19:53:55 +08:00
Apcallover
60a0448aa7 flat: 暂存 2025-11-18 19:43:15 +08:00
ca7273f152 style : 样式优化 2025-11-13 10:57:01 +08:00
27 changed files with 1526 additions and 1898 deletions

42
App.vue
View File

@@ -9,23 +9,26 @@ import config from '@/config.js';
const appword = 'aKd20dbGdFvmuwrt'; // 固定值
onLaunch((options) => {
getUserInfo();
// useUserStore().initSeesionId(); //更新
useDictStore().getDictData();
// uni.hideTabBar();
// 登录
// let token = uni.getStorageSync('token') || ''; // 同步获取 缓存信息
// if (token) {
// useUserStore()
// .loginSetToken(token)
// .then(() => {
// $api.msg('登录成功');
// });
// } else {
// uni.redirectTo({
// url: '/pages/login/login',
// });
// }
useDictStore().getDictData();
try {
getUserInfo();
} catch {
console.log('不是爱山东平台,使用测试登陆');
useUserStore().initSeesionId(); //更新
let token = uni.getStorageSync('token') || ''; // 同步获取 缓存信息
if (token) {
useUserStore()
.loginSetToken(token)
.then(() => {
$api.msg('登录成功');
});
} else {
uni.redirectTo({
url: '/pages/login/login',
});
}
}
});
onMounted(() => {});
@@ -40,23 +43,20 @@ onHide(() => {
function getUserInfo() {
lightAppJssdk.user.getUserInfoWithEncryptedParamByAppId({
appId: 'qdsrgznrgpp', // 接入方在成功创建应用后自动生成
appId: config.appInfo.loveShandong, // 接入方在成功创建应用后自动生成
success: function (data) {
if (data == '未登录') onLoginApp();
else {
if (typeof data == 'string') data = JSON.parse(data);
const sm2_privateKey = '7e14966df4ecd4241ed082ef716d82b52113cb5899ebdc704a98844d0a32b0dc';
const sm2_privateKey = config.appInfo.sm2PrivateKey;
let sm2_encrypt_result = data.data;
let sm2_decrypt_result = sm2_Decrypt(sm2_encrypt_result, sm2_privateKey);
if (typeof sm2_decrypt_result == 'string') sm2_decrypt_result = JSON.parse(sm2_decrypt_result);
// 其次,对sm2解密后的结果进行 aes解密
// aes解密需要用到 appword , 为固定值,使用示例代码中的即可
let aes_encrypt_result = sm2_decrypt_result.data;
let aes_decrypt_result = aes_Decrypt(aes_encrypt_result, appword);
// 加密
loginCallback(aes_decrypt_result);
}

View File

@@ -1,6 +1,5 @@
import useUserStore from "../stores/useUserStore";
import {
request,
createRequest,
uploadFile
} from "../utils/request";
@@ -8,6 +7,9 @@ import streamRequest, {
chatRequest
} from "../utils/streamRequest.js";
const sm4 = typeof window.sm4 !== 'undefined' ? window.sm4 :
(typeof window.smCrypto !== 'undefined' ? window.smCrypto.sm4 : null);
export const CloneDeep = (props) => {
if (typeof props !== 'object' || props === null) {
return props
@@ -563,7 +565,6 @@ function aes_Decrypt(word, key) {
return decrypt.toString(CryptoJS.enc.Utf8)
}
export function sm2_Decrypt(word, key) {
return SM.decrypt(word, key);
}
@@ -572,11 +573,51 @@ export function sm2_Encrypt(word, key) {
return SM.encrypt(word, key);
}
export function sm4Decrypt(key, value, mode = "hex") {
try {
if (key.length !== 32) {
alert('密钥必须是32位16进制字符串128位');
return;
}
const decrypted = sm4.decrypt(value, key, {
mode: 'ecb',
cipherType: mode === 'hex' ? 'hex' : 'base64',
padding: 'pkcs#5'
});
return decrypted
} catch (e) {
console.log('解密失败')
}
}
export function sm4Encrypt(key, value, mode = "hex") {
try {
if (key.length !== 32) {
alert('密钥必须是32位16进制字符串128位');
return;
}
const encrypted = sm4.encrypt(value, key, {
mode: 'ecb',
cipherType: mode === 'hex' ? 'hex' : 'base64',
padding: 'pkcs#5'
});
return encrypted
} catch (e) {
console.log('加密失败')
}
}
export const $api = {
msg,
prePage,
sleep,
request,
createRequest,
streamRequest,
chatRequest,
@@ -615,6 +656,7 @@ export default {
insertSortData,
isInWechatMiniProgramWebview,
isEmptyObject,
sm4Decrypt,
aes_Decrypt,
sm2_Decrypt,
sm2_Encrypt

View File

@@ -2,17 +2,18 @@
<view v-for="job in listData" :key="job.id">
<view class="cards" @click="nextDetail(job)">
<view class="card-company">
<text class="company line_1">{{ job.name }}</text>
<text class="company line_1">{{ job.gsmc }}</text>
</view>
<view class="card-bottom">
<view class="fl_box fs_14">
<dict-tree-Label class="mar_ri10" dictType="industry" :value="job.industry"></dict-tree-Label>
<dict-Label dictType="scale" :value="job.scale"></dict-Label>
<view class="card-bottom" >
<view class="fl_box fs_14" >
<!-- <dict-tree-Label class="mar_ri10" dictType="industry" :value="job.industry"></dict-tree-Label>
<dict-Label dictType="scale" :value="job.scale"></dict-Label> -->
<view>{{job.gsxy}}</view>
</view>
<view class="ris">
<view class="ris" >
<text class="fs_14">
在招职位·
<text class="color_256BFA">{{ job.totalRecruitment || '-' }}</text>
<text class="color_256BFA">{{ job.zzgwsl || '-' }}</text>
</text>
</view>
@@ -20,10 +21,14 @@
<view class="card-tags">
<view class="tag" v-if="job.nature">
<dict-Label dictType="nature" :value="job.nature"></dict-Label>
<dict-Label dictType="nature" :value="job.nature"></dict-Label>
</view>
<view class="tag">
{{ vacanciesTo(job.vacancies) }}
</view>
<view class="tag" v-if="job.qyxz">
{{job.qyxz}}
</view>
</view>
</view>
</view>
@@ -51,6 +56,10 @@ const props = defineProps({
type: String,
default: '',
},
zphId: {
type: String,
default: '',
},
});
const listData = computed(() => {
@@ -58,7 +67,7 @@ const listData = computed(() => {
});
function nextDetail(company) {
navTo(`/packageA/pages/UnitDetails/UnitDetails?companyId=${company.companyId}`);
navTo(`/packageA/pages/UnitDetails/UnitDetails?companyId=${company.gsID}&companyName=${company.gsmc}&zphId=${props.zphId}`);
}
</script>
@@ -119,7 +128,7 @@ function nextDetail(company) {
}
}
.card-bottom{
margin-top: 4rpx
margin-top: 15rpx
margin-bottom: 10rpx
display: flex
justify-content: space-between

View File

@@ -2,33 +2,33 @@
<view v-for="job in listData" :key="job.id">
<view v-if="!job.isTitle" class="cards" @click="nextDetail(job)">
<view class="card-company">
<text class="company">{{ job.jobTitle }}</text>
<text class="company">{{ job.gwmc }}</text>
<view class="salary">
<Salary-Expectation :max-salary="job.maxSalary" :min-salary="job.minSalary"></Salary-Expectation>
</view>
</view>
<view class="card-companyName">{{ job.companyName }}</view>
<view class="card-companyName">{{ job.gsmc }}</view>
<view class="card-tags">
<view class="tag">
<dict-Label dictType="education" :value="job.education"></dict-Label>
{{job.xlyq == '不限' ? '学历不限' : job.xlyq}}
</view>
<view class="tag">
<dict-Label dictType="experience" :value="job.experience"></dict-Label>
{{job.gwgzjy == '不限' ? '经验不限' : job.gwgzjy}}
</view>
<view class="tag">
{{ vacanciesTo(job.vacancies) }}
{{ vacanciesTo(job.zprs) }}
</view>
</view>
<view class="card-bottom">
<view>{{ job.postingDate }}</view>
<view>{{ parseDateTime(job.createTime).date }}</view>
<view>
<convert-distance
<!-- <convert-distance
:alat="job.latitude"
:along="job.longitude"
:blat="latitude"
:blong="longitude"
></convert-distance>
<dict-Label class="mar_le10" dictType="area" :value="job.jobLocationAreaCode"></dict-Label>
<dict-Label class="mar_le10" dictType="area" :value="job.jobLocationAreaCode"></dict-Label> -->
</view>
</view>
</view>
@@ -77,7 +77,25 @@ function nextDetail(job) {
const recordData = recommedIndexDb.JobParameter(job);
recommedIndexDb.addRecord(recordData);
}
navTo(`/packageA/pages/post/post?jobId=${btoa(job.jobId)}`);
navTo(`/packageA/pages/post/post?jobId=${btoa(job.id)}`);
}
function parseDateTime(datetimeStr) {
if (!datetimeStr) return { time: '', date: '' };
const dateObj = new Date(datetimeStr);
if (isNaN(dateObj.getTime())) return { time: '', date: '' }; // 无效时间
const year = dateObj.getFullYear();
const month = String(dateObj.getMonth() + 1).padStart(2, '0');
const day = String(dateObj.getDate()).padStart(2, '0');
const hours = String(dateObj.getHours()).padStart(2, '0');
const minutes = String(dateObj.getMinutes()).padStart(2, '0');
return {
time: `${hours}:${minutes}`,
date: `${year}-${month}-${day}`,
};
}
</script>

View File

@@ -19,7 +19,7 @@
</template>
<script setup>
import { ref, defineProps, onMounted, computed } from 'vue';
import { ref, onMounted, computed } from 'vue';
import { useReadMsg } from '@/stores/useReadMsg';
const props = defineProps({
currentpage: {

View File

@@ -1,8 +1,7 @@
export default {
baseUrl: 'https://fw.rc.qingdao.gov.cn/rgpp-api/api', // 内网
// baseUrl: 'https://qd.zhaopinzao8dian.com/api', // 测试
// baseUrl: "http://192.168.98.110:18181",
// baseUrl: "http://192.168.3.19:8080",
// baseUrl: 'http://192.168.3.29:8081',
// sseAI+
// StreamBaseURl: 'http://39.98.44.136:8000',
StreamBaseURl: 'https://qd.zhaopinzao8dian.com/ai',
@@ -18,14 +17,14 @@ export default {
OnlyUseCachedDB: false,
// 使用模拟定位
UsingSimulatedPositioning: true,
// 私钥
pubilcKey: '',
// 公钥
privateKey: '',
// 应用信息
appInfo: {
// 应用名称
name: "青岛市就业服务",
// 爱山东应用标识
loveShandong: 'szjxrgznqzzp',
// 爱山东应用Key
sm2PrivateKey: '0d152c849f10e4469f2af8cedea62004e4f1db7be23c2f7270c1441d8050799d',
// 地区名
areaName: '青岛市',
// AI名称
@@ -75,5 +74,11 @@ export default {
title: '找工作,用 AI 更高效|青岛市智能求职平台',
desc: '融合海量岗位、智能简历匹配、竞争力分析,助你精准锁定理想职位!',
imgUrl: 'https://qd.zhaopinzao8dian.com/file/csn/qd_shareLogo.jpg',
},
sm4Config: {
key: '86C63180C1306ABC4D8F989E0A0BC9F3',
mode: 'ECB', // default
iv: 'UISwD9fW6cFh9SNS', // default is null
cipherType: 'base64' // default is base64
}
}

View File

@@ -17,18 +17,20 @@
})();
</script>
<title></title>
<!-- vconsole -->
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
<!-- eruda -->
<script src="https://cdn.jsdelivr.net/npm/eruda"></script>
<script>
var vConsole = new window.VConsole();
vConsole.destroy();
eruda.init();
</script>
<!-- 爱山东jssdk -->
<!-- 爱山东jssdk 本sdk存在性能问题 -->
<script type="text/javascript" src="https://isdapp.shandong.gov.cn/jmopen/jssdk/index.js"></script>
<script type="text/javascript" src="./static/encryption/aes.js"></script>
<script type="text/javascript" src="./static/js/sm4.min.js"></script>
<script type="text/javascript" src="./static/js/SM.js"></script>
<script type="text/javascript" src="./static/js/aes.js"></script>
<script type="text/javascript" src="./static/encryption/SM.js"></script>
</head>
<!-- <body> -->
<div id="app"><!--app-html--></div>

View File

@@ -21,7 +21,7 @@
<image src="@/static/icon/companyIcon.png" mode=""></image>
</view>
<view class="companyinfo-right">
<view class="row1">{{ companyInfo?.name }}</view>
<view class="row1">{{ companyInfo?.gsmc }}</view>
<view class="row2">
<dict-tree-Label
v-if="companyInfo?.industry"
@@ -30,12 +30,13 @@
></dict-tree-Label>
<span v-if="companyInfo?.industry">&nbsp;</span>
<dict-Label dictType="scale" :value="companyInfo?.scale"></dict-Label>
<span>{{companyInfo.gsxy}}</span>
</view>
</view>
</view>
<view class="conetent-info" :class="{ expanded: isExpanded }">
<view class="info-title">公司介绍</view>
<view class="info-desirption">{{ companyInfo.description }}</view>
<view class="info-desirption">{{ companyInfo.qyxz }}</view>
<!-- <view class="info-title title2">公司地址</view>
<view class="locationCompany"></view> -->
</view>
@@ -47,7 +48,8 @@
src="@/static/icon/downs.png"
></image>
</view>
<scroll-view scroll-y class="Detailscroll-view" @scrolltolower="getJobsList('add')">
<!-- <scroll-view scroll-y class="Detailscroll-view" @scrolltolower="getJobsList('add')"> -->
<scroll-view scroll-y class="Detailscroll-view">
<view class="views">
<view class="Detail-title"><text class="title">在招职位</text></view>
<renderJobs
@@ -85,32 +87,32 @@ const companyInfo = ref({});
onLoad((options) => {
console.log(options);
getCompanyInfo(options.companyId || options.bussinessId);
getCompanyInfo(options.companyId,options.companyName,options.zphId);
});
function companyCollection() {
const companyId = companyInfo.value.companyId;
const companyId = companyInfo.value.gsID;
if (companyInfo.value.isCollection) {
$api.createRequest(`/app/company/collection/${companyId}`, {}, 'DELETE').then((resData) => {
getCompanyInfo(companyId);
// getCompanyInfo(companyId);
$api.msg('取消收藏成功');
});
} else {
$api.createRequest(`/app/company/collection/${companyId}`, {}, 'POST').then((resData) => {
getCompanyInfo(companyId);
// getCompanyInfo(companyId);
$api.msg('收藏成功');
});
}
}
function getCompanyInfo(id) {
$api.createRequest(`/app/company/${id}`).then((resData) => {
function getCompanyInfo(companyId,companyName,zphId) {
$api.createRequest(`/app/internal/companyThirdPart/${companyId}`).then((resData) => {
companyInfo.value = resData.data;
getJobsList();
getJobsList(companyId,companyName,zphId);
});
}
function getJobsList(type = 'add') {
function getJobsList(companyId,companyName,zphId,type='add') {
if (type === 'refresh') {
pageState.page = 1;
pageState.maxPage = 1;
@@ -122,13 +124,14 @@ function getJobsList(type = 'add') {
current: pageState.page,
pageSize: pageState.pageSize,
};
$api.createRequest(`/app/company/job/${companyInfo.value.companyId}`, params).then((resData) => {
$api.createRequest(`/app/internal/jobThirdPart?gsID=${companyId}&gsmc=${companyName}&zphID=${zphId}`, ).then((resData) => {
const { rows, total } = resData;
if (type === 'add') {
const str = pageState.pageSize * (pageState.page - 1);
const end = pageState.list.length;
const reslist = rows;
pageState.list.splice(str, end, ...reslist);
// const str = pageState.pageSize * (pageState.page - 1);
// const end = pageState.list.length;
// const reslist = rows;
// pageState.list.splice(str, end, ...reslist);
pageState.list = rows
} else {
pageState.list = rows;
}

View File

@@ -11,15 +11,15 @@
<image src="@/static/icon/companyIcon.png" mode=""></image>
</view>
<view class="companyinfo-right">
<view class="row1 line_2">{{ fairInfo?.name }}</view>
<view class="row1 line_2">{{ fairInfo?.zphmc }}</view>
<view class="row2">
<text>{{ fairInfo.location }}</text>
<convert-distance
<text>{{ fairInfo.jbf }}</text>
<!-- <convert-distance
:alat="fairInfo.latitude"
:along="fairInfo.longitude"
:blat="latitudeVal"
:blong="longitudeVal"
></convert-distance>
></convert-distance> -->
</view>
</view>
</view>
@@ -27,36 +27,36 @@
<image class="location-img" src="/static/icon/mapLine.png"></image>
<view class="location-info">
<view class="info">
<text class="info-title">{{ fairInfo.address }}</text>
<text class="info-text">位置</text>
<text class="info-title">{{ fairInfo.zphdz }}</text>
<!-- <text class="info-text">位置</text> -->
</view>
</view>
</view>
<view class="conetent-info" :class="{ expanded: isExpanded }">
<view class="info-title">内容描述</view>
<view class="info-desirption">{{ fairInfo.description }}</view>
<view class="info-desirption">{{ fairInfo.zphjj }}</view>
<!-- <view class="info-title title2">公司地址</view>
<view class="locationCompany"></view> -->
<view class="company-times">
<view class="info-title">内容描述</view>
<view class="card-times">
<view class="time-left">
<view class="left-date">{{ parseDateTime(fairInfo.startTime).time }}</view>
<view class="left-dateDay">{{ parseDateTime(fairInfo.startTime).date }}</view>
<view class="left-date">{{ parseDateTime(fairInfo.zphjbsj).time }}</view>
<view class="left-dateDay">{{ parseDateTime(fairInfo.zphjbsj).date }}</view>
</view>
<view class="line"></view>
<view class="time-center">
<view class="center-date">
{{ getTimeStatus(fairInfo.startTime, fairInfo.endTime).statusText }}
{{ getTimeStatus(fairInfo.zphjbsj, fairInfo.zphjzsj).statusText }}
</view>
<view class="center-dateDay">
{{ getHoursBetween(fairInfo.startTime, fairInfo.endTime) }}小时
{{ getHoursBetween(fairInfo.zphjbsj, fairInfo.zphjzsj) }}小时
</view>
</view>
<view class="line"></view>
<view class="time-right">
<view class="left-date">{{ parseDateTime(fairInfo.endTime).time }}</view>
<view class="left-dateDay">{{ parseDateTime(fairInfo.endTime).date }}</view>
<view class="left-date">{{ parseDateTime(fairInfo.zphjzsj).time }}</view>
<view class="left-dateDay">{{ parseDateTime(fairInfo.zphjzsj).date }}</view>
</view>
</view>
</view>
@@ -76,6 +76,7 @@
</view>
<renderCompanys
v-if="companyList.length"
:zphId="zphId"
:list="companyList"
:longitude="longitudeVal"
:latitude="latitudeVal"
@@ -112,17 +113,24 @@ const isExpanded = ref(false);
const fairInfo = ref({});
const companyList = ref([]);
const hasnext = ref(true);
const zphId = ref('');
onLoad((options) => {
getCompanyInfo(options.jobFairId);
zphId.value = options.jobFairId
getJobFairInfo(options.jobFairId, options.jobFairName);
getCompanyInfo(options.jobFairId, options.jobFairName);
});
function getCompanyInfo(id) {
$api.createRequest(`/app/fair/${id}`).then((resData) => {
function getJobFairInfo(id,name) {
$api.createRequest(`/app/internal/jobFairThirdPart/${id}`).then((resData) => {
fairInfo.value = resData.data;
companyList.value = resData.data.companyList;
hasAppointment();
});
}
function getCompanyInfo(id,name) {
$api.createRequest(`/app/internal/companyThirdPart/?zphID=${id}&zphmc=${name}`).then((resData) => {
companyList.value = resData.rows;
});
}
const hasAppointment = () => {
const isTimePassed = (timeStr) => {

View File

@@ -7,31 +7,56 @@
</template>
<view class="mys-container">
<!-- 个人信息 -->
<view class="card-top" style="margin-top: 12rpx; padding: 0; background: none">
<view
class="card-top"
style="margin-top: 12rpx; padding: 0; background: none"
>
<view class="mys-tops btn-feel">
<view class="tops-left">
<view class="name">
<text>{{ userInfo.name || "编辑用户名" }}</text>
<view class="edit-icon mar_le10">
<image class="button-click" src="@/static/icon/edit1.png" @click="navTo('/packageA/pages/personalInfo/personalInfo')"></image>
<image
class="button-click"
src="@/static/icon/edit1.png"
@click="navTo('/packageA/pages/personalInfo/personalInfo')"
></image>
</view>
</view>
<view class="subName">
<dict-Label class="mar_ri10" dictType="sex" :value="userInfo.sex"></dict-Label>
<dict-Label
class="mar_ri10"
dictType="sex"
:value="userInfo.sex"
></dict-Label>
<text class="mar_ri10">{{ userInfo.age }}</text>
<dict-Label class="mar_ri10" dictType="education" :value="userInfo.education"></dict-Label>
<dict-Label class="mar_ri10" dictType="affiliation" :value="userInfo.politicalAffiliation"></dict-Label>
<dict-Label
class="mar_ri10"
dictType="education"
:value="userInfo.education"
></dict-Label>
<dict-Label
class="mar_ri10"
dictType="affiliation"
:value="userInfo.politicalAffiliation"
></dict-Label>
</view>
<view class="subName">{{ userInfo.phone }}</view>
</view>
<view class="tops-right">
<view class="right-imghead">
<image v-if="userInfo.avatar" :src="userInfo.avatar"></image>
<image v-else-if="userInfo.sex == '0'" src="@/static/icon/boy.png"></image>
<image
v-else-if="userInfo.sex == '0'"
src="@/static/icon/boy.png"
></image>
<image v-else src="@/static/icon/girl.png"></image>
</view>
<view class="right-sex">
<image v-if="userInfo.sex === '0'" src="@/static/icon/boy1.png"></image>
<image
v-if="userInfo.sex === '0'"
src="@/static/icon/boy1.png"
></image>
<image v-else src="@/static/icon/girl1.png"></image>
</view>
</view>
@@ -43,19 +68,34 @@
<view class="mys-info btn-feel">
<view class="mys-h4">
<view>求职期望</view>
<image class="icon" src="@/static/icon/edit1.png" @click="navTo('/packageA/pages/jobExpect/jobExpect')"></image>
<image
class="icon"
src="@/static/icon/edit1.png"
@click="navTo('/packageA/pages/jobExpect/jobExpect')"
></image>
</view>
<view class="mys-text">
<text>期望薪资</text>
<text>{{ userInfo.salaryMin / 1000 }}k-{{ userInfo.salaryMax / 1000 }}k</text>
<text
>{{ userInfo.salaryMin / 1000 }}k-{{
userInfo.salaryMax / 1000
}}k</text
>
</view>
<view class="mys-text">
<text>期望工作地</text>
<text>青岛市-</text>
<dict-Label dictType="area" :value="Number(userInfo.area)"></dict-Label>
<dict-Label
dictType="area"
:value="Number(userInfo.area)"
></dict-Label>
</view>
<view class="mys-list">
<view class="cards button-click" v-for="(title, index) in userInfo.jobTitle" :key="index">
<view
class="cards button-click"
v-for="(title, index) in userInfo.jobTitle"
:key="index"
>
{{ title }}
</view>
</view>
@@ -65,19 +105,35 @@
<view class="mys-info" style="padding: 0">
<view class="mys-h4 btn-feel">
<text>工作经历</text>
<view class="mys-edit-icon btn-feel" @click="navTo('/packageA/pages/workExp/workExp')">
<image class="icon button-click btn-feel" src="@/static/icon/plus.png"></image>
<view
class="mys-edit-icon btn-feel"
@click="navTo('/packageA/pages/workExp/workExp')"
>
<image
class="icon button-click btn-feel"
src="@/static/icon/plus.png"
></image>
<view class="txt">添加</view>
</view>
</view>
<view class="exp-item btn-feel" v-for="item in userInfo.workExp" :key="item.id">
<view
class="exp-item btn-feel"
v-for="item in userInfo.workExp"
:key="item.id"
>
<view class="fl_box fl_justbet mar_top15">
<view class="fs_16">{{ item.company }}</view>
<image class="icon btn-feel" src="@/static/icon/edit1.png" @click="navTo(`/packageA/pages/workExp/workExp?id=${item.id}`)"></image>
<image
class="icon btn-feel"
src="@/static/icon/edit1.png"
@click="navTo(`/packageA/pages/workExp/workExp?id=${item.id}`)"
></image>
</view>
<view class="mys-text fl_box fl_justbet">
<text class="color_333333 fs_14">{{ item.position }}</text>
<text class="datetext">{{ item.startTime }}--{{ item.endTime || "至今" }}</text>
<text class="datetext"
>{{ item.startTime }}--{{ item.endTime || "至今" }}</text
>
</view>
<view class="mys-text">
<text>{{ item.duty }}</text>
@@ -88,7 +144,9 @@
</view>
<template #footer>
<view class="footer-container">
<view class="footer-button btn-feel">上传简历</view>
<view class="footer-button btn-feel" @click="chooseResume"
>上传简历</view
>
</view>
</template>
</AppLayout>
@@ -104,6 +162,69 @@ import useDictStore from "@/stores/useDictStore";
const { userInfo } = storeToRefs(useUserStore());
const { getUserResume } = useUserStore();
const { getDictData, oneDictData } = useDictStore();
import config from "@/config.js";
onLoad(() => {
getUserResume();
});
function chooseResume() {
uni.chooseImage({
sizeType: ["original", "compressed"],
sourceType: ["album", "camera"],
count: 1,
success: ({ tempFilePaths, tempFiles }) => {
uploadResume(tempFilePaths[0], true)
.then((res) => {
res = JSON.parse(res);
getUserResume();
$api.msg("上传成功");
})
.catch((err) => {
$api.msg("上传失败");
});
},
fail: (error) => {},
});
}
function uploadResume(tempFilePath, loading) {
if (loading) {
uni.showLoading({
title: "请稍后",
mask: true,
});
}
let Authorization = "";
if (useUserStore().token) {
Authorization = `${useUserStore().token}`;
}
const header = {};
header["Authorization"] = encodeURIComponent(Authorization);
return new Promise((resolve, reject) => {
uni.uploadFile({
url: config.baseUrl + "/app/oss/uploadToObs",
filePath: tempFilePath,
name: "file",
header,
success: (uploadFileRes) => {
if (uploadFileRes.statusCode === 200) {
resolve(uploadFileRes.data);
} else {
reject();
}
},
fail: (err) => {
reject(err);
},
complete: () => {
if (loading) {
uni.hideLoading();
}
},
});
});
}
</script>
<style lang="stylus" scoped>

View File

@@ -28,9 +28,12 @@ watch(
() => props.value,
(newVal) => {
if (newVal && Object.keys(newVal).length > 0) {
const { skill, experience, education, salary, age, location } = newVal.radarChart;
const labels = ['学历', '年龄', '工作地', '技能', '工作经验', '期望薪资'];
const data = [education, age, location, skill, experience, salary].map((item) => item * 0.05);
// const { skill, experience, education, salary, age, location } = newVal.radarChart;
const { experience, education, salary, age, location } = newVal.radarChart;
// const labels = ['学历', '年龄', '工作地', '技能', '工作经验', '期望薪资'];
const labels = ['学历', '年龄', '工作地', '工作经验', '期望薪资'];
// const data = [education, age, location, skill, experience, salary].map((item) => item * 0.05);
const data = [education, age, location, experience, salary].map((item) => item * 0.05);
rawRadarChart(labels, data);
}
},
@@ -43,10 +46,8 @@ function rawRadarChart(labels, data) {
const height = 80;
const centerX = 150;
const centerY = 125;
// const data = [2, 3.5, 5, 3.5, 5, 3.5]; // 示例数据
// const labels = ['火烧', '泡水', '事故', '外观', '部件', '火烧'];
const colors = ['#F5F5F5', '#F5F5F5', '#F5F5F5', '#F5F5F5', '#F5F5F5'];
const maxScore = 5; // 数据最大值
const maxScore = 5;
const angleStep = (2 * Math.PI) / labels.length;
@@ -62,9 +63,8 @@ function rawRadarChart(labels, data) {
ctx.fill();
//多边形圈
// 多边形圈
for (let i = 5; i > 0; i--) {
ctx.setStrokeStyle(colors[i - 1]); // 设置边框颜色
ctx.setStrokeStyle(colors[i - 1]);
ctx.beginPath();
labels.forEach((label, index) => {
const x = centerX + (width / 5) * i * Math.cos(angleStep * index - Math.PI / 2);
@@ -76,19 +76,20 @@ function rawRadarChart(labels, data) {
}
});
ctx.closePath();
ctx.stroke(); // 只描边,不填充
ctx.stroke();
}
// //竖线
//竖线
labels.forEach((label, index) => {
ctx.setStrokeStyle('#F5F5F5');
ctx.setFillStyle('#F5F5F5');
ctx.beginPath();
const x1 = centerX + width * 0.6 * Math.sin(angleStep * index);
const y1 = centerY + height * 0.6 * Math.cos(angleStep * index);
const x = centerX + width * Math.sin(angleStep * index);
const y = centerY + height * Math.cos(angleStep * index);
// 修改坐标计算,使用与多边形圈相同的角度计算方式
const x1 = centerX + width * 0.6 * Math.cos(angleStep * index - Math.PI / 2);
const y1 = centerY + height * 0.6 * Math.sin(angleStep * index - Math.PI / 2);
const x = centerX + width * Math.cos(angleStep * index - Math.PI / 2);
const y = centerY + height * Math.sin(angleStep * index - Math.PI / 2);
ctx.moveTo(x1, y1);
ctx.lineTo(x, y);
@@ -102,11 +103,11 @@ function rawRadarChart(labels, data) {
ctx.setFillStyle('rgba(37,107,250, 0.24)');
ctx.setLineWidth(2);
ctx.beginPath();
const pointList = []; // 记录每个点的位置,等会画小圆点
const pointList = [];
data.forEach((score, index) => {
const x = centerX + width * (score / maxScore) * Math.cos(angleStep * index - Math.PI / 2);
const y = centerY + height * (score / maxScore) * Math.sin(angleStep * index - Math.PI / 2);
pointList.push({ x, y }); // 保存位置
pointList.push({ x, y });
if (index === 0) {
ctx.moveTo(x, y);
} else {
@@ -118,15 +119,16 @@ function rawRadarChart(labels, data) {
ctx.stroke();
// 绘制每个小圆点
ctx.setFillStyle('#256BFA'); // 小圆点颜色(你可以改)
ctx.setFillStyle('#256BFA');
pointList.forEach((point) => {
ctx.beginPath();
ctx.arc(point.x, point.y, 4, 0, 2 * Math.PI); // 半径 4可以自己调大小
ctx.arc(point.x, point.y, 4, 0, 2 * Math.PI);
ctx.fill();
});
// 绘制标签
ctx.setTextAlign('center');
ctx.setTextBaseline('middle');
labels.forEach((label, index) => {
const x = centerX + (width + 30) * Math.cos(angleStep * index - Math.PI / 2);
@@ -137,30 +139,9 @@ function rawRadarChart(labels, data) {
ctx.setFontSize(12);
ctx.font = 'bold 12px sans-serif';
ctx.fillText(label, x, y);
// ctx.setFillStyle('#A2A4A2');
// ctx.font = '12px sans-serif';
// ctx.setFontSize(12);
// ctx.fillText(data[index], x, y + 16);
});
ctx.draw();
//转图片
// uni.canvasToTempFilePath({
// x: 0,
// y: 0,
// width: 320,
// height: 320,
// destWidth: 840,
// destHeight: 840,
// canvasId: 'radarCanvas',
// success: (res) => {
// // 在H5平台下tempFilePath 为 base64
// src = res.tempFilePath;
// },
// });
}
</script>

View File

@@ -23,20 +23,26 @@
:is-month="true"
></Salary-Expectation>
</view>
<view class="top-name">{{ jobInfo.jobTitle }}</view>
<view class="top-name">{{ jobInfo.gwmc }}</view>
<view class="top-info">
<view class="info-img"><image src="/static/icon/post12.png"></image></view>
<view class="info-text">
<!-- <view class="info-text">
<dict-Label dictType="experience" :value="jobInfo.experience"></dict-Label>
</view> -->
<view class="info-text">
{{jobInfo.xlyq == '不限' ? '学历不限' : jobInfo.xlyq}}
</view>
<view class="info-img mar_le20"><image src="/static/icon/post13.png"></image></view>
<view class="info-text">
<!-- <view class="info-text">
<dict-Label dictType="education" :value="jobInfo.education"></dict-Label>
</view> -->
<view class="info-text">
{{jobInfo.gwgzjy == '不限' ? '经验不限' : jobInfo.gwgzjy}}
</view>
</view>
<view class="position-source">
<text>来源&nbsp;</text>
{{ jobInfo.dataSource }}
青岛人才网
</view>
</view>
<view class="ai-explain" v-if="jobInfo.isExplain">
@@ -53,7 +59,7 @@
<text class="title">职位描述</text>
</view>
<view class="description" :style="{ whiteSpace: 'pre-wrap' }">
{{ jobInfo.description }}
{{ jobInfo.gwms }}
</view>
</view>
<view class="content-card">
@@ -61,7 +67,7 @@
<text class="title">公司信息</text>
<text
class="btntext button-click"
@click="navTo(`/packageA/pages/UnitDetails/UnitDetails?companyId=${jobInfo.company.companyId}`)"
@click=" navTo(`/packageA/pages/UnitDetails/UnitDetails?companyId=${jobInfo.gsID}&companyName=${jobInfo.gsmc}&zphId=${jobInfo.zphID}`);"
>
单位详情
</text>
@@ -71,7 +77,7 @@
<image src="@/static/icon/companyIcon.png" mode=""></image>
</view>
<view class="companyinfo-right">
<view class="row1">{{ jobInfo.company?.name }}</view>
<view class="row1">{{ jobInfo.gsmc }}</view>
<view class="row2">
<dict-tree-Label
v-if="jobInfo.company?.industry"
@@ -80,6 +86,7 @@
></dict-tree-Label>
<span v-if="jobInfo.company?.industry">&nbsp;</span>
<dict-Label dictType="scale" :value="jobInfo.company?.scale"></dict-Label>
<span>{{jobInfo.qyxz}}</span>
</view>
<view class="row2">
<text>在招</text>
@@ -102,9 +109,9 @@
<text class="title">竞争力分析</text>
</view>
<view class="description">
三个月内共15位求职者申请你的简历匹配度为{{ raderData.matchScore }}排名位于第{{
raderData.rank
}}超过{{ raderData.percentile }}%的竞争者处在优秀位置
三个月内共{{ raderData.totalApplicants }}位求职者申请你的简历匹配度为{{
raderData.matchScore
}}排名位于第{{ raderData.rank }}超过{{ raderData.percentile }}%的竞争者处在优秀位置
</view>
<RadarMap :value="raderData"></RadarMap>
@@ -187,12 +194,13 @@ function seeExplain() {
function getDetail(jobId) {
return new Promise((reslove, reject) => {
$api.createRequest(`/app/job/${jobId}`).then((resData) => {
const { latitude, longitude, companyName, companyId } = resData.data;
$api.createRequest(`/app/internal/jobThirdPart/${jobId}`).then((resData) => {
const { gsID, gsmc, zphID} = resData.data;
jobInfo.value = resData.data;
reslove(resData.data);
getCompanyIsAJobs(companyId);
getCompetivetuveness(jobId);
getCompanyIsAJobs(gsID, gsmc, zphID);
// getCompetivetuveness(jobId);
return
if (latitude && longitude) {
mapCovers.value = [
{
@@ -216,9 +224,9 @@ function getDetail(jobId) {
});
}
function getCompanyIsAJobs(companyId) {
$api.createRequest(`/app/company/count/${companyId}`).then((resData) => {
companyCount.value = resData.data;
function getCompanyIsAJobs(gsID, gsmc, zphID) {
$api.createRequest(`/app/internal/jobThirdPart?gsID=${gsID}&gsmc=${gsmc}&zphID=${zphID}`).then((resData) => {
companyCount.value = resData.total;
});
}
@@ -238,7 +246,7 @@ function getCompetivetuveness(jobId) {
// 申请岗位
function jobApply() {
const jobId = jobInfo.value.jobId;
const jobId = jobInfo.value.id;
if (jobInfo.value.isApply) {
const jobUrl = jobInfo.value.jobUrl;
return window.open(jobUrl);

View File

@@ -32,22 +32,23 @@
</view>
</view>
<view class="info-bottom">
<view>到岗2025-11-02</view>
<!-- <view>到岗2025-11-02</view> -->
<view></view>
<view>地点青岛市-<dict-Label dictType="area" :value="Number(userInfo.area)"></dict-Label></view>
</view>
<view class="des-card" style="margin-top: 24rpx">
<view class="fl_box fl_justbet">
<view>求职意向岗位</view>
<view>{{ userInfo.jobIntention || "-" }}</view>
<view style="white-space:nowrap">求职意向岗位</view>
<view class="line_1" style="padding-left:40rpx" >{{ userInfo.jobIntention || userInfo.jobTitle?.join(',') || '-' }}</view>
</view>
<view class="fl_box fl_justbet">
<view>毕业学校</view>
<view>{{ userInfo.graduationSchool || "-" }}</view>
</view>
<view class="fl_box fl_justbet">
<!-- <view class="fl_box fl_justbet">
<view>当前状态</view>
<view>在职 看工作机会</view>
</view>
</view> -->
</view>
</view>

View File

@@ -68,11 +68,9 @@
}
}
],
"subpackages": [
{
"subpackages": [{
"root": "packageA",
"pages": [
{
"pages": [{
"path": "pages/choiceness/choiceness",
"style": {
"navigationBarTitleText": "精选",
@@ -227,8 +225,7 @@
}
}
]
}
],
}],
"tabBar": {
"custom": true,
"display": "none",
@@ -241,8 +238,7 @@
"height": "50px",
"backgroundImage": "static/tabbar/logo2copy.png"
},
"list": [
{
"list": [{
"pagePath": "pages/index/index",
"iconPath": "static/tabbar/calendar.png",
"selectedIconPath": "static/tabbar/calendared.png",

View File

@@ -0,0 +1,545 @@
<template>
<view class="app-custom-root">
<view class="app-container">
<!-- 顶部头部区域 -->
<view class="container-header">
<view class="header-top">
<view class="header-btnLf button-click" @click="seemsg(0)" :class="{ active: state.current === 0 }">
现场招聘
</view>
<view class="header-btnLf button-click" @click="seemsg(1)" :class="{ active: state.current === 1 }">
VR虚拟招聘会
</view>
</view>
<view class="header-input btn-feel">
<uni-icons class="iconsearch" color="#666666" type="search" size="18"></uni-icons>
<input class="input" placeholder="招聘会" placeholder-class="inputplace" />
</view>
<view class="header-date">
<view class="data-week">
<view
class="weel-days button-click"
:class="{ active: currentDay.fullDate === item.fullDate }"
v-for="(item, index) in weekList"
:key="index"
@click="selectDate(item)"
>
<view class="label">{{ item.day }}</view>
<view class="day">{{ item.date }}</view>
</view>
</view>
<view class="data-all">
<image class="allimg button-click" @click="toSelectDate" src="/static/icon/date1.png"></image>
</view>
</view>
</view>
<!-- 主体内容区域 -->
<view class="container-main">
<scroll-view scroll-y class="main-scroll" @scrolltolower="handleScrollToLower">
<view class="cards" v-if="fairList.length">
<view
class="card press-button"
v-for="(item, index) in fairList"
:key="index"
@click="navTo('/packageA/pages/exhibitors/exhibitors?jobFairId=' + item.jobFairId)"
>
<view class="card-title">{{ item.zphmc }}</view>
<view class="card-row">
<text class="">{{ item.zphdz }}</text>
<text class="">
<convert-distance
:alat="item.latitude"
:along="item.longitude"
:blat="latitudeVal"
:blong="longitudeVal"
></convert-distance>
</text>
</view>
<view class="card-times">
<view class="time-left">
<view class="left-date">{{ parseDateTime(item.zphjbsj).time }}</view>
<view class="left-dateDay">{{ parseDateTime(item.zphjbsj).date }}</view>
</view>
<view class="line"></view>
<view class="time-center">
<view class="center-date">
{{ getTimeStatus(item.zphjbsj, item.zphjzsj).statusText }}
</view>
<view class="center-dateDay">
{{ getHoursBetween(item.zphjbsj, item.zphjzsj) }}小时
</view>
</view>
<view class="line"></view>
<view class="time-right">
<view class="left-date">{{ parseDateTime(item.zphjzsj).time }}</view>
<view class="left-dateDay">{{ parseDateTime(item.zphjzsj).date }}</view>
</view>
</view>
<view class="recommend-card-line"></view>
<view class="card-footer">内容简介{{ item.zphjj }}</view>
</view>
</view>
<empty v-else pdTop="200"></empty>
</scroll-view>
</view>
<Tabbar :currentpage="1"></Tabbar>
</view>
</view>
</template>
<script setup>
import { reactive, inject, watch, ref, onMounted } from 'vue';
import { onLoad, onShow } from '@dcloudio/uni-app';
import Tabbar from '@/components/tabbar/midell-box.vue';
import useLocationStore from '@/stores/useLocationStore';
import { storeToRefs } from 'pinia';
const { longitudeVal, latitudeVal } = storeToRefs(useLocationStore());
const { $api, navTo, cloneDeep } = inject('globalFunction');
const weekList = ref([]);
const fairList = ref([]);
const currentDay = ref({});
const state = reactive({
current: 0,
all: [{}],
});
const pageState = reactive({
page: 0,
total: 0,
maxPage: 2,
pageSize: 10,
search: {},
});
onLoad(() => {
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const day = String(today.getDate()).padStart(2, '0');
const currentDate = `${year}-${month}-${day}`;
const result = getNextDates({
startDate: currentDate,
});
weekList.value = result;
currentDay.value.fullDate = result[0].fullDate
getFair('refresh');
});
function toSelectDate() {
navTo('/packageA/pages/selectDate/selectDate', {
query: {
date: currentDay.value.fullDate,
},
onBack: (res) => {
console.log(res);
const result = getNextDates({
startDate: res.date,
});
const formattedDate = res.date.slice(5); // MM-DD
const dateFull = {
date: res.date.slice(5),
day: '周' + res.week,
fullDate: res.date,
};
currentDay.value = dateFull;
weekList.value = result;
getFair('refresh');
},
});
}
// 查看消息类型
function changeSwiperMsgType(e) {
const currented = e.detail.current;
state.current = currented;
}
function seemsg(index) {
if (index === 1) {
return $api.msg('功能确定中');
}
state.current = index;
}
const handleScrollToLower = () => {
return
getFair();
console.log('触底');
};
function getFair(type = 'add') {
if (type === 'refresh') {
pageState.page = 1;
pageState.maxPage = 1;
}
if (type === 'add' && pageState.page < pageState.maxPage) {
pageState.page += 1;
}
let params = {
...pageState.search,
// current: pageState.page,
// pageSize: pageState.pageSize,
};
// if (currentDay.value?.fullDate) {
// params.queryDate = currentDay.value.fullDate;
// }
if (currentDay.value?.fullDate) {
params.zphjbsj = currentDay.value.fullDate.replace(/-/g, '');
}
$api.createRequest('/app/internal/jobFairThirdPart', params).then((resData) => {
const { rows, total } = resData;
if (type === 'add') {
// const str = pageState.pageSize * (pageState.page - 1);
// const end = fairList.value.length;
// const reslist = rows;
// fairList.value.splice(str, end, ...reslist);
fairList.value = rows
} else {
fairList.value = rows;
}
// pageState.list = resData.rows;
pageState.total = resData.total;
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
});
}
function parseDateTime(datetimeStr) {
if (!datetimeStr) return { time: '', date: '' };
const dateObj = new Date(datetimeStr);
if (isNaN(dateObj.getTime())) return { time: '', date: '' }; // 无效时间
const year = dateObj.getFullYear();
const month = String(dateObj.getMonth() + 1).padStart(2, '0');
const day = String(dateObj.getDate()).padStart(2, '0');
const hours = String(dateObj.getHours()).padStart(2, '0');
const minutes = String(dateObj.getMinutes()).padStart(2, '0');
return {
time: `${hours}:${minutes}`,
date: `${year}${month}${day}`,
};
}
function getTimeStatus(startTimeStr, endTimeStr) {
const now = new Date();
const startTime = new Date(startTimeStr);
const endTime = new Date(endTimeStr);
// 判断状态0 开始中1 过期2 待开始
let status = 0;
let statusText = '开始中';
if (now < startTime) {
status = 2; // 待开始
statusText = '待开始';
} else if (now > endTime) {
status = 1; // 已过期
statusText = '已过期';
} else {
status = 0; // 进行中
statusText = '进行中';
}
return {
status, // 0: 进行中1: 已过期2: 待开始
statusText,
};
}
function getHoursBetween(startTimeStr, endTimeStr) {
const start = new Date(startTimeStr);
const end = new Date(endTimeStr);
const diffMs = end - start;
const diffHours = diffMs / (1000 * 60 * 60);
return +diffHours.toFixed(2); // 保留 2 位小数
}
const selectDate = (item) => {
if (currentDay.value?.fullDate === item.fullDate) {
currentDay.value = {};
getFair('refresh');
return;
}
currentDay.value = item;
getFair('refresh');
};
function getNextDates({ startDate = '', count = 6 }) {
const baseDate = startDate ? new Date(startDate) : new Date(); // 指定起点或今天
const dates = [];
const dayNames = ['日', '一', '二', '三', '四', '五', '六'];
for (let i = 0; i < count; i++) {
const date = new Date(baseDate);
date.setDate(baseDate.getDate() + i);
const fullDate = date.toISOString().slice(0, 10); // YYYY-MM-DD
const formattedDate = fullDate.slice(5); // MM-DD
const dayOfWeek = dayNames[date.getDay()];
dates.push({
date: formattedDate,
fullDate,
day: '周' + dayOfWeek,
});
}
// 可选设置默认选中项
// currentDay.value = dates[0];
return dates;
}
</script>
<style lang="stylus" scoped>
.app-custom-root {
position: fixed;
z-index: 10;
width: 100vw;
height: calc(100% - var(--window-bottom));
overflow: hidden;
}
.app-container {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
.container-header {
background: url('@/static/icon/background2.png') 0 0 no-repeat;
background-size: 100% 400rpx;
.header-top{
display: flex;
line-height: calc(88rpx - 14rpx);
padding: 16rpx 44rpx 14rpx 44rpx;
.header-btnLf {
display: flex;
width: fit-content;
white-space: nowrap
justify-content: flex-start;
align-items: center;
width: calc(60rpx * 3);
font-weight: 500;
font-size: 40rpx;
color: #696969;
margin-right: 44rpx;
position: relative;
.btns-wd{
position: absolute
top: 2rpx;
right: 2rpx
width: 16rpx;
height: 16rpx;
background: #F73636;
border-radius: 50%;
border: 4rpx solid #EEEEFF;
}
}
.active {
font-weight: 600;
font-size: 40rpx;
color: #000000;
}
}
.header-input{
padding: 0 24rpx
width: calc(100% - 48rpx);
position: relative
.iconsearch{
position: absolute
left: 50rpx;
top: 50%
transform: translate(0, -50%)
}
.input{
padding: 0 30rpx 0 80rpx
height: 80rpx;
background: #FFFFFF;
border-radius: 75rpx 75rpx 75rpx 75rpx;
font-size: 28rpx;
}
.inputplace{
font-weight: 400;
font-size: 28rpx;
color: #B5B5B5;
}
}
.header-date{
padding: 28rpx
display: flex
justify-content: space-between
align-items: center
.data-week{
flex: 1
display: flex
justify-content: space-between
flex-wrap: nowrap
overflow: hidden
.weel-days{
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
display: flex
justify-content: center
flex-direction: column
text-align: center
font-weight: 400;
font-size: 24rpx;
color: #333333;
width: 96rpx;
height: 88rpx;
.label{}
.day{
font-weight: 500;
}
}
.active{
background: rgba(37,107,250,0.1);
border-radius: 12rpx 12rpx 12rpx 12rpx;
color: #256BFA;
}
}
.data-all{
width: 66rpx;
height: 66rpx;
margin-left: 18rpx
.allimg{
width: 100%;
height: 100%
}
}
}
}
}
.container-main {
flex: 1;
overflow: hidden;
background-color: #f4f4f4;
}
.main-scroll {
width: 100%
height: 100%;
}
.cards{
padding: 28rpx 28rpx 28rpx 28rpx;
.card{
margin-top: 28rpx
padding: 32rpx;
background: #FFFFFF
background: #FFFFFF;
box-shadow: 0rpx 0rpx 8rpx 0rpx rgba(0,0,0,0.04);
border-radius: 20rpx 20rpx 20rpx 20rpx;
.card-title{
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
font-weight: 500;
font-size: 32rpx;
color: #333333;
}
.card-row{
display: flex
justify-content: space-between
font-weight: 400;
font-size: 28rpx;
color: #495265;
margin-top: 4rpx
}
.card-times{
display: flex;
justify-content: space-between
align-items: center
margin-top: 24rpx
.time-left,
.time-right{
text-align: center
.left-date{
font-weight: 500;
font-size: 48rpx;
color: #333333;
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
}
.left-dateDay{
font-weight: 400;
font-size: 24rpx;
color: #333333;
margin-top: 12rpx
}
}
.line{
width: 40rpx;
height: 0rpx;
border: 2rpx solid #D4D4D4;
margin-top: 64rpx
}
.time-center{
text-align: center;
display: flex
flex-direction: column
justify-content: center
align-items: center
.center-date{
font-weight: 400;
font-size: 28rpx;
color: #FF881A;
padding-top: 10rpx
}
.center-dateDay{
font-weight: 400;
font-size: 24rpx;
color: #333333;
margin-top: 6rpx
line-height: 48rpx;
width: 104rpx;
height: 48rpx;
background: #F9F9F9;
border-radius: 8rpx 8rpx 8rpx 8rpx;
}
}
}
.recommend-card-line{
width: calc(100%);
height: 0rpx;
border-radius: 0rpx 0rpx 0rpx 0rpx;
border: 2rpx dashed rgba(0,0,0,0.14);
margin-top: 32rpx
position: relative
}
.recommend-card-line::before{
position: absolute
content: ''
left: 0
top: 0
transform: translate(-50% - 110rpx, -50%)
width: 28rpx;
height: 28rpx;
background: #F4F4F4;
border-radius: 50%;
}
.recommend-card-line::after{
position: absolute
content: ''
right: 0
top: 0
transform: translate(50% + 100rpx, -50%)
width: 28rpx;
height: 28rpx;
background: #F4F4F4;
border-radius: 50%;
}
.card-footer{
margin-top: 32rpx
min-height: 50rpx;
font-weight: 400;
font-size: 28rpx;
color: #6C7282;
}
}
.card:first-child{
margin-top: 0
}
}
</style>

View File

@@ -13,7 +13,7 @@
</view>
<view class="header-input btn-feel">
<uni-icons class="iconsearch" color="#666666" type="search" size="18"></uni-icons>
<input class="input" placeholder="招聘会" placeholder-class="inputplace" />
<input v-model="pageState.zphmc" confirm-type="search" @confirm="getFair" class="input" placeholder="招聘会" placeholder-class="inputplace" />
</view>
<view class="header-date">
<view class="data-week">
@@ -42,42 +42,42 @@
class="card press-button"
v-for="(item, index) in fairList"
:key="index"
@click="navTo('/packageA/pages/exhibitors/exhibitors?jobFairId=' + item.jobFairId)"
@click="navTo('/packageA/pages/exhibitors/exhibitors?jobFairId=' + item.zphID + '&jobFairName=' + item.zphmc)"
>
<view class="card-title">{{ item.name }}</view>
<view class="card-title">{{ item.zphmc }}</view>
<view class="card-row">
<text class="">{{ item.location }}</text>
<text class="">{{ item.jbf }}</text>
<text class="">
<convert-distance
<!-- <convert-distance
:alat="item.latitude"
:along="item.longitude"
:blat="latitudeVal"
:blong="longitudeVal"
></convert-distance>
></convert-distance> -->
</text>
</view>
<view class="card-times">
<view class="time-left">
<view class="left-date">{{ parseDateTime(item.startTime).time }}</view>
<view class="left-dateDay">{{ parseDateTime(item.startTime).date }}</view>
<view class="left-date">{{ parseDateTime(item.zphjbsj).time }}</view>
<view class="left-dateDay">{{ parseDateTime(item.zphjbsj).date }}</view>
</view>
<view class="line"></view>
<view class="time-center">
<view class="center-date">
{{ getTimeStatus(item.startTime, item.endTime).statusText }}
{{ getTimeStatus(item.zphjbsj, item.zphjzsj).statusText }}
</view>
<view class="center-dateDay">
{{ getHoursBetween(item.startTime, item.endTime) }}小时
{{ getHoursBetween(item.zphjbsj, item.zphjzsj) }}小时
</view>
</view>
<view class="line"></view>
<view class="time-right">
<view class="left-date">{{ parseDateTime(item.endTime).time }}</view>
<view class="left-dateDay">{{ parseDateTime(item.endTime).date }}</view>
<view class="left-date">{{ parseDateTime(item.zphjzsj).time }}</view>
<view class="left-dateDay">{{ parseDateTime(item.zphjzsj).date }}</view>
</view>
</view>
<view class="recommend-card-line"></view>
<view class="card-footer">内容简介{{ item.description }}</view>
<view class="card-footer">内容简介{{ item.zphjj }}</view>
</view>
</view>
<empty v-else pdTop="200"></empty>
@@ -95,7 +95,7 @@ import Tabbar from '@/components/tabbar/midell-box.vue';
import useLocationStore from '@/stores/useLocationStore';
import { storeToRefs } from 'pinia';
const { longitudeVal, latitudeVal } = storeToRefs(useLocationStore());
const { $api, navTo, cloneDeep } = inject('globalFunction');
const { $api, navTo, cloneDeep,debounce } = inject('globalFunction');
const weekList = ref([]);
const fairList = ref([]);
const currentDay = ref({});
@@ -108,7 +108,7 @@ const pageState = reactive({
total: 0,
maxPage: 2,
pageSize: 10,
search: {},
zphmc:''
});
onLoad(() => {
@@ -122,6 +122,7 @@ onLoad(() => {
startDate: currentDate,
});
weekList.value = result;
currentDay.value.fullDate = result[0].fullDate
getFair('refresh');
});
@@ -161,10 +162,12 @@ function seemsg(index) {
}
const handleScrollToLower = () => {
return
getFair();
console.log('触底');
};
function getFair(type = 'add') {
if (type === 'refresh') {
pageState.page = 1;
@@ -174,21 +177,24 @@ function getFair(type = 'add') {
pageState.page += 1;
}
let params = {
...pageState.search,
current: pageState.page,
pageSize: pageState.pageSize,
zphmc:pageState.zphmc,
// current: pageState.page,
// pageSize: pageState.pageSize,
};
// if (currentDay.value?.fullDate) {
// params.queryDate = currentDay.value.fullDate;
// }
if (currentDay.value?.fullDate) {
params.queryDate = currentDay.value.fullDate;
params.zphjbsj = currentDay.value.fullDate.replace(/-/g, '');
}
$api.createRequest('/app/fair', params).then((resData) => {
$api.createRequest('/app/internal/jobFairThirdPart', params).then((resData) => {
const { rows, total } = resData;
console.log(rows);
if (type === 'add') {
const str = pageState.pageSize * (pageState.page - 1);
const end = fairList.value.length;
const reslist = rows;
fairList.value.splice(str, end, ...reslist);
// const str = pageState.pageSize * (pageState.page - 1);
// const end = fairList.value.length;
// const reslist = rows;
// fairList.value.splice(str, end, ...reslist);
fairList.value = rows
} else {
fairList.value = rows;
}

View File

@@ -250,8 +250,6 @@ import {
ref,
inject,
nextTick,
defineProps,
defineEmits,
onMounted,
onUnmounted,
toRaw,
@@ -448,7 +446,7 @@ const scrollToBottom = throttle(function () {
}, 500);
function getGuess() {
$api.chatRequest('/guest', { sessionId: chatSessionID.value }, 'POST').then((res) => {
$api.chatRequest('/app/chat/guest', { sessionId: chatSessionID.value }, 'POST').then((res) => {
guessList.value = res.data;
showGuess.value = true;
nextTick(() => {

View File

@@ -37,7 +37,7 @@
</template>
<script setup>
import { ref, inject, defineEmits } from 'vue';
import { ref, inject } from 'vue';
const emit = defineEmits(['onSend']);
const { $api } = inject('globalFunction');
const popup = ref(null);

View File

@@ -109,6 +109,7 @@
</template>
</tabcontrolVue>
<SelectJobs ref="selectJobsModel"></SelectJobs>
<view class="backdoor" @click="loginbackdoor">后门</view>
</AppLayout>
</template>
@@ -149,7 +150,6 @@ const fromValue = reactive({
});
onLoad((parmas) => {
console.log(parmas);
getTreeselect();
});
@@ -244,6 +244,23 @@ function getTreeselect() {
});
}
function loginbackdoor() {
$api.createRequest('/app/mock/login', {}, 'post').then((resData) => {
$api.msg('模拟帐号密码测试登录成功');
loginSetToken(resData.token).then((resume) => {
if (resume.data.jobTitleId) {
// 设置推荐列表,每次退出登录都需要更新
useUserStore().initSeesionId();
uni.reLaunch({
url: '/pages/index/index',
});
} else {
nextStep();
}
});
});
}
// 登录
function loginTest() {
// uni.share({
@@ -290,6 +307,12 @@ function complete() {
</script>
<style lang="stylus" scoped>
.backdoor{
position: fixed;
left: 0;
top: 500rpx;
background: red
}
.input-nx
position: relative
border-bottom: 2rpx solid #EBEBEB

View File

@@ -45,9 +45,7 @@
<text v-if="userInfo.jobTitle.length - 1 !== index">|</text>
</text>
</view>
<view class="top-btn button-click" >
电子名片
</view>
<view class="top-btn button-click">电子名片</view>
</view>
<view class="card-main">
<view class="main-title">服务专区</view>
@@ -132,7 +130,6 @@ const isAbove90 = (percent) => parseFloat(percent) < 90;
function getUserstatistics() {
$api.createRequest('/app/user/statistics').then((resData) => {
console.log(resData);
counts.value = resData.data;
});
}

File diff suppressed because it is too large Load Diff

234
static/js/aes.js Normal file
View File

@@ -0,0 +1,234 @@
;(function (root, factory, undef) {
if (typeof exports === "object") {
// CommonJS
module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core"));
}
else if (typeof define === "function" && define.amd) {
// AMD
define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory);
}
else {
// Global (browser)
factory(root.CryptoJS);
}
}(this, function (CryptoJS) {
(function () {
// Shortcuts
var C = CryptoJS;
var C_lib = C.lib;
var BlockCipher = C_lib.BlockCipher;
var C_algo = C.algo;
// Lookup tables
var SBOX = [];
var INV_SBOX = [];
var SUB_MIX_0 = [];
var SUB_MIX_1 = [];
var SUB_MIX_2 = [];
var SUB_MIX_3 = [];
var INV_SUB_MIX_0 = [];
var INV_SUB_MIX_1 = [];
var INV_SUB_MIX_2 = [];
var INV_SUB_MIX_3 = [];
// Compute lookup tables
(function () {
// Compute double table
var d = [];
for (var i = 0; i < 256; i++) {
if (i < 128) {
d[i] = i << 1;
} else {
d[i] = (i << 1) ^ 0x11b;
}
}
// Walk GF(2^8)
var x = 0;
var xi = 0;
for (var i = 0; i < 256; i++) {
// Compute sbox
var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4);
sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63;
SBOX[x] = sx;
INV_SBOX[sx] = x;
// Compute multiplication
var x2 = d[x];
var x4 = d[x2];
var x8 = d[x4];
// Compute sub bytes, mix columns tables
var t = (d[sx] * 0x101) ^ (sx * 0x1010100);
SUB_MIX_0[x] = (t << 24) | (t >>> 8);
SUB_MIX_1[x] = (t << 16) | (t >>> 16);
SUB_MIX_2[x] = (t << 8) | (t >>> 24);
SUB_MIX_3[x] = t;
// Compute inv sub bytes, inv mix columns tables
var t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100);
INV_SUB_MIX_0[sx] = (t << 24) | (t >>> 8);
INV_SUB_MIX_1[sx] = (t << 16) | (t >>> 16);
INV_SUB_MIX_2[sx] = (t << 8) | (t >>> 24);
INV_SUB_MIX_3[sx] = t;
// Compute next counter
if (!x) {
x = xi = 1;
} else {
x = x2 ^ d[d[d[x8 ^ x2]]];
xi ^= d[d[xi]];
}
}
}());
// Precomputed Rcon lookup
var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
/**
* AES block cipher algorithm.
*/
var AES = C_algo.AES = BlockCipher.extend({
_doReset: function () {
var t;
// Skip reset of nRounds has been set before and key did not change
if (this._nRounds && this._keyPriorReset === this._key) {
return;
}
// Shortcuts
var key = this._keyPriorReset = this._key;
var keyWords = key.words;
var keySize = key.sigBytes / 4;
// Compute number of rounds
var nRounds = this._nRounds = keySize + 6;
// Compute number of key schedule rows
var ksRows = (nRounds + 1) * 4;
// Compute key schedule
var keySchedule = this._keySchedule = [];
for (var ksRow = 0; ksRow < ksRows; ksRow++) {
if (ksRow < keySize) {
keySchedule[ksRow] = keyWords[ksRow];
} else {
t = keySchedule[ksRow - 1];
if (!(ksRow % keySize)) {
// Rot word
t = (t << 8) | (t >>> 24);
// Sub word
t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff];
// Mix Rcon
t ^= RCON[(ksRow / keySize) | 0] << 24;
} else if (keySize > 6 && ksRow % keySize == 4) {
// Sub word
t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff];
}
keySchedule[ksRow] = keySchedule[ksRow - keySize] ^ t;
}
}
// Compute inv key schedule
var invKeySchedule = this._invKeySchedule = [];
for (var invKsRow = 0; invKsRow < ksRows; invKsRow++) {
var ksRow = ksRows - invKsRow;
if (invKsRow % 4) {
var t = keySchedule[ksRow];
} else {
var t = keySchedule[ksRow - 4];
}
if (invKsRow < 4 || ksRow <= 4) {
invKeySchedule[invKsRow] = t;
} else {
invKeySchedule[invKsRow] = INV_SUB_MIX_0[SBOX[t >>> 24]] ^ INV_SUB_MIX_1[SBOX[(t >>> 16) & 0xff]] ^
INV_SUB_MIX_2[SBOX[(t >>> 8) & 0xff]] ^ INV_SUB_MIX_3[SBOX[t & 0xff]];
}
}
},
encryptBlock: function (M, offset) {
this._doCryptBlock(M, offset, this._keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX);
},
decryptBlock: function (M, offset) {
// Swap 2nd and 4th rows
var t = M[offset + 1];
M[offset + 1] = M[offset + 3];
M[offset + 3] = t;
this._doCryptBlock(M, offset, this._invKeySchedule, INV_SUB_MIX_0, INV_SUB_MIX_1, INV_SUB_MIX_2, INV_SUB_MIX_3, INV_SBOX);
// Inv swap 2nd and 4th rows
var t = M[offset + 1];
M[offset + 1] = M[offset + 3];
M[offset + 3] = t;
},
_doCryptBlock: function (M, offset, keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX) {
// Shortcut
var nRounds = this._nRounds;
// Get input, add round key
var s0 = M[offset] ^ keySchedule[0];
var s1 = M[offset + 1] ^ keySchedule[1];
var s2 = M[offset + 2] ^ keySchedule[2];
var s3 = M[offset + 3] ^ keySchedule[3];
// Key schedule row counter
var ksRow = 4;
// Rounds
for (var round = 1; round < nRounds; round++) {
// Shift rows, sub bytes, mix columns, add round key
var t0 = SUB_MIX_0[s0 >>> 24] ^ SUB_MIX_1[(s1 >>> 16) & 0xff] ^ SUB_MIX_2[(s2 >>> 8) & 0xff] ^ SUB_MIX_3[s3 & 0xff] ^ keySchedule[ksRow++];
var t1 = SUB_MIX_0[s1 >>> 24] ^ SUB_MIX_1[(s2 >>> 16) & 0xff] ^ SUB_MIX_2[(s3 >>> 8) & 0xff] ^ SUB_MIX_3[s0 & 0xff] ^ keySchedule[ksRow++];
var t2 = SUB_MIX_0[s2 >>> 24] ^ SUB_MIX_1[(s3 >>> 16) & 0xff] ^ SUB_MIX_2[(s0 >>> 8) & 0xff] ^ SUB_MIX_3[s1 & 0xff] ^ keySchedule[ksRow++];
var t3 = SUB_MIX_0[s3 >>> 24] ^ SUB_MIX_1[(s0 >>> 16) & 0xff] ^ SUB_MIX_2[(s1 >>> 8) & 0xff] ^ SUB_MIX_3[s2 & 0xff] ^ keySchedule[ksRow++];
// Update state
s0 = t0;
s1 = t1;
s2 = t2;
s3 = t3;
}
// Shift rows, sub bytes, add round key
var t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++];
var t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++];
var t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++];
var t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++];
// Set output
M[offset] = t0;
M[offset + 1] = t1;
M[offset + 2] = t2;
M[offset + 3] = t3;
},
keySize: 256/32
});
/**
* Shortcut functions to the cipher's object interface.
*
* @example
*
* var ciphertext = CryptoJS.AES.encrypt(message, key, cfg);
* var plaintext = CryptoJS.AES.decrypt(ciphertext, key, cfg);
*/
C.AES = BlockCipher._createHelper(AES);
}());
return CryptoJS.AES;
}));

7
static/js/sm4.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -180,7 +180,7 @@ const useChatGroupDBStore = defineStore("messageGroup", () => {
resolve();
}
$api.streamRequest('/chat', params, onDataReceived, onError, onComplete);
$api.streamRequest('/app/chat/chat', params, onDataReceived, onError, onComplete);
} catch (err) {
console.log(err);
reject(err);
@@ -230,7 +230,7 @@ const useChatGroupDBStore = defineStore("messageGroup", () => {
// 云端数据
function getHistory() {
$api.chatRequest('/getHistory').then((res) => {
$api.chatRequest('/app/chat/getHistory').then((res) => {
if (!res.data.list.length) return
let tabel = parseHistory(res.data.list)
if (tabel && tabel.length) {
@@ -250,7 +250,7 @@ const useChatGroupDBStore = defineStore("messageGroup", () => {
const params = {
sessionId: chatSessionID.value
}
$api.chatRequest('/detail', params, 'GET', loading).then((res) => {
$api.chatRequest('/app/chat/detail', params, 'GET', loading).then((res) => {
let list = parseHistoryDetail(res.data.list, chatSessionID.value)
if (list.length) {
baseDB.db.add(massageName.value, list).then((ids) => {

View File

@@ -4,73 +4,21 @@ import {
sm2_Encrypt
} from '@/common/globalFunction';
import useUserStore from '@/stores/useUserStore';
import {
sm4Decrypt,
sm4Encrypt
} from '../common/globalFunction';
export function request({
url,
method = 'GET',
data = {},
load = false,
header = {}
} = {}) {
return new Promise((resolve, reject) => {
if (load) {
uni.showLoading({
title: '请稍候',
mask: true
});
}
let Authorization = ''
if (useUserStore().token) {
Authorization = `${useUserStore().userInfo.token}${useUserStore().token}`
}
uni.request({
url: config.baseUrl + url,
method,
data: data,
header: {
'Authorization': Authorization || '',
},
success: resData => {
// 响应拦截
if (resData.statusCode === 200) {
const {
code,
msg
} = resData.data
if (code === 200) {
resolve(resData.data)
return
}
uni.showToast({
title: msg,
icon: 'none'
})
}
if (resData.data?.code === 401 || resData.data?.code === 402) {
useUserStore().logOut()
uni.showToast({
title: '登录过期,请重新登录',
icon: 'none'
})
return
}
const err = new Error('请求出现异常,请联系工作人员')
err.error = resData
reject(err)
},
fail: err => reject(err),
complete() {
if (load) {
uni.hideLoading();
}
}
})
})
}
const needToEncrypt = [
["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/{value}"],
["get", "/app/user/experience/list"]
]
/**
* @param url String请求的地址默认none
@@ -94,15 +42,44 @@ export function createRequest(url, data = {}, method = 'GET', loading = false, h
const header = headers || {};
header["Authorization"] = encodeURIComponent(Authorization);
// ------------------------------------------------------------------
// 检查当前请求是否需要加密
const isEncrypt = needToEncrypt.some(item => {
const matchMethod = item[0].toLowerCase() === method.toLowerCase();
const matchUrl = item[1].includes('{') ?
url.startsWith(item[1].split('/{')[0]) // 检查动态路径的前缀
:
item[1] === url; // 检查静态路径
return matchMethod && matchUrl;
});
let requestData = data;
if (isEncrypt) {
const jsonData = JSON.stringify(data);
const encryptedBody = sm4Encrypt(config.sm4Config.key, jsonData);
requestData = {
encrypted: true,
encryptedData: encryptedBody,
timestamp: Date.now()
};
}
// ------------------------------------------------------------------
return new Promise((resolve, reject) => {
uni.request({
url: config.baseUrl + url,
method: method,
data: data,
data: requestData,
header,
success: resData => {
// 响应拦截
if (resData.statusCode === 200) {
if (resData.data.encrypted) {
const decryptedData = sm4Decrypt(config
.sm4Config.key, resData.data.encryptedData)
resData.data = JSON.parse(decryptedData)
}
const {
code,
msg

View File

@@ -17,7 +17,7 @@ export default function StreamRequest(url, data = {}, onDataReceived, onError, o
};
return new Promise(async (resolve, reject) => {
try {
const response = await fetch(config.StreamBaseURl + url, {
const response = await fetch(config.baseUrl + url, {
method: "POST",
headers,
body: JSON.stringify(data)
@@ -46,6 +46,7 @@ export default function StreamRequest(url, data = {}, onDataReceived, onError, o
let lines = buffer.split("\n");
buffer = lines.pop(); // 可能是不完整的 JSON 片段,留待下次解析
for (let line of lines) {
line = line.slice(5).trim()
if (line.startsWith("data: ")) {
const jsonData = line.slice(6).trim();
if (jsonData === "[DONE]") {
@@ -104,7 +105,7 @@ export function chatRequest(url, data = {}, method = 'GET', loading = false, hea
header["Authorization"] = encodeURIComponent(Authorization);
return new Promise((resolve, reject) => {
uni.request({
url: config.StreamBaseURl + url,
url: config.baseUrl + url,
method: method,
data: data,
header,