flat: 合并
This commit is contained in:
95
App.vue
95
App.vue
@@ -3,14 +3,19 @@ import { reactive, inject, onMounted } from 'vue';
|
||||
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app';
|
||||
import useUserStore from './stores/useUserStore';
|
||||
import useDictStore from './stores/useDictStore';
|
||||
const { $api, navTo, appendScriptTagElement } = inject('globalFunction');
|
||||
const { $api, navTo, appendScriptTagElement, aes_Decrypt, sm2_Decrypt } = inject('globalFunction');
|
||||
import config from '@/config.js';
|
||||
|
||||
const appword = 'aKd20dbGdFvmuwrt'; // 固定值
|
||||
|
||||
onLaunch((options) => {
|
||||
useUserStore().initSeesionId(); //更新
|
||||
// uni.hideTabBar();
|
||||
useDictStore().getDictData();
|
||||
uni.hideTabBar();
|
||||
// 登录
|
||||
try {
|
||||
getUserInfo();
|
||||
} catch {
|
||||
console.log('不是爱山东平台,使用测试登陆');
|
||||
useUserStore().initSeesionId(); //更新
|
||||
let token = uni.getStorageSync('token') || ''; // 同步获取 缓存信息
|
||||
if (token) {
|
||||
useUserStore()
|
||||
@@ -23,6 +28,7 @@ onLaunch((options) => {
|
||||
url: '/pages/login/login',
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {});
|
||||
@@ -34,6 +40,87 @@ onShow(() => {
|
||||
onHide(() => {
|
||||
console.log('App Hide');
|
||||
});
|
||||
|
||||
function getUserInfo() {
|
||||
lightAppJssdk.user.getUserInfoWithEncryptedParamByAppId({
|
||||
appId: 'qdsrgznrgpp', // 接入方在成功创建应用后自动生成
|
||||
success: function (data) {
|
||||
if (data == '未登录') onLoginApp();
|
||||
else {
|
||||
if (typeof data == 'string') data = JSON.parse(data);
|
||||
|
||||
const sm2_privateKey = '7e14966df4ecd4241ed082ef716d82b52113cb5899ebdc704a98844d0a32b0dc';
|
||||
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);
|
||||
}
|
||||
},
|
||||
fail: function (data) {
|
||||
console.log('err', data);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用jssdk调用登录页面
|
||||
*/
|
||||
function onLoginApp() {
|
||||
lightAppJssdk.user.loginapp({
|
||||
success: function (data) {
|
||||
if (data == '未登录') {
|
||||
//取消登录或登录失败,关闭页面
|
||||
oncloseWindow();
|
||||
} else {
|
||||
getUserInfo();
|
||||
}
|
||||
},
|
||||
fail: function (data) {
|
||||
//关闭页面
|
||||
oncloseWindow();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭容器
|
||||
*/
|
||||
function oncloseWindow() {
|
||||
lightAppJssdk.navigation.close({
|
||||
success: function (data) {},
|
||||
fail: function (data) {},
|
||||
});
|
||||
}
|
||||
|
||||
function loginCallback(userInfo) {
|
||||
let params = {
|
||||
username: userInfo,
|
||||
};
|
||||
$api.createRequest('/app/login', params, 'post').then((resData) => {
|
||||
useUserStore()
|
||||
.loginSetToken(resData.token)
|
||||
.then((resume) => {
|
||||
if (resume.data.jobTitleId) {
|
||||
useUserStore().initSeesionId();
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index',
|
||||
});
|
||||
} else {
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/login',
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -554,6 +554,24 @@ function isEmptyObject(obj) {
|
||||
return obj && typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0;
|
||||
}
|
||||
|
||||
function aes_Decrypt(word, key) {
|
||||
var key = CryptoJS.enc.Utf8.parse(key) //转为128bit
|
||||
var srcs = CryptoJS.enc.Hex.parse(word) //转为16进制
|
||||
var str = CryptoJS.enc.Base64.stringify(srcs) //变为Base64编码的字符串
|
||||
var decrypt = CryptoJS.AES.decrypt(str, key, {
|
||||
mode: CryptoJS.mode.ECB,
|
||||
spadding: CryptoJS.pad.Pkcs7
|
||||
})
|
||||
return decrypt.toString(CryptoJS.enc.Utf8)
|
||||
}
|
||||
|
||||
export function sm2_Decrypt(word, key) {
|
||||
return SM.decrypt(word, key);
|
||||
}
|
||||
|
||||
export function sm2_Encrypt(word, key) {
|
||||
return SM.encrypt(word, key);
|
||||
}
|
||||
|
||||
export function sm4Decrypt(key, value, mode = "hex") {
|
||||
try {
|
||||
@@ -607,7 +625,8 @@ export const $api = {
|
||||
uploadFile,
|
||||
formatFileSize,
|
||||
sendingMiniProgramMessage,
|
||||
copyText
|
||||
copyText,
|
||||
aes_Decrypt,
|
||||
}
|
||||
|
||||
|
||||
@@ -638,4 +657,7 @@ export default {
|
||||
isInWechatMiniProgramWebview,
|
||||
isEmptyObject,
|
||||
sm4Decrypt,
|
||||
aes_Decrypt,
|
||||
sm2_Decrypt,
|
||||
sm2_Encrypt
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
export default {
|
||||
// baseUrl: 'http://39.98.44.136:8080', // 测试
|
||||
// baseUrl: 'https://fw.rc.qingdao.gov.cn/rgpp-api/api', // 内网
|
||||
baseUrl: 'https://qd.zhaopinzao8dian.com/api', // 测试
|
||||
// baseUrl: 'http://10.133.17.161:8080/api', // 测试
|
||||
// baseUrl: 'http://192.168.3.19:8080', // 测试
|
||||
// baseUrl: 'http://39.98.44.136:6009', // 测试
|
||||
// baseUrl: "http://192.168.98.110:18181",
|
||||
// baseUrl: "http://192.168.3.19:8080",
|
||||
// sseAI+
|
||||
// StreamBaseURl: 'http://39.98.44.136:8000',
|
||||
StreamBaseURl: 'https://qd.zhaopinzao8dian.com/ai',
|
||||
|
||||
@@ -49,6 +49,7 @@ export function useTTSPlayer() {
|
||||
const newUtterance = new SpeechSynthesisUtterance(filteredText); // Use filtered text
|
||||
utteranceRef.value = newUtterance;
|
||||
|
||||
newUtterance.lang = 'zh-CN';
|
||||
newUtterance.rate = options.rate || 1;
|
||||
newUtterance.pitch = options.pitch || 1;
|
||||
if (options.voice) {
|
||||
|
||||
19
index.html
19
index.html
@@ -17,14 +17,19 @@
|
||||
})();
|
||||
</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();
|
||||
</script> -->
|
||||
<!-- 爱山东jssdk -->
|
||||
<!-- <script type="text/javascript" src="https://isdapp.shandong.gov.cn/jmopen/jssdk/index.js"></script> -->
|
||||
eruda.init();
|
||||
</script>
|
||||
<!-- 爱山东jssdk 本sdk存在性能问题 -->
|
||||
<script type="text/javascript" src="https://isdapp.shandong.gov.cn/jmopen/jssdk/index.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/js/sm4.min.js"></script>
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
"locale": "zh-Hans",
|
||||
"h5": {
|
||||
"router": {
|
||||
"base": "/app/",
|
||||
"base": "./",
|
||||
"mode": "hash"
|
||||
},
|
||||
"title": "青岛智慧就业服务",
|
||||
@@ -97,6 +97,9 @@
|
||||
"serviceHost": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"devServer": {
|
||||
"https": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -102,9 +102,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>
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
<template>
|
||||
<scroll-view :scroll-y="true" class="app-container" :scroll-top="scrollTop" @scroll="checkStickyStatus" @scrolltolower="scrollBottom">
|
||||
<scroll-view
|
||||
:scroll-y="true"
|
||||
class="app-container"
|
||||
:scroll-top="scrollTop"
|
||||
@scroll="checkStickyStatus"
|
||||
@scrolltolower="scrollBottom"
|
||||
>
|
||||
<view class="nav-hidden">
|
||||
<view class="container-search">
|
||||
<image class="bg-text" mode="widthFix" src="@/static/icon/index-text-bg.png"></image>
|
||||
@@ -79,23 +85,49 @@
|
||||
<view class="filter-top" @touchmove.stop.prevent>
|
||||
<scroll-view :scroll-x="true" :show-scrollbar="false" class="tab-scroll">
|
||||
<view class="jobs-left">
|
||||
<view class="job button-click" :class="{ active: state.tabIndex === 'all' }" @click="choosePosition('all')"> 全部 </view>
|
||||
<view class="job button-click" :class="{ active: state.tabIndex === index }" v-for="(item, index) in userInfo.jobTitle" :key="index" @click="choosePosition(index)">
|
||||
<view
|
||||
class="job button-click"
|
||||
:class="{ active: state.tabIndex === 'all' }"
|
||||
@click="choosePosition('all')"
|
||||
>
|
||||
全部
|
||||
</view>
|
||||
<view
|
||||
class="job button-click"
|
||||
:class="{ active: state.tabIndex === index }"
|
||||
v-for="(item, index) in userInfo.jobTitle"
|
||||
:key="index"
|
||||
@click="choosePosition(index)"
|
||||
>
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<image @click="navTo('/packageA/pages/addPosition/addPosition')" class="add-icon button-click" src="@/static/icon/add-circle.png"></image>
|
||||
<image
|
||||
@click="navTo('/packageA/pages/addPosition/addPosition')"
|
||||
class="add-icon button-click"
|
||||
src="@/static/icon/add-circle.png"
|
||||
></image>
|
||||
</view>
|
||||
<view class="filter-bottom">
|
||||
<view class="btm-left">
|
||||
<view class="button-click filterbtm" :class="{ active: pageState.search.order === item.value }" v-for="item in rangeOptions" @click="handelHostestSearch(item)" :key="item.value">
|
||||
<view
|
||||
class="button-click filterbtm"
|
||||
:class="{ active: pageState.search.order === item.value }"
|
||||
v-for="item in rangeOptions"
|
||||
@click="handelHostestSearch(item)"
|
||||
:key="item.value"
|
||||
>
|
||||
{{ item.text }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="btm-right button-click" @click="openFilter">
|
||||
筛选
|
||||
<image class="right-sx" :class="{ active: showFilter }" src="@/static/icon/polygon-down.png"></image>
|
||||
<image
|
||||
class="right-sx"
|
||||
:class="{ active: showFilter }"
|
||||
src="@/static/icon/polygon-down.png"
|
||||
></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -122,7 +154,10 @@
|
||||
<view v-if="job.isHot">
|
||||
<view class="falls-card-pay">
|
||||
<view class="pay-text">
|
||||
<Salary-Expectation :max-salary="job.maxSalary" :min-salary="job.minSalary"></Salary-Expectation>
|
||||
<Salary-Expectation
|
||||
:max-salary="job.maxSalary"
|
||||
:min-salary="job.minSalary"
|
||||
></Salary-Expectation>
|
||||
</view>
|
||||
<image class="flame" src="/static/icon/flame3.png"></image>
|
||||
</view>
|
||||
@@ -132,7 +167,10 @@
|
||||
<view class="falls-card-title">{{ job.jobTitle }}</view>
|
||||
<view class="falls-card-pay" style="margin-top: 10rpx">
|
||||
<view class="pay-text">
|
||||
<Salary-Expectation :max-salary="job.maxSalary" :min-salary="job.minSalary"></Salary-Expectation>
|
||||
<Salary-Expectation
|
||||
:max-salary="job.maxSalary"
|
||||
:min-salary="job.minSalary"
|
||||
></Salary-Expectation>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -153,7 +191,7 @@
|
||||
<view>
|
||||
<image class="point2" src="/static/icon/pintDate2.png"></image>
|
||||
<view class="fl_1">
|
||||
{{ job.postingDate || "发布日期" }}
|
||||
{{ job.postingDate || '发布日期' }}
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
@@ -176,7 +214,9 @@
|
||||
</view>
|
||||
<view v-if="!job.education" class="recommend-card" :class="{ isBut: job.isBut }">
|
||||
<view class="card-content">
|
||||
<view class="recommend-card-title">在找岗位:{{ job.jobCategory }}的工作吗?</view>
|
||||
<view class="recommend-card-title">
|
||||
在找岗位:{{ job.jobCategory }}的工作吗?
|
||||
</view>
|
||||
<!-- <view class="recommend-card-tip">{{ job.tip }}</view> -->
|
||||
<view class="recommend-card-tip">确认您的兴趣,为您推荐更多合适的岗位</view>
|
||||
<!-- <view class="recommend-card-line"></view> -->
|
||||
@@ -212,24 +252,24 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted, watchEffect, nextTick, getCurrentInstance } from "vue";
|
||||
import img from "@/static/icon/filter.png";
|
||||
import dictLabel from "@/components/dict-Label/dict-Label.vue";
|
||||
const { $api, navTo, vacanciesTo, formatTotal, throttle } = inject("globalFunction");
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||
import { storeToRefs } from "pinia";
|
||||
import useUserStore from "@/stores/useUserStore";
|
||||
import { reactive, inject, watch, ref, onMounted, watchEffect, nextTick, getCurrentInstance } from 'vue';
|
||||
import img from '@/static/icon/filter.png';
|
||||
import dictLabel from '@/components/dict-Label/dict-Label.vue';
|
||||
const { $api, navTo, vacanciesTo, formatTotal, throttle } = inject('globalFunction');
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
const { userInfo } = storeToRefs(useUserStore());
|
||||
import useDictStore from "@/stores/useDictStore";
|
||||
import useDictStore from '@/stores/useDictStore';
|
||||
const { getTransformChildren, oneDictData } = useDictStore();
|
||||
import useLocationStore from "@/stores/useLocationStore";
|
||||
import selectFilter from "@/components/selectFilter/selectFilter.vue";
|
||||
import { useRecommedIndexedDBStore, jobRecommender } from "@/stores/useRecommedIndexedDBStore.js";
|
||||
import { useScrollDirection } from "@/hook/useScrollDirection";
|
||||
import { useColumnCount } from "@/hook/useColumnCount";
|
||||
import useLocationStore from '@/stores/useLocationStore';
|
||||
import selectFilter from '@/components/selectFilter/selectFilter.vue';
|
||||
import { useRecommedIndexedDBStore, jobRecommender } from '@/stores/useRecommedIndexedDBStore.js';
|
||||
import { useScrollDirection } from '@/hook/useScrollDirection';
|
||||
import { useColumnCount } from '@/hook/useColumnCount';
|
||||
const { isScrollingDown, handleScroll } = useScrollDirection();
|
||||
const recommedIndexDb = useRecommedIndexedDBStore();
|
||||
import AIMatch from "./AIMatch.vue";
|
||||
import AIMatch from './AIMatch.vue';
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
@@ -239,7 +279,7 @@ const isSticky = ref(false);
|
||||
const showScrollBottom = ref(false);
|
||||
const scrollTop = ref(0);
|
||||
|
||||
const emits = defineEmits(["onShowTabbar"]);
|
||||
const emits = defineEmits(['onShowTabbar']);
|
||||
|
||||
const waterfallsFlowRef = ref(null);
|
||||
const loadmoreRef = ref(null);
|
||||
@@ -247,7 +287,7 @@ const conditionSearch = ref({});
|
||||
const waterfallcolumn = ref(2);
|
||||
|
||||
const state = reactive({
|
||||
tabIndex: "all",
|
||||
tabIndex: 'all',
|
||||
});
|
||||
const list = ref([]);
|
||||
const pageState = reactive({
|
||||
@@ -259,23 +299,64 @@ const pageState = reactive({
|
||||
order: 0,
|
||||
},
|
||||
});
|
||||
const inputText = ref("");
|
||||
const inputText = ref('');
|
||||
const showFilter = ref(false);
|
||||
const selectFilterModel = ref(null);
|
||||
const showModel = ref(false);
|
||||
const rangeOptions = ref([
|
||||
{ value: 0, text: "推荐" },
|
||||
{ value: 1, text: "最热" },
|
||||
{ value: 2, text: "最新发布" },
|
||||
{ value: 0, text: '推荐' },
|
||||
{ value: 1, text: '最热' },
|
||||
{ value: 2, text: '最新发布' },
|
||||
]);
|
||||
const isLoaded = ref(false);
|
||||
|
||||
const occupations = ["律师", "工程师", "医生", "教师", "设计师", "程序员", "会计师", "建筑师", "护士", "销售", "经理", "顾问", "分析师", "研究员", "编辑", "记者", "摄影师", "厨师", "司机", "保安", "客服", "行政", "人事", "市场", "运营", "产品", "测试", "运维", "前端", "后端", "全栈", "数据", "策划", "导演", "演员", "歌手", "作家", "画家", "翻译", "导游"];
|
||||
const occupations = [
|
||||
'律师',
|
||||
'工程师',
|
||||
'医生',
|
||||
'教师',
|
||||
'设计师',
|
||||
'程序员',
|
||||
'会计师',
|
||||
'建筑师',
|
||||
'护士',
|
||||
'销售',
|
||||
'经理',
|
||||
'顾问',
|
||||
'分析师',
|
||||
'研究员',
|
||||
'编辑',
|
||||
'记者',
|
||||
'摄影师',
|
||||
'厨师',
|
||||
'司机',
|
||||
'保安',
|
||||
'客服',
|
||||
'行政',
|
||||
'人事',
|
||||
'市场',
|
||||
'运营',
|
||||
'产品',
|
||||
'测试',
|
||||
'运维',
|
||||
'前端',
|
||||
'后端',
|
||||
'全栈',
|
||||
'数据',
|
||||
'策划',
|
||||
'导演',
|
||||
'演员',
|
||||
'歌手',
|
||||
'作家',
|
||||
'画家',
|
||||
'翻译',
|
||||
'导游',
|
||||
];
|
||||
|
||||
const colors = ["#0069FE", "#FF9400", "#FF6969", "#21EA85", "#87E2EC"];
|
||||
const colors = ['#0069FE', '#FF9400', '#FF6969', '#21EA85', '#87E2EC'];
|
||||
|
||||
onMounted(() => {
|
||||
let firstEntry = uni.getStorageSync("firstEntry") === false ? false : true; // 默认未读
|
||||
let firstEntry = uni.getStorageSync('firstEntry') === false ? false : true; // 默认未读
|
||||
maskFirstEntry.value = firstEntry;
|
||||
});
|
||||
|
||||
@@ -284,7 +365,7 @@ const checkStickyStatus = (e) => {
|
||||
nextTick(() => {
|
||||
const query = uni.createSelectorQuery().in(proxy);
|
||||
query
|
||||
.select(".nav-filter")
|
||||
.select('.nav-filter')
|
||||
.boundingClientRect()
|
||||
.exec((res) => {
|
||||
if (res[0]) {
|
||||
@@ -299,12 +380,12 @@ const checkStickyStatus = (e) => {
|
||||
};
|
||||
|
||||
function closeVideoTip() {
|
||||
uni.setStorageSync("firstEntry", false);
|
||||
uni.setStorageSync('firstEntry', false);
|
||||
maskFirstEntry.value = false;
|
||||
}
|
||||
|
||||
const handleTagClick = (tagInfo) => {
|
||||
console.log("点击的标签信息:", tagInfo);
|
||||
console.log('点击的标签信息:', tagInfo);
|
||||
};
|
||||
|
||||
const hexToRgba = (hex, opacity) => {
|
||||
@@ -319,12 +400,12 @@ const getTextColor = (hexColor) => {
|
||||
const g = parseInt(hexColor.slice(3, 5), 16);
|
||||
const b = parseInt(hexColor.slice(5, 7), 16);
|
||||
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
||||
return brightness > 180 ? "#1D71EF" : "#FFFFFF";
|
||||
return brightness > 180 ? '#1D71EF' : '#FFFFFF';
|
||||
};
|
||||
|
||||
const { columnCount, columnSpace } = useColumnCount(() => {
|
||||
pageState.pageSize = 10 * (columnCount.value - 1);
|
||||
getJobRecommend("refresh");
|
||||
getJobRecommend('refresh');
|
||||
nextTick(() => {
|
||||
waterfallsFlowRef.value?.refresh?.();
|
||||
useLocationStore().getLocation();
|
||||
@@ -342,14 +423,16 @@ async function loadData() {
|
||||
}
|
||||
|
||||
const scrollBottom = () => {
|
||||
if (loadmoreRef?.value?.status == "loading" || loadmoreRef?.value?.status == "noMore") return;
|
||||
loadmoreRef.value.change("loading");
|
||||
if (loadmoreRef.value && typeof loadmoreRef.value.change === 'function') {
|
||||
// if (loadmoreRef?.value?.status == 'loading' || loadmoreRef?.value?.status == 'noMore') return;
|
||||
loadmoreRef.value.change('loading');
|
||||
stopScroll();
|
||||
if (state.tabIndex === "all") {
|
||||
if (state.tabIndex === 'all') {
|
||||
getJobRecommend();
|
||||
} else {
|
||||
getJobList();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function stopScroll() {
|
||||
@@ -362,7 +445,7 @@ function stopScroll() {
|
||||
|
||||
function findJob(job) {
|
||||
if (job.isBut) {
|
||||
$api.msg("已确认");
|
||||
$api.msg('已确认');
|
||||
} else {
|
||||
list.value = list.value.map((item) => {
|
||||
if (item.recommend && item.jobCategory === job.jobCategory) {
|
||||
@@ -375,13 +458,13 @@ function findJob(job) {
|
||||
});
|
||||
const jobstr = job.jobCategory;
|
||||
const jobsObj = {
|
||||
地区: "area",
|
||||
岗位: "jobTitle",
|
||||
经验: "experience",
|
||||
地区: 'area',
|
||||
岗位: 'jobTitle',
|
||||
经验: 'experience',
|
||||
};
|
||||
const [name, value] = jobstr.split(":");
|
||||
const [name, value] = jobstr.split(':');
|
||||
const nameAttr = jobsObj[name];
|
||||
if (name === "岗位") {
|
||||
if (name === '岗位') {
|
||||
conditionSearch.value[nameAttr] = value;
|
||||
} else {
|
||||
const valueAttr = oneDictData(nameAttr).filter((item) => item.label === value);
|
||||
@@ -395,7 +478,7 @@ function findJob(job) {
|
||||
|
||||
function clearfindJob(job) {
|
||||
if (job.isBut) {
|
||||
$api.msg("已确认");
|
||||
$api.msg('已确认');
|
||||
} else {
|
||||
list.value = list.value.map((item) => {
|
||||
if (item.recommend && item.jobCategory === job.jobCategory) {
|
||||
@@ -421,23 +504,23 @@ function nextDetail(job) {
|
||||
|
||||
function openFilter() {
|
||||
showFilter.value = true;
|
||||
emits("onShowTabbar", false);
|
||||
emits('onShowTabbar', false);
|
||||
selectFilterModel.value?.open({
|
||||
title: "筛选",
|
||||
title: '筛选',
|
||||
maskClick: true,
|
||||
success: (values) => {
|
||||
pageState.search = {
|
||||
...pageState.search,
|
||||
};
|
||||
for (const [key, value] of Object.entries(values)) {
|
||||
pageState.search[key] = value.join(",");
|
||||
pageState.search[key] = value.join(',');
|
||||
}
|
||||
showFilter.value = false;
|
||||
getJobList("refresh");
|
||||
getJobList('refresh');
|
||||
},
|
||||
cancel: () => {
|
||||
showFilter.value = false;
|
||||
emits("onShowTabbar", true);
|
||||
emits('onShowTabbar', true);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -449,31 +532,31 @@ function handleFilterConfirm(e) {
|
||||
function choosePosition(index) {
|
||||
state.tabIndex = index;
|
||||
list.value = [];
|
||||
if (index === "all") {
|
||||
if (index === 'all') {
|
||||
pageState.search = {
|
||||
order: pageState.search.order,
|
||||
};
|
||||
inputText.value = "";
|
||||
getJobRecommend("refresh");
|
||||
inputText.value = '';
|
||||
getJobRecommend('refresh');
|
||||
} else {
|
||||
// const id = useUserStore().userInfo.jobTitleId.split(',')[index];
|
||||
pageState.search.jobTitle = userInfo.value.jobTitle[index];
|
||||
inputText.value = "";
|
||||
getJobList("refresh");
|
||||
inputText.value = '';
|
||||
getJobList('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
function handelHostestSearch(val) {
|
||||
pageState.search.order = val.value;
|
||||
if (state.tabIndex === "all") {
|
||||
getJobRecommend("refresh");
|
||||
if (state.tabIndex === 'all') {
|
||||
getJobRecommend('refresh');
|
||||
} else {
|
||||
getJobList("refresh");
|
||||
getJobList('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
function getJobRecommend(type = "add") {
|
||||
if (type === "refresh") {
|
||||
function getJobRecommend(type = 'add') {
|
||||
if (type === 'refresh') {
|
||||
list.value = [];
|
||||
if (waterfallsFlowRef.value) waterfallsFlowRef.value.refresh();
|
||||
}
|
||||
@@ -485,13 +568,13 @@ function getJobRecommend(type = "add") {
|
||||
};
|
||||
let comd = {
|
||||
recommend: true,
|
||||
jobCategory: "",
|
||||
tip: "确认你的兴趣,为您推荐更多合适的岗位",
|
||||
jobCategory: '',
|
||||
tip: '确认你的兴趣,为您推荐更多合适的岗位',
|
||||
};
|
||||
$api.createRequest("/app/job/recommend", params).then((resData) => {
|
||||
$api.createRequest('/app/job/recommend', params).then((resData) => {
|
||||
const { data, total } = resData;
|
||||
pageState.total = 0;
|
||||
if (type === "add") {
|
||||
if (type === 'add') {
|
||||
// 记录系统
|
||||
recommedIndexDb.getRecord().then((res) => {
|
||||
if (res.length) {
|
||||
@@ -518,11 +601,11 @@ function getJobRecommend(type = "add") {
|
||||
list.value = dataToImg(data);
|
||||
}
|
||||
// 切换状态
|
||||
if (loadmoreRef.value && typeof loadmoreRef.value.change === "function") {
|
||||
if (loadmoreRef.value && typeof loadmoreRef.value.change === 'function') {
|
||||
if (data.length < pageState.pageSize) {
|
||||
loadmoreRef.value.change("noMore");
|
||||
loadmoreRef.value.change('noMore');
|
||||
} else {
|
||||
loadmoreRef.value.change("more");
|
||||
loadmoreRef.value.change('more');
|
||||
}
|
||||
}
|
||||
// 当没有岗位,刷新sessionId重新啦
|
||||
@@ -532,11 +615,11 @@ function getJobRecommend(type = "add") {
|
||||
});
|
||||
}
|
||||
|
||||
function getJobList(type = "add") {
|
||||
if (type === "add" && pageState.page < pageState.maxPage) {
|
||||
function getJobList(type = 'add') {
|
||||
if (type === 'add' && pageState.page < pageState.maxPage) {
|
||||
pageState.page += 1;
|
||||
}
|
||||
if (type === "refresh") {
|
||||
if (type === 'refresh') {
|
||||
list.value = [];
|
||||
pageState.page = 1;
|
||||
pageState.maxPage = 2;
|
||||
@@ -550,9 +633,9 @@ function getJobList(type = "add") {
|
||||
// ...conditionSearch.value,
|
||||
};
|
||||
|
||||
$api.createRequest("/app/job/list", params).then((resData) => {
|
||||
$api.createRequest('/app/job/list', params).then((resData) => {
|
||||
const { rows, total } = resData;
|
||||
if (type === "add") {
|
||||
if (type === 'add') {
|
||||
const str = pageState.pageSize * (pageState.page - 1);
|
||||
const end = list.value.length;
|
||||
const reslist = dataToImg(rows);
|
||||
@@ -563,11 +646,11 @@ function getJobList(type = "add") {
|
||||
pageState.total = resData.total;
|
||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
||||
// 切换状态
|
||||
if (loadmoreRef.value && typeof loadmoreRef.value.change === "function") {
|
||||
if (loadmoreRef.value && typeof loadmoreRef.value.change === 'function') {
|
||||
if (rows.length < pageState.pageSize) {
|
||||
loadmoreRef.value?.change("noMore");
|
||||
loadmoreRef.value?.change('noMore');
|
||||
} else {
|
||||
loadmoreRef.value?.change("more");
|
||||
loadmoreRef.value?.change('more');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -69,7 +69,7 @@ onLoad(() => {
|
||||
|
||||
onShow(() => {
|
||||
// 获取消息列表
|
||||
useReadMsg().fetchMessages();
|
||||
// useReadMsg().fetchMessages();
|
||||
});
|
||||
|
||||
const state = reactive({
|
||||
|
||||
@@ -126,7 +126,7 @@ const { getDictSelectOption, oneDictData } = useDictStore();
|
||||
const openSelectPopup = inject('openSelectPopup');
|
||||
// status
|
||||
const selectJobsModel = ref();
|
||||
const tabCurrent = ref(0);
|
||||
const tabCurrent = ref(1);
|
||||
const salay = [2, 5, 10, 15, 20, 25, 30, 50, 80, 100];
|
||||
const state = reactive({
|
||||
station: [],
|
||||
@@ -150,7 +150,7 @@ const fromValue = reactive({
|
||||
});
|
||||
|
||||
onLoad((parmas) => {
|
||||
// getTreeselect();
|
||||
getTreeselect();
|
||||
});
|
||||
|
||||
onMounted(() => {});
|
||||
|
||||
168
static/js/SM.js
Normal file
168
static/js/SM.js
Normal file
File diff suppressed because one or more lines are too long
234
static/js/aes.js
Normal file
234
static/js/aes.js
Normal 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;
|
||||
|
||||
}));
|
||||
@@ -1,4 +1,8 @@
|
||||
import config from "@/config.js"
|
||||
import {
|
||||
sm2_Decrypt,
|
||||
sm2_Encrypt
|
||||
} from '@/common/globalFunction';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import {
|
||||
sm4Decrypt,
|
||||
|
||||
Reference in New Issue
Block a user