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 { onLaunch, onShow, onHide } from '@dcloudio/uni-app';
|
||||||
import useUserStore from './stores/useUserStore';
|
import useUserStore from './stores/useUserStore';
|
||||||
import useDictStore from './stores/useDictStore';
|
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';
|
import config from '@/config.js';
|
||||||
|
|
||||||
|
const appword = 'aKd20dbGdFvmuwrt'; // 固定值
|
||||||
|
|
||||||
onLaunch((options) => {
|
onLaunch((options) => {
|
||||||
useUserStore().initSeesionId(); //更新
|
// uni.hideTabBar();
|
||||||
useDictStore().getDictData();
|
useDictStore().getDictData();
|
||||||
uni.hideTabBar();
|
try {
|
||||||
// 登录
|
getUserInfo();
|
||||||
|
} catch {
|
||||||
|
console.log('不是爱山东平台,使用测试登陆');
|
||||||
|
useUserStore().initSeesionId(); //更新
|
||||||
let token = uni.getStorageSync('token') || ''; // 同步获取 缓存信息
|
let token = uni.getStorageSync('token') || ''; // 同步获取 缓存信息
|
||||||
if (token) {
|
if (token) {
|
||||||
useUserStore()
|
useUserStore()
|
||||||
@@ -23,6 +28,7 @@ onLaunch((options) => {
|
|||||||
url: '/pages/login/login',
|
url: '/pages/login/login',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {});
|
onMounted(() => {});
|
||||||
@@ -34,6 +40,87 @@ onShow(() => {
|
|||||||
onHide(() => {
|
onHide(() => {
|
||||||
console.log('App Hide');
|
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>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -554,6 +554,24 @@ function isEmptyObject(obj) {
|
|||||||
return obj && typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0;
|
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") {
|
export function sm4Decrypt(key, value, mode = "hex") {
|
||||||
try {
|
try {
|
||||||
@@ -607,7 +625,8 @@ export const $api = {
|
|||||||
uploadFile,
|
uploadFile,
|
||||||
formatFileSize,
|
formatFileSize,
|
||||||
sendingMiniProgramMessage,
|
sendingMiniProgramMessage,
|
||||||
copyText
|
copyText,
|
||||||
|
aes_Decrypt,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -638,4 +657,7 @@ export default {
|
|||||||
isInWechatMiniProgramWebview,
|
isInWechatMiniProgramWebview,
|
||||||
isEmptyObject,
|
isEmptyObject,
|
||||||
sm4Decrypt,
|
sm4Decrypt,
|
||||||
|
aes_Decrypt,
|
||||||
|
sm2_Decrypt,
|
||||||
|
sm2_Encrypt
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
export default {
|
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: 'https://qd.zhaopinzao8dian.com/api', // 测试
|
||||||
// baseUrl: 'http://10.133.17.161:8080/api', // 测试
|
// baseUrl: "http://192.168.98.110:18181",
|
||||||
// baseUrl: 'http://192.168.3.19:8080', // 测试
|
// baseUrl: "http://192.168.3.19:8080",
|
||||||
// baseUrl: 'http://39.98.44.136:6009', // 测试
|
|
||||||
// sseAI+
|
// sseAI+
|
||||||
// StreamBaseURl: 'http://39.98.44.136:8000',
|
// StreamBaseURl: 'http://39.98.44.136:8000',
|
||||||
StreamBaseURl: 'https://qd.zhaopinzao8dian.com/ai',
|
StreamBaseURl: 'https://qd.zhaopinzao8dian.com/ai',
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ export function useTTSPlayer() {
|
|||||||
const newUtterance = new SpeechSynthesisUtterance(filteredText); // Use filtered text
|
const newUtterance = new SpeechSynthesisUtterance(filteredText); // Use filtered text
|
||||||
utteranceRef.value = newUtterance;
|
utteranceRef.value = newUtterance;
|
||||||
|
|
||||||
|
newUtterance.lang = 'zh-CN';
|
||||||
newUtterance.rate = options.rate || 1;
|
newUtterance.rate = options.rate || 1;
|
||||||
newUtterance.pitch = options.pitch || 1;
|
newUtterance.pitch = options.pitch || 1;
|
||||||
if (options.voice) {
|
if (options.voice) {
|
||||||
|
|||||||
19
index.html
19
index.html
@@ -17,14 +17,19 @@
|
|||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<title></title>
|
<title></title>
|
||||||
<!-- vconsole -->
|
<!-- eruda -->
|
||||||
<!-- <script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/eruda"></script>
|
||||||
<script>
|
<script>
|
||||||
var vConsole = new window.VConsole();
|
eruda.init();
|
||||||
vConsole.destroy();
|
</script>
|
||||||
</script> -->
|
<!-- 爱山东jssdk 本sdk存在性能问题 -->
|
||||||
<!-- 爱山东jssdk -->
|
<script type="text/javascript" src="https://isdapp.shandong.gov.cn/jmopen/jssdk/index.js"></script>
|
||||||
<!-- <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>
|
<script type="text/javascript" src="./static/js/sm4.min.js"></script>
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@
|
|||||||
"locale": "zh-Hans",
|
"locale": "zh-Hans",
|
||||||
"h5": {
|
"h5": {
|
||||||
"router": {
|
"router": {
|
||||||
"base": "/app/",
|
"base": "./",
|
||||||
"mode": "hash"
|
"mode": "hash"
|
||||||
},
|
},
|
||||||
"title": "青岛智慧就业服务",
|
"title": "青岛智慧就业服务",
|
||||||
@@ -97,6 +97,9 @@
|
|||||||
"serviceHost": ""
|
"serviceHost": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"devServer": {
|
||||||
|
"https": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,31 +7,56 @@
|
|||||||
</template>
|
</template>
|
||||||
<view class="mys-container">
|
<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="mys-tops btn-feel">
|
||||||
<view class="tops-left">
|
<view class="tops-left">
|
||||||
<view class="name">
|
<view class="name">
|
||||||
<text>{{ userInfo.name || "编辑用户名" }}</text>
|
<text>{{ userInfo.name || "编辑用户名" }}</text>
|
||||||
<view class="edit-icon mar_le10">
|
<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>
|
</view>
|
||||||
<view class="subName">
|
<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>
|
<text class="mar_ri10">{{ userInfo.age }}岁</text>
|
||||||
<dict-Label class="mar_ri10" dictType="education" :value="userInfo.education"></dict-Label>
|
<dict-Label
|
||||||
<dict-Label class="mar_ri10" dictType="affiliation" :value="userInfo.politicalAffiliation"></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>
|
||||||
<view class="subName">{{ userInfo.phone }}</view>
|
<view class="subName">{{ userInfo.phone }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="tops-right">
|
<view class="tops-right">
|
||||||
<view class="right-imghead">
|
<view class="right-imghead">
|
||||||
<image v-if="userInfo.avatar" :src="userInfo.avatar"></image>
|
<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>
|
<image v-else src="@/static/icon/girl.png"></image>
|
||||||
</view>
|
</view>
|
||||||
<view class="right-sex">
|
<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>
|
<image v-else src="@/static/icon/girl1.png"></image>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -43,19 +68,34 @@
|
|||||||
<view class="mys-info btn-feel">
|
<view class="mys-info btn-feel">
|
||||||
<view class="mys-h4">
|
<view class="mys-h4">
|
||||||
<view>求职期望</view>
|
<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>
|
||||||
<view class="mys-text">
|
<view class="mys-text">
|
||||||
<text>期望薪资:</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>
|
||||||
<view class="mys-text">
|
<view class="mys-text">
|
||||||
<text>期望工作地:</text>
|
<text>期望工作地:</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>
|
||||||
<view class="mys-list">
|
<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 }}
|
{{ title }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -65,19 +105,35 @@
|
|||||||
<view class="mys-info" style="padding: 0">
|
<view class="mys-info" style="padding: 0">
|
||||||
<view class="mys-h4 btn-feel">
|
<view class="mys-h4 btn-feel">
|
||||||
<text>工作经历</text>
|
<text>工作经历</text>
|
||||||
<view class="mys-edit-icon btn-feel" @click="navTo('/packageA/pages/workExp/workExp')">
|
<view
|
||||||
<image class="icon button-click btn-feel" src="@/static/icon/plus.png"></image>
|
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 class="txt">添加</view>
|
||||||
</view>
|
</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="fl_box fl_justbet mar_top15">
|
||||||
<view class="fs_16">{{ item.company }}</view>
|
<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>
|
||||||
<view class="mys-text fl_box fl_justbet">
|
<view class="mys-text fl_box fl_justbet">
|
||||||
<text class="color_333333 fs_14">{{ item.position }}</text>
|
<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>
|
||||||
<view class="mys-text">
|
<view class="mys-text">
|
||||||
<text>{{ item.duty }}</text>
|
<text>{{ item.duty }}</text>
|
||||||
@@ -88,7 +144,9 @@
|
|||||||
</view>
|
</view>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<view class="footer-container">
|
<view class="footer-container">
|
||||||
<view class="footer-button btn-feel">上传简历</view>
|
<view class="footer-button btn-feel" @click="chooseResume"
|
||||||
|
>上传简历</view
|
||||||
|
>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
</AppLayout>
|
</AppLayout>
|
||||||
@@ -104,6 +162,69 @@ import useDictStore from "@/stores/useDictStore";
|
|||||||
const { userInfo } = storeToRefs(useUserStore());
|
const { userInfo } = storeToRefs(useUserStore());
|
||||||
const { getUserResume } = useUserStore();
|
const { getUserResume } = useUserStore();
|
||||||
const { getDictData, oneDictData } = useDictStore();
|
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>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
|
|||||||
@@ -102,9 +102,9 @@
|
|||||||
<text class="title">竞争力分析</text>
|
<text class="title">竞争力分析</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="description">
|
<view class="description">
|
||||||
三个月内共15位求职者申请,你的简历匹配度为{{ raderData.matchScore }}分,排名位于第{{
|
三个月内共{{ raderData.totalApplicants }}位求职者申请,你的简历匹配度为{{
|
||||||
raderData.rank
|
raderData.matchScore
|
||||||
}}位,超过{{ raderData.percentile }}%的竞争者,处在优秀位置。
|
}}分,排名位于第{{ raderData.rank }}位,超过{{ raderData.percentile }}%的竞争者,处在优秀位置。
|
||||||
</view>
|
</view>
|
||||||
<RadarMap :value="raderData"></RadarMap>
|
<RadarMap :value="raderData"></RadarMap>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
<template>
|
<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="nav-hidden">
|
||||||
<view class="container-search">
|
<view class="container-search">
|
||||||
<image class="bg-text" mode="widthFix" src="@/static/icon/index-text-bg.png"></image>
|
<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>
|
<view class="filter-top" @touchmove.stop.prevent>
|
||||||
<scroll-view :scroll-x="true" :show-scrollbar="false" class="tab-scroll">
|
<scroll-view :scroll-x="true" :show-scrollbar="false" class="tab-scroll">
|
||||||
<view class="jobs-left">
|
<view class="jobs-left">
|
||||||
<view class="job button-click" :class="{ active: state.tabIndex === 'all' }" @click="choosePosition('all')"> 全部 </view>
|
<view
|
||||||
<view class="job button-click" :class="{ active: state.tabIndex === index }" v-for="(item, index) in userInfo.jobTitle" :key="index" @click="choosePosition(index)">
|
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 }}
|
{{ item }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</scroll-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>
|
||||||
<view class="filter-bottom">
|
<view class="filter-bottom">
|
||||||
<view class="btm-left">
|
<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 }}
|
{{ item.text }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="btm-right button-click" @click="openFilter">
|
<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>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -122,7 +154,10 @@
|
|||||||
<view v-if="job.isHot">
|
<view v-if="job.isHot">
|
||||||
<view class="falls-card-pay">
|
<view class="falls-card-pay">
|
||||||
<view class="pay-text">
|
<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>
|
||||||
<image class="flame" src="/static/icon/flame3.png"></image>
|
<image class="flame" src="/static/icon/flame3.png"></image>
|
||||||
</view>
|
</view>
|
||||||
@@ -132,7 +167,10 @@
|
|||||||
<view class="falls-card-title">{{ job.jobTitle }}</view>
|
<view class="falls-card-title">{{ job.jobTitle }}</view>
|
||||||
<view class="falls-card-pay" style="margin-top: 10rpx">
|
<view class="falls-card-pay" style="margin-top: 10rpx">
|
||||||
<view class="pay-text">
|
<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>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -153,7 +191,7 @@
|
|||||||
<view>
|
<view>
|
||||||
<image class="point2" src="/static/icon/pintDate2.png"></image>
|
<image class="point2" src="/static/icon/pintDate2.png"></image>
|
||||||
<view class="fl_1">
|
<view class="fl_1">
|
||||||
{{ job.postingDate || "发布日期" }}
|
{{ job.postingDate || '发布日期' }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view>
|
<view>
|
||||||
@@ -176,7 +214,9 @@
|
|||||||
</view>
|
</view>
|
||||||
<view v-if="!job.education" class="recommend-card" :class="{ isBut: job.isBut }">
|
<view v-if="!job.education" class="recommend-card" :class="{ isBut: job.isBut }">
|
||||||
<view class="card-content">
|
<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">{{ job.tip }}</view> -->
|
||||||
<view class="recommend-card-tip">确认您的兴趣,为您推荐更多合适的岗位</view>
|
<view class="recommend-card-tip">确认您的兴趣,为您推荐更多合适的岗位</view>
|
||||||
<!-- <view class="recommend-card-line"></view> -->
|
<!-- <view class="recommend-card-line"></view> -->
|
||||||
@@ -212,24 +252,24 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, inject, watch, ref, onMounted, watchEffect, nextTick, getCurrentInstance } from "vue";
|
import { reactive, inject, watch, ref, onMounted, watchEffect, nextTick, getCurrentInstance } from 'vue';
|
||||||
import img from "@/static/icon/filter.png";
|
import img from '@/static/icon/filter.png';
|
||||||
import dictLabel from "@/components/dict-Label/dict-Label.vue";
|
import dictLabel from '@/components/dict-Label/dict-Label.vue';
|
||||||
const { $api, navTo, vacanciesTo, formatTotal, throttle } = inject("globalFunction");
|
const { $api, navTo, vacanciesTo, formatTotal, throttle } = inject('globalFunction');
|
||||||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from 'pinia';
|
||||||
import useUserStore from "@/stores/useUserStore";
|
import useUserStore from '@/stores/useUserStore';
|
||||||
const { userInfo } = storeToRefs(useUserStore());
|
const { userInfo } = storeToRefs(useUserStore());
|
||||||
import useDictStore from "@/stores/useDictStore";
|
import useDictStore from '@/stores/useDictStore';
|
||||||
const { getTransformChildren, oneDictData } = useDictStore();
|
const { getTransformChildren, oneDictData } = useDictStore();
|
||||||
import useLocationStore from "@/stores/useLocationStore";
|
import useLocationStore from '@/stores/useLocationStore';
|
||||||
import selectFilter from "@/components/selectFilter/selectFilter.vue";
|
import selectFilter from '@/components/selectFilter/selectFilter.vue';
|
||||||
import { useRecommedIndexedDBStore, jobRecommender } from "@/stores/useRecommedIndexedDBStore.js";
|
import { useRecommedIndexedDBStore, jobRecommender } from '@/stores/useRecommedIndexedDBStore.js';
|
||||||
import { useScrollDirection } from "@/hook/useScrollDirection";
|
import { useScrollDirection } from '@/hook/useScrollDirection';
|
||||||
import { useColumnCount } from "@/hook/useColumnCount";
|
import { useColumnCount } from '@/hook/useColumnCount';
|
||||||
const { isScrollingDown, handleScroll } = useScrollDirection();
|
const { isScrollingDown, handleScroll } = useScrollDirection();
|
||||||
const recommedIndexDb = useRecommedIndexedDBStore();
|
const recommedIndexDb = useRecommedIndexedDBStore();
|
||||||
import AIMatch from "./AIMatch.vue";
|
import AIMatch from './AIMatch.vue';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
|
|
||||||
@@ -239,7 +279,7 @@ const isSticky = ref(false);
|
|||||||
const showScrollBottom = ref(false);
|
const showScrollBottom = ref(false);
|
||||||
const scrollTop = ref(0);
|
const scrollTop = ref(0);
|
||||||
|
|
||||||
const emits = defineEmits(["onShowTabbar"]);
|
const emits = defineEmits(['onShowTabbar']);
|
||||||
|
|
||||||
const waterfallsFlowRef = ref(null);
|
const waterfallsFlowRef = ref(null);
|
||||||
const loadmoreRef = ref(null);
|
const loadmoreRef = ref(null);
|
||||||
@@ -247,7 +287,7 @@ const conditionSearch = ref({});
|
|||||||
const waterfallcolumn = ref(2);
|
const waterfallcolumn = ref(2);
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
tabIndex: "all",
|
tabIndex: 'all',
|
||||||
});
|
});
|
||||||
const list = ref([]);
|
const list = ref([]);
|
||||||
const pageState = reactive({
|
const pageState = reactive({
|
||||||
@@ -259,23 +299,64 @@ const pageState = reactive({
|
|||||||
order: 0,
|
order: 0,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const inputText = ref("");
|
const inputText = ref('');
|
||||||
const showFilter = ref(false);
|
const showFilter = ref(false);
|
||||||
const selectFilterModel = ref(null);
|
const selectFilterModel = ref(null);
|
||||||
const showModel = ref(false);
|
const showModel = ref(false);
|
||||||
const rangeOptions = ref([
|
const rangeOptions = ref([
|
||||||
{ value: 0, text: "推荐" },
|
{ value: 0, text: '推荐' },
|
||||||
{ value: 1, text: "最热" },
|
{ value: 1, text: '最热' },
|
||||||
{ value: 2, text: "最新发布" },
|
{ value: 2, text: '最新发布' },
|
||||||
]);
|
]);
|
||||||
const isLoaded = ref(false);
|
const isLoaded = ref(false);
|
||||||
|
|
||||||
const occupations = ["律师", "工程师", "医生", "教师", "设计师", "程序员", "会计师", "建筑师", "护士", "销售", "经理", "顾问", "分析师", "研究员", "编辑", "记者", "摄影师", "厨师", "司机", "保安", "客服", "行政", "人事", "市场", "运营", "产品", "测试", "运维", "前端", "后端", "全栈", "数据", "策划", "导演", "演员", "歌手", "作家", "画家", "翻译", "导游"];
|
const occupations = [
|
||||||
|
'律师',
|
||||||
|
'工程师',
|
||||||
|
'医生',
|
||||||
|
'教师',
|
||||||
|
'设计师',
|
||||||
|
'程序员',
|
||||||
|
'会计师',
|
||||||
|
'建筑师',
|
||||||
|
'护士',
|
||||||
|
'销售',
|
||||||
|
'经理',
|
||||||
|
'顾问',
|
||||||
|
'分析师',
|
||||||
|
'研究员',
|
||||||
|
'编辑',
|
||||||
|
'记者',
|
||||||
|
'摄影师',
|
||||||
|
'厨师',
|
||||||
|
'司机',
|
||||||
|
'保安',
|
||||||
|
'客服',
|
||||||
|
'行政',
|
||||||
|
'人事',
|
||||||
|
'市场',
|
||||||
|
'运营',
|
||||||
|
'产品',
|
||||||
|
'测试',
|
||||||
|
'运维',
|
||||||
|
'前端',
|
||||||
|
'后端',
|
||||||
|
'全栈',
|
||||||
|
'数据',
|
||||||
|
'策划',
|
||||||
|
'导演',
|
||||||
|
'演员',
|
||||||
|
'歌手',
|
||||||
|
'作家',
|
||||||
|
'画家',
|
||||||
|
'翻译',
|
||||||
|
'导游',
|
||||||
|
];
|
||||||
|
|
||||||
const colors = ["#0069FE", "#FF9400", "#FF6969", "#21EA85", "#87E2EC"];
|
const colors = ['#0069FE', '#FF9400', '#FF6969', '#21EA85', '#87E2EC'];
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
let firstEntry = uni.getStorageSync("firstEntry") === false ? false : true; // 默认未读
|
let firstEntry = uni.getStorageSync('firstEntry') === false ? false : true; // 默认未读
|
||||||
maskFirstEntry.value = firstEntry;
|
maskFirstEntry.value = firstEntry;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -284,7 +365,7 @@ const checkStickyStatus = (e) => {
|
|||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
const query = uni.createSelectorQuery().in(proxy);
|
const query = uni.createSelectorQuery().in(proxy);
|
||||||
query
|
query
|
||||||
.select(".nav-filter")
|
.select('.nav-filter')
|
||||||
.boundingClientRect()
|
.boundingClientRect()
|
||||||
.exec((res) => {
|
.exec((res) => {
|
||||||
if (res[0]) {
|
if (res[0]) {
|
||||||
@@ -299,12 +380,12 @@ const checkStickyStatus = (e) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function closeVideoTip() {
|
function closeVideoTip() {
|
||||||
uni.setStorageSync("firstEntry", false);
|
uni.setStorageSync('firstEntry', false);
|
||||||
maskFirstEntry.value = false;
|
maskFirstEntry.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleTagClick = (tagInfo) => {
|
const handleTagClick = (tagInfo) => {
|
||||||
console.log("点击的标签信息:", tagInfo);
|
console.log('点击的标签信息:', tagInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
const hexToRgba = (hex, opacity) => {
|
const hexToRgba = (hex, opacity) => {
|
||||||
@@ -319,12 +400,12 @@ const getTextColor = (hexColor) => {
|
|||||||
const g = parseInt(hexColor.slice(3, 5), 16);
|
const g = parseInt(hexColor.slice(3, 5), 16);
|
||||||
const b = parseInt(hexColor.slice(5, 7), 16);
|
const b = parseInt(hexColor.slice(5, 7), 16);
|
||||||
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
||||||
return brightness > 180 ? "#1D71EF" : "#FFFFFF";
|
return brightness > 180 ? '#1D71EF' : '#FFFFFF';
|
||||||
};
|
};
|
||||||
|
|
||||||
const { columnCount, columnSpace } = useColumnCount(() => {
|
const { columnCount, columnSpace } = useColumnCount(() => {
|
||||||
pageState.pageSize = 10 * (columnCount.value - 1);
|
pageState.pageSize = 10 * (columnCount.value - 1);
|
||||||
getJobRecommend("refresh");
|
getJobRecommend('refresh');
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
waterfallsFlowRef.value?.refresh?.();
|
waterfallsFlowRef.value?.refresh?.();
|
||||||
useLocationStore().getLocation();
|
useLocationStore().getLocation();
|
||||||
@@ -342,14 +423,16 @@ async function loadData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const scrollBottom = () => {
|
const scrollBottom = () => {
|
||||||
if (loadmoreRef?.value?.status == "loading" || loadmoreRef?.value?.status == "noMore") return;
|
if (loadmoreRef.value && typeof loadmoreRef.value.change === 'function') {
|
||||||
loadmoreRef.value.change("loading");
|
// if (loadmoreRef?.value?.status == 'loading' || loadmoreRef?.value?.status == 'noMore') return;
|
||||||
|
loadmoreRef.value.change('loading');
|
||||||
stopScroll();
|
stopScroll();
|
||||||
if (state.tabIndex === "all") {
|
if (state.tabIndex === 'all') {
|
||||||
getJobRecommend();
|
getJobRecommend();
|
||||||
} else {
|
} else {
|
||||||
getJobList();
|
getJobList();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function stopScroll() {
|
function stopScroll() {
|
||||||
@@ -362,7 +445,7 @@ function stopScroll() {
|
|||||||
|
|
||||||
function findJob(job) {
|
function findJob(job) {
|
||||||
if (job.isBut) {
|
if (job.isBut) {
|
||||||
$api.msg("已确认");
|
$api.msg('已确认');
|
||||||
} else {
|
} else {
|
||||||
list.value = list.value.map((item) => {
|
list.value = list.value.map((item) => {
|
||||||
if (item.recommend && item.jobCategory === job.jobCategory) {
|
if (item.recommend && item.jobCategory === job.jobCategory) {
|
||||||
@@ -375,13 +458,13 @@ function findJob(job) {
|
|||||||
});
|
});
|
||||||
const jobstr = job.jobCategory;
|
const jobstr = job.jobCategory;
|
||||||
const jobsObj = {
|
const jobsObj = {
|
||||||
地区: "area",
|
地区: 'area',
|
||||||
岗位: "jobTitle",
|
岗位: 'jobTitle',
|
||||||
经验: "experience",
|
经验: 'experience',
|
||||||
};
|
};
|
||||||
const [name, value] = jobstr.split(":");
|
const [name, value] = jobstr.split(':');
|
||||||
const nameAttr = jobsObj[name];
|
const nameAttr = jobsObj[name];
|
||||||
if (name === "岗位") {
|
if (name === '岗位') {
|
||||||
conditionSearch.value[nameAttr] = value;
|
conditionSearch.value[nameAttr] = value;
|
||||||
} else {
|
} else {
|
||||||
const valueAttr = oneDictData(nameAttr).filter((item) => item.label === value);
|
const valueAttr = oneDictData(nameAttr).filter((item) => item.label === value);
|
||||||
@@ -395,7 +478,7 @@ function findJob(job) {
|
|||||||
|
|
||||||
function clearfindJob(job) {
|
function clearfindJob(job) {
|
||||||
if (job.isBut) {
|
if (job.isBut) {
|
||||||
$api.msg("已确认");
|
$api.msg('已确认');
|
||||||
} else {
|
} else {
|
||||||
list.value = list.value.map((item) => {
|
list.value = list.value.map((item) => {
|
||||||
if (item.recommend && item.jobCategory === job.jobCategory) {
|
if (item.recommend && item.jobCategory === job.jobCategory) {
|
||||||
@@ -421,23 +504,23 @@ function nextDetail(job) {
|
|||||||
|
|
||||||
function openFilter() {
|
function openFilter() {
|
||||||
showFilter.value = true;
|
showFilter.value = true;
|
||||||
emits("onShowTabbar", false);
|
emits('onShowTabbar', false);
|
||||||
selectFilterModel.value?.open({
|
selectFilterModel.value?.open({
|
||||||
title: "筛选",
|
title: '筛选',
|
||||||
maskClick: true,
|
maskClick: true,
|
||||||
success: (values) => {
|
success: (values) => {
|
||||||
pageState.search = {
|
pageState.search = {
|
||||||
...pageState.search,
|
...pageState.search,
|
||||||
};
|
};
|
||||||
for (const [key, value] of Object.entries(values)) {
|
for (const [key, value] of Object.entries(values)) {
|
||||||
pageState.search[key] = value.join(",");
|
pageState.search[key] = value.join(',');
|
||||||
}
|
}
|
||||||
showFilter.value = false;
|
showFilter.value = false;
|
||||||
getJobList("refresh");
|
getJobList('refresh');
|
||||||
},
|
},
|
||||||
cancel: () => {
|
cancel: () => {
|
||||||
showFilter.value = false;
|
showFilter.value = false;
|
||||||
emits("onShowTabbar", true);
|
emits('onShowTabbar', true);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -449,31 +532,31 @@ function handleFilterConfirm(e) {
|
|||||||
function choosePosition(index) {
|
function choosePosition(index) {
|
||||||
state.tabIndex = index;
|
state.tabIndex = index;
|
||||||
list.value = [];
|
list.value = [];
|
||||||
if (index === "all") {
|
if (index === 'all') {
|
||||||
pageState.search = {
|
pageState.search = {
|
||||||
order: pageState.search.order,
|
order: pageState.search.order,
|
||||||
};
|
};
|
||||||
inputText.value = "";
|
inputText.value = '';
|
||||||
getJobRecommend("refresh");
|
getJobRecommend('refresh');
|
||||||
} else {
|
} else {
|
||||||
// const id = useUserStore().userInfo.jobTitleId.split(',')[index];
|
// const id = useUserStore().userInfo.jobTitleId.split(',')[index];
|
||||||
pageState.search.jobTitle = userInfo.value.jobTitle[index];
|
pageState.search.jobTitle = userInfo.value.jobTitle[index];
|
||||||
inputText.value = "";
|
inputText.value = '';
|
||||||
getJobList("refresh");
|
getJobList('refresh');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handelHostestSearch(val) {
|
function handelHostestSearch(val) {
|
||||||
pageState.search.order = val.value;
|
pageState.search.order = val.value;
|
||||||
if (state.tabIndex === "all") {
|
if (state.tabIndex === 'all') {
|
||||||
getJobRecommend("refresh");
|
getJobRecommend('refresh');
|
||||||
} else {
|
} else {
|
||||||
getJobList("refresh");
|
getJobList('refresh');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getJobRecommend(type = "add") {
|
function getJobRecommend(type = 'add') {
|
||||||
if (type === "refresh") {
|
if (type === 'refresh') {
|
||||||
list.value = [];
|
list.value = [];
|
||||||
if (waterfallsFlowRef.value) waterfallsFlowRef.value.refresh();
|
if (waterfallsFlowRef.value) waterfallsFlowRef.value.refresh();
|
||||||
}
|
}
|
||||||
@@ -485,13 +568,13 @@ function getJobRecommend(type = "add") {
|
|||||||
};
|
};
|
||||||
let comd = {
|
let comd = {
|
||||||
recommend: true,
|
recommend: true,
|
||||||
jobCategory: "",
|
jobCategory: '',
|
||||||
tip: "确认你的兴趣,为您推荐更多合适的岗位",
|
tip: '确认你的兴趣,为您推荐更多合适的岗位',
|
||||||
};
|
};
|
||||||
$api.createRequest("/app/job/recommend", params).then((resData) => {
|
$api.createRequest('/app/job/recommend', params).then((resData) => {
|
||||||
const { data, total } = resData;
|
const { data, total } = resData;
|
||||||
pageState.total = 0;
|
pageState.total = 0;
|
||||||
if (type === "add") {
|
if (type === 'add') {
|
||||||
// 记录系统
|
// 记录系统
|
||||||
recommedIndexDb.getRecord().then((res) => {
|
recommedIndexDb.getRecord().then((res) => {
|
||||||
if (res.length) {
|
if (res.length) {
|
||||||
@@ -518,11 +601,11 @@ function getJobRecommend(type = "add") {
|
|||||||
list.value = dataToImg(data);
|
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) {
|
if (data.length < pageState.pageSize) {
|
||||||
loadmoreRef.value.change("noMore");
|
loadmoreRef.value.change('noMore');
|
||||||
} else {
|
} else {
|
||||||
loadmoreRef.value.change("more");
|
loadmoreRef.value.change('more');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 当没有岗位,刷新sessionId重新啦
|
// 当没有岗位,刷新sessionId重新啦
|
||||||
@@ -532,11 +615,11 @@ function getJobRecommend(type = "add") {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getJobList(type = "add") {
|
function getJobList(type = 'add') {
|
||||||
if (type === "add" && pageState.page < pageState.maxPage) {
|
if (type === 'add' && pageState.page < pageState.maxPage) {
|
||||||
pageState.page += 1;
|
pageState.page += 1;
|
||||||
}
|
}
|
||||||
if (type === "refresh") {
|
if (type === 'refresh') {
|
||||||
list.value = [];
|
list.value = [];
|
||||||
pageState.page = 1;
|
pageState.page = 1;
|
||||||
pageState.maxPage = 2;
|
pageState.maxPage = 2;
|
||||||
@@ -550,9 +633,9 @@ function getJobList(type = "add") {
|
|||||||
// ...conditionSearch.value,
|
// ...conditionSearch.value,
|
||||||
};
|
};
|
||||||
|
|
||||||
$api.createRequest("/app/job/list", params).then((resData) => {
|
$api.createRequest('/app/job/list', params).then((resData) => {
|
||||||
const { rows, total } = resData;
|
const { rows, total } = resData;
|
||||||
if (type === "add") {
|
if (type === 'add') {
|
||||||
const str = pageState.pageSize * (pageState.page - 1);
|
const str = pageState.pageSize * (pageState.page - 1);
|
||||||
const end = list.value.length;
|
const end = list.value.length;
|
||||||
const reslist = dataToImg(rows);
|
const reslist = dataToImg(rows);
|
||||||
@@ -563,11 +646,11 @@ function getJobList(type = "add") {
|
|||||||
pageState.total = resData.total;
|
pageState.total = resData.total;
|
||||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
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) {
|
if (rows.length < pageState.pageSize) {
|
||||||
loadmoreRef.value?.change("noMore");
|
loadmoreRef.value?.change('noMore');
|
||||||
} else {
|
} else {
|
||||||
loadmoreRef.value?.change("more");
|
loadmoreRef.value?.change('more');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ onLoad(() => {
|
|||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
// 获取消息列表
|
// 获取消息列表
|
||||||
useReadMsg().fetchMessages();
|
// useReadMsg().fetchMessages();
|
||||||
});
|
});
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ const { getDictSelectOption, oneDictData } = useDictStore();
|
|||||||
const openSelectPopup = inject('openSelectPopup');
|
const openSelectPopup = inject('openSelectPopup');
|
||||||
// status
|
// status
|
||||||
const selectJobsModel = ref();
|
const selectJobsModel = ref();
|
||||||
const tabCurrent = ref(0);
|
const tabCurrent = ref(1);
|
||||||
const salay = [2, 5, 10, 15, 20, 25, 30, 50, 80, 100];
|
const salay = [2, 5, 10, 15, 20, 25, 30, 50, 80, 100];
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
station: [],
|
station: [],
|
||||||
@@ -150,7 +150,7 @@ const fromValue = reactive({
|
|||||||
});
|
});
|
||||||
|
|
||||||
onLoad((parmas) => {
|
onLoad((parmas) => {
|
||||||
// getTreeselect();
|
getTreeselect();
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {});
|
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 config from "@/config.js"
|
||||||
|
import {
|
||||||
|
sm2_Decrypt,
|
||||||
|
sm2_Encrypt
|
||||||
|
} from '@/common/globalFunction';
|
||||||
import useUserStore from '@/stores/useUserStore';
|
import useUserStore from '@/stores/useUserStore';
|
||||||
import {
|
import {
|
||||||
sm4Decrypt,
|
sm4Decrypt,
|
||||||
|
|||||||
Reference in New Issue
Block a user