Compare commits
26 Commits
8e316cf2a1
...
main-ALL-I
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c29882f36 | |||
| 4cf75922da | |||
| bb67e9ba12 | |||
|
|
7479176eff | ||
|
|
3fe0a1b9e1 | ||
| 284d696b25 | |||
| 85a24d3346 | |||
| 854bc9c197 | |||
|
|
606b6104bb | ||
|
|
a10fd29440 | ||
|
|
ab3201b015 | ||
|
|
8420d265e1 | ||
| a30a302e90 | |||
|
|
3d826aec86 | ||
| 8b9f7890af | |||
| 32e147e601 | |||
| 8ccdcbf93b | |||
| 01d817f99c | |||
| 137542a92f | |||
| cd9c3acfc0 | |||
|
|
80213b18e9 | ||
| 4a03b4d4cb | |||
|
|
77dfab84f1 | ||
| 33f1d0a8ab | |||
| 92d87347d0 | |||
| add2cfeac4 |
131
App.vue
@@ -1,36 +1,57 @@
|
||||
<script setup>
|
||||
import { reactive, inject, onMounted } from 'vue';
|
||||
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app';
|
||||
import { IncreaseRevie } from '@/common/all-in-one-listen.js';
|
||||
import useUserStore from './stores/useUserStore';
|
||||
import usePageAnimation from './hook/usePageAnimation';
|
||||
import useDictStore from './stores/useDictStore';
|
||||
import { GlobalInactivityManager } from '@/utils/GlobalInactivityManager';
|
||||
const { $api, navTo, appendScriptTagElement, aes_Decrypt, sm2_Decrypt, safeReLaunch } = inject('globalFunction');
|
||||
import config from '@/config.js';
|
||||
import baseDB from '@/utils/db.js';
|
||||
import { $confirm } from '@/utils/modal.js';
|
||||
import useLocationStore from '@/stores/useLocationStore';
|
||||
usePageAnimation();
|
||||
const appword = 'aKd20dbGdFvmuwrt'; // 固定值
|
||||
let uQRListen = null;
|
||||
let inactivityManager = null;
|
||||
let inactivityModalTimer = null;
|
||||
|
||||
onLaunch((options) => {
|
||||
useDictStore().getDictData();
|
||||
try {
|
||||
if (lightAppJssdk.user) {
|
||||
console.warn('爱山东环境');
|
||||
getUserInfo();
|
||||
useUserStore().changMiniProgramAppStatus(false);
|
||||
} catch {
|
||||
console.log('不是爱山东平台,使用测试登陆');
|
||||
useUserStore().changMachineEnv(false);
|
||||
return;
|
||||
}
|
||||
if (isY9MachineType()) {
|
||||
console.warn('求职一体机环境');
|
||||
baseDB.resetAndReinit(); // 清空indexdb
|
||||
useUserStore().logOutApp();
|
||||
useUserStore().changMiniProgramAppStatus(true);
|
||||
useUserStore().initSeesionId(); //更新
|
||||
let token = uni.getStorageSync('token') || ''; // 同步获取 缓存信息
|
||||
if (token) {
|
||||
useUserStore()
|
||||
.loginSetToken(token)
|
||||
.then(() => {
|
||||
$api.msg('登录成功');
|
||||
});
|
||||
} else {
|
||||
safeReLaunch('/pages/login/login');
|
||||
// uni.redirectTo({
|
||||
// url: '/pages/login/login',
|
||||
// });
|
||||
}
|
||||
useUserStore().changMachineEnv(true);
|
||||
useLocationStore().getLocation();
|
||||
uQRListen = new IncreaseRevie();
|
||||
inactivityManager = new GlobalInactivityManager(handleInactivity, 60 * 1000);
|
||||
inactivityManager.start();
|
||||
return;
|
||||
}
|
||||
// 正式上线去除此方法
|
||||
console.warn('浏览器环境');
|
||||
useUserStore().changMiniProgramAppStatus(true);
|
||||
useUserStore().changMachineEnv(false);
|
||||
useUserStore().initSeesionId(); //更新
|
||||
let token = uni.getStorageSync('token') || '';
|
||||
if (token) {
|
||||
useUserStore()
|
||||
.loginSetToken(token)
|
||||
.then(() => {
|
||||
$api.msg('登录成功');
|
||||
});
|
||||
} else {
|
||||
safeReLaunch('/pages/login/login');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -44,6 +65,68 @@ onHide(() => {
|
||||
console.log('App Hide');
|
||||
});
|
||||
|
||||
function handleInactivity() {
|
||||
console.log('【全局】60秒无操作,执行安全逻辑');
|
||||
if (inactivityModalTimer) {
|
||||
clearTimeout(inactivityModalTimer);
|
||||
inactivityModalTimer = null;
|
||||
}
|
||||
|
||||
if (useUserStore().hasLogin) {
|
||||
// 1. 正常弹出确认框
|
||||
$confirm({
|
||||
title: '会话即将过期',
|
||||
content: '长时间无操作,是否继续使用?',
|
||||
success: (res) => {
|
||||
if (inactivityModalTimer) {
|
||||
clearTimeout(inactivityModalTimer);
|
||||
inactivityModalTimer = null;
|
||||
}
|
||||
if (res.confirm) {
|
||||
inactivityManager?.resume();
|
||||
} else {
|
||||
performLogout();
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
if (inactivityModalTimer) {
|
||||
clearTimeout(inactivityModalTimer);
|
||||
inactivityModalTimer = null;
|
||||
}
|
||||
performLogout();
|
||||
},
|
||||
});
|
||||
|
||||
// 2. 启动 10 秒倒计时
|
||||
inactivityModalTimer = setTimeout(() => {
|
||||
inactivityModalTimer = null;
|
||||
console.log('【自动登出】10秒无响应,强制清理状态');
|
||||
|
||||
// 【关键改进】:通知全局组件强制关闭弹窗,防止用户点击陈旧弹窗
|
||||
uni.$emit('hide-global-popup');
|
||||
|
||||
performLogout();
|
||||
}, 10000);
|
||||
} else {
|
||||
inactivityManager?.resume();
|
||||
}
|
||||
}
|
||||
|
||||
function performLogout() {
|
||||
uni.clearStorageSync();
|
||||
baseDB.resetAndReinit();
|
||||
useUserStore().logOutApp();
|
||||
inactivityManager?.resume(); // 恢复监听
|
||||
}
|
||||
|
||||
// 一体机环境判断
|
||||
function isY9MachineType() {
|
||||
const ua = navigator.userAgent;
|
||||
const isY9Machine = /Y9-ZYYH/i.test(ua); // 匹配机器型号
|
||||
return isY9Machine;
|
||||
}
|
||||
|
||||
// 爱山东环境登录
|
||||
function getUserInfo() {
|
||||
lightAppJssdk.user.getUserInfoWithEncryptedParamByAppId({
|
||||
appId: config.appInfo.loveShandong, // 接入方在成功创建应用后自动生成
|
||||
@@ -110,15 +193,9 @@ function loginCallback(userInfo) {
|
||||
.then((resume) => {
|
||||
if (resume.data.jobTitleId) {
|
||||
useUserStore().initSeesionId();
|
||||
// uni.reLaunch({
|
||||
// url: '/pages/index/index',
|
||||
// });
|
||||
safeReLaunch('/pages/index/index');
|
||||
} else {
|
||||
safeReLaunch('/pages/login/login');
|
||||
// uni.redirectTo({
|
||||
// url: '/pages/login/login',
|
||||
// });
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -130,7 +207,6 @@ function loginCallback(userInfo) {
|
||||
@import '@/common/animation.css';
|
||||
@import '@/common/common.css';
|
||||
|
||||
|
||||
/* 修改pages tabbar样式 H5才有效 */
|
||||
.uni-tabbar .uni-tabbar__item:nth-child(4) .uni-tabbar__bd .uni-tabbar__icon {
|
||||
width: 108rpx !important;
|
||||
@@ -163,7 +239,6 @@ uni-modal,
|
||||
z-index: 998;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: DingTalk JinBuTi;
|
||||
src: url('/static/font/DingTalk JinBuTi_min.woff2') format('woff2');
|
||||
@@ -172,19 +247,19 @@ uni-modal,
|
||||
|
||||
@font-face {
|
||||
font-family: PingFangSC-Regular;
|
||||
src: url('https://qd.zhaopinzao8dian.com/file/csn/PingFangSC-Regular.woff2') format('woff2');
|
||||
src: url('/static/font/PingFangSC-Regular.woff2') format('woff2');
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: PingFangSC-Medium;
|
||||
src: url('https://qd.zhaopinzao8dian.com/file/csn/PingFangSC-Medium.woff2') format('woff2');
|
||||
src: url('/static/font/PingFangSC-Medium.woff2') format('woff2');
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: DIN-Medium;
|
||||
src: url('https://qd.zhaopinzao8dian.com/file/csn/DIN-Medium.woff2') format('woff2');
|
||||
src: url('/static/font/DIN-Medium.woff2') format('woff2');
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
|
||||
65
common/all-in-one-listen.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import {
|
||||
$api
|
||||
} from "./globalFunction";
|
||||
import baseDB from '@/utils/db.js';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
|
||||
export class IncreaseRevie {
|
||||
constructor(arg) {
|
||||
this.myEventCallback = this.myCallback.bind(this);
|
||||
this._debounceTimer = null;
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.close();
|
||||
setTimeout(() => {
|
||||
if (window.hh?.on) {
|
||||
window.hh.on('initQRListener', this.myEventCallback);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
close() {
|
||||
if (window.hh?.off) {
|
||||
window.hh.off('initQRListener', this.myEventCallback);
|
||||
}
|
||||
if (this._debounceTimer) {
|
||||
clearTimeout(this._debounceTimer);
|
||||
this._debounceTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
myCallback(res) {
|
||||
if (this._debounceTimer) {
|
||||
clearTimeout(this._debounceTimer);
|
||||
}
|
||||
|
||||
this._debounceTimer = setTimeout(() => {
|
||||
this.handleDebouncedCallback(res);
|
||||
this._debounceTimer = null;
|
||||
}, 300);
|
||||
}
|
||||
|
||||
async handleDebouncedCallback(res) {
|
||||
if (res.data) {
|
||||
const code = res.data.qrQode
|
||||
console.log('二维码code', code);
|
||||
// 把code给到后端,后端拿code兑换用户信息,给前端返回token进行登录
|
||||
// 一体机用户需要清空indexDB
|
||||
// useUserStore()
|
||||
// .loginSetToken(resData.token)
|
||||
// .then((resume) => {
|
||||
// if (resume.data.jobTitleId) {
|
||||
// useUserStore().initSeesionId();
|
||||
// safeReLaunch('/pages/index/index');
|
||||
// } else {
|
||||
// safeReLaunch('/pages/login/login');
|
||||
// }
|
||||
// });
|
||||
// baseDB.resetAndReinit(); // 清空indexdb
|
||||
} else {
|
||||
$api.msg('识别失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,3 +30,15 @@ uni-toast .uni-toast__content {
|
||||
font-size: 30rpx !important;
|
||||
}
|
||||
|
||||
uni-modal .uni-modal{
|
||||
max-width: 450rpx !important;
|
||||
}
|
||||
|
||||
uni-modal .uni-modal__bd{
|
||||
font-size: 34rpx !important;
|
||||
min-height: 100rpx !important;
|
||||
}
|
||||
uni-modal .uni-modal__ft{
|
||||
font-size: 36rpx !important;
|
||||
line-height: 80rpx !important;
|
||||
}
|
||||
|
||||
115
components/GlobalPopup/GlobalPopup.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<uni-popup ref="popup" type="dialog" mask-background-color="rgba(0,0,0,0.5)" @change="onPopupChange">
|
||||
<view class="global-confirm-wrapper">
|
||||
<uni-popup-dialog
|
||||
mode="base"
|
||||
:type="state.type"
|
||||
:title="state.title"
|
||||
:content="state.content"
|
||||
:before-close="true"
|
||||
@confirm="onConfirm"
|
||||
@close="onClose"
|
||||
></uni-popup-dialog>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, onUnmounted } from 'vue';
|
||||
|
||||
const popup = ref(null);
|
||||
const state = reactive({
|
||||
title: '',
|
||||
content: '',
|
||||
type: 'info',
|
||||
resolve: null,
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
uni.$on('show-global-popup', (options) => {
|
||||
state.title = options.title || '提示';
|
||||
state.content = options.content || '';
|
||||
state.type = options.type || 'info';
|
||||
state.resolve = options.resolve;
|
||||
popup.value.open();
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
uni.$off('show-global-popup');
|
||||
});
|
||||
|
||||
const onConfirm = () => {
|
||||
if (state.resolve) state.resolve(true);
|
||||
popup.value.close();
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
if (state.resolve) state.resolve(false);
|
||||
popup.value.close();
|
||||
};
|
||||
|
||||
const onPopupChange = (e) => {
|
||||
if (!e.show && state.resolve) {
|
||||
state.resolve(false);
|
||||
state.resolve = null;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.global-confirm-wrapper {
|
||||
/* 整个弹窗容器宽度自适应 */
|
||||
width: 600rpx;
|
||||
|
||||
/* 深度覆盖 uni-popup-dialog 内置样式 */
|
||||
:deep(.uni-popup-dialog) {
|
||||
width: 600rpx !important;
|
||||
background-color: #fff;
|
||||
border-radius: 24rpx;
|
||||
|
||||
/* 标题部分 */
|
||||
.uni-dialog-title {
|
||||
padding: 40rpx 0 20rpx;
|
||||
.uni-dialog-title-text {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
/* 内容部分 */
|
||||
.uni-dialog-content {
|
||||
padding: 20rpx 40rpx 40rpx;
|
||||
.uni-dialog-content-text {
|
||||
font-size: 30rpx;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* 底部按钮组 */
|
||||
.uni-dialog-button-group {
|
||||
height: 100rpx;
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
|
||||
.uni-dialog-button {
|
||||
height: 100%;
|
||||
/* 每个按钮的样式 */
|
||||
.uni-dialog-button-text {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
/* 确定按钮颜色(通常是蓝色或主题色) */
|
||||
.uni-button-color {
|
||||
color: #007aff;
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮中间的分割线 */
|
||||
.uni-border-left {
|
||||
border-left: 1rpx solid #f0f0f0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -19,11 +19,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import { useReadMsg } from '@/stores/useReadMsg';
|
||||
|
||||
import useScreenStore from '@/stores/useScreenStore'
|
||||
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
const { isMachineEnv } = storeToRefs(useUserStore());
|
||||
|
||||
const screenStore = useScreenStore()
|
||||
const {isWideScreen} = screenStore
|
||||
|
||||
@@ -72,6 +75,7 @@ const tabbarList = computed(() => [
|
||||
selectedIconPath: '../../static/tabbar/chat4ed.png',
|
||||
centerItem: false,
|
||||
badge: readMsg.badges[3].count,
|
||||
needLogin:true,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
@@ -81,6 +85,7 @@ const tabbarList = computed(() => [
|
||||
selectedIconPath: '../../static/tabbar/mined.png',
|
||||
centerItem: false,
|
||||
badge: readMsg.badges[4].count,
|
||||
needLogin:true,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -90,9 +95,14 @@ onMounted(() => {
|
||||
});
|
||||
|
||||
const changeItem = (item) => {
|
||||
uni.switchTab({
|
||||
url: item.path,
|
||||
});
|
||||
if(isMachineEnv.value && item.needLogin){
|
||||
useUserStore().logOut()
|
||||
}else{
|
||||
uni.switchTab({
|
||||
url: item.path,
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
13
config.js
@@ -1,14 +1,15 @@
|
||||
export default {
|
||||
baseUrl: 'https://fw.rc.qingdao.gov.cn/rgpp-api/api', // 内网
|
||||
// baseUrl: 'https://qd.zhaopinzao8dian.com/api', // 测试
|
||||
// baseUrl: 'https://fw.rc.qingdao.gov.cn/rgpp-api/api', // 内网
|
||||
baseUrl: 'https://qd.zhaopinzao8dian.com/api', // 测试
|
||||
// baseUrl: 'http://192.168.3.29:8081',
|
||||
// baseUrl: 'http://10.213.6.207:19010/api',
|
||||
// 语音转文字
|
||||
// vioceBaseURl: 'wss://qd.zhaopinzao8dian.com/api/system/asr/connect', // 自定义
|
||||
vioceBaseURl: 'wss://fw.rc.qingdao.gov.cn/rgpp-api/api/system/asr/connect', // 内网
|
||||
vioceBaseURl: 'wss://qd.zhaopinzao8dian.com/api/app/asr/connect', // 自定义
|
||||
// vioceBaseURl: 'wss://fw.rc.qingdao.gov.cn/rgpp-api/api/app/asr/connect', // 内网
|
||||
// 语音合成
|
||||
speechSynthesis: 'wss://qd.zhaopinzao8dian.com/api/speech-synthesis',
|
||||
// speechSynthesis: 'wss://qd.zhaopinzao8dian.com/api/speech-synthesis',
|
||||
speechSynthesis2: 'wss://resource.zhuoson.com/synthesis/', //直接替换即可
|
||||
// speechSynthesis2: 'http://39.98.44.136:19527', //直接替换即可
|
||||
// indexedDB
|
||||
DBversion: 3,
|
||||
// 只使用本地缓寸的数据
|
||||
@@ -58,7 +59,7 @@ export default {
|
||||
allowedFileTypes: [
|
||||
"text/plain", // .txt
|
||||
"text/markdown", // .md
|
||||
"text/html", // .html
|
||||
// "text/html", // .html
|
||||
"application/msword", // .doc
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document", // .docx
|
||||
"application/pdf", // .pdf
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
export class PiperTTS {
|
||||
constructor(config = {}) {
|
||||
this.baseUrl = config.baseUrl || 'http://localhost:5001';
|
||||
this.wsUrl = config.wsUrl || '/ws/synthesize'
|
||||
this.audioCtx = config.audioCtx || new(window.AudioContext || window.webkitAudioContext)();
|
||||
this.onStatus = config.onStatus || ((msg, type) => console.log(`[Piper] ${msg}`));
|
||||
this.onStart = config.onStart || (() => {});
|
||||
this.onEnd = config.onEnd || (() => {});
|
||||
|
||||
|
||||
// 内部状态
|
||||
this.ws = null;
|
||||
this.nextTime = 0; // 下一段音频的预定播放时间
|
||||
@@ -56,7 +58,7 @@ export class PiperTTS {
|
||||
this.onStatus('正在建立连接...', 'processing');
|
||||
|
||||
try {
|
||||
const wsUrl = this.baseUrl.replace(/^http/, 'ws') + '/ws/synthesize';
|
||||
const wsUrl = this.baseUrl.replace(/^http/, 'ws') + this.wsUrl;
|
||||
this.ws = new WebSocket(wsUrl);
|
||||
this.ws.binaryType = 'arraybuffer';
|
||||
|
||||
|
||||
@@ -22,17 +22,19 @@
|
||||
<script>
|
||||
eruda.init();
|
||||
</script> -->
|
||||
|
||||
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||
<script>
|
||||
// VConsole 默认会挂载到 `window.VConsole` 上
|
||||
var vConsole = new window.VConsole();
|
||||
</script>
|
||||
<!-- 爱山东jssdk 本sdk存在性能问题 -->
|
||||
<script type="text/javascript" src="./static/js/jsbridge.js"></script>
|
||||
<!-- <script type="text/javascript" src="./static/js/jweixin-1.4.0.js"></script> -->
|
||||
<script type="text/javascript" src="https://isdapp.shandong.gov.cn/jmopen/jssdk/index.js"></script>
|
||||
<!-- 只在内网有效 -->
|
||||
<script type="text/javascript" src="./static/js/SM.js"></script>
|
||||
<script type="text/javascript" src="./static/js/pixi.min.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"><!--app-html--></div>
|
||||
|
||||
6
main.js
@@ -8,6 +8,7 @@ import '@/lib/string-similarity.min.js'
|
||||
import similarityJobs from '@/utils/similarity_Job.js';
|
||||
import useScreenStore from './stores/useScreenStore'
|
||||
|
||||
|
||||
// 组件
|
||||
import AppLayout from './components/AppLayout/AppLayout.vue';
|
||||
import Empty from './components/empty/empty.vue';
|
||||
@@ -24,6 +25,7 @@ import renderJobCollectionRecord from '@/components/renderJobCollectionRecord/re
|
||||
import renderCompanyCollectionRecord from '@/components/renderCompanyCollectionRecord/renderCompanyCollectionRecord.vue';
|
||||
import renderJobViewRecord from '@/components/renderJobViewRecord/renderJobViewRecord.vue';
|
||||
import MyIcons from '@/components/My-icons/my-icons.vue';
|
||||
import GlobalPopup from '@/components/GlobalPopup/GlobalPopup.vue'
|
||||
// import Tabbar from '@/components/tabbar/midell-box.vue'
|
||||
// 自动导入 directives 目录下所有指令
|
||||
console.log(lightAppJssdk)
|
||||
@@ -54,7 +56,8 @@ export function createApp() {
|
||||
app.component('renderJobCollectionRecord', renderJobCollectionRecord) //渲染岗位收藏记录
|
||||
app.component('renderCompanyCollectionRecord', renderCompanyCollectionRecord) //渲染公司收藏记录
|
||||
app.component('renderJobViewRecord', renderJobViewRecord) //渲染岗位浏览记录
|
||||
app.component('MyIcons', MyIcons)
|
||||
app.component('MyIcons', MyIcons)
|
||||
app.component('global-popup', GlobalPopup)
|
||||
// app.component('tabbar-custom', Tabbar)
|
||||
|
||||
for (const path in directives) {
|
||||
@@ -68,6 +71,7 @@ export function createApp() {
|
||||
...globalFunction,
|
||||
similarityJobs
|
||||
});
|
||||
|
||||
app.provide('deviceInfo', globalFunction.getdeviceInfo());
|
||||
|
||||
app.use(SelectPopupPlugin);
|
||||
|
||||
210
manifest.json
@@ -1,105 +1,105 @@
|
||||
{
|
||||
"name": "qingdao-employment-service",
|
||||
"appid": "__UNI__C939371",
|
||||
"description": "招聘",
|
||||
"versionName": "1.0.0",
|
||||
"versionCode": "100",
|
||||
"transformPx": false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus": {
|
||||
"usingComponents": true,
|
||||
"nvueStyleCompiler": "uni-app",
|
||||
"compilerVersion": 3,
|
||||
"splashscreen": {
|
||||
"alwaysShowBeforeRender": true,
|
||||
"waiting": true,
|
||||
"autoclose": true,
|
||||
"delay": 0
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules": {},
|
||||
/* 应用发布信息 */
|
||||
"distribute": {
|
||||
/* android打包配置 */
|
||||
"android": {
|
||||
"permissions": [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||
]
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios": {},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs": {}
|
||||
}
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
"quickapp": {},
|
||||
/* 小程序特有相关 */
|
||||
"mp-weixin": {
|
||||
"appid": "",
|
||||
"setting": {
|
||||
"urlCheck": false,
|
||||
"es6": true,
|
||||
"postcss": true,
|
||||
"minified": true
|
||||
},
|
||||
"usingComponents": true,
|
||||
"permission": {
|
||||
"scope.userLocation": {
|
||||
"desc": "用于用户选择地图查看位置"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mp-alipay": {
|
||||
"usingComponents": true
|
||||
},
|
||||
"mp-baidu": {
|
||||
"usingComponents": true
|
||||
},
|
||||
"mp-toutiao": {
|
||||
"usingComponents": true
|
||||
},
|
||||
"uniStatistics": {
|
||||
"enable": false
|
||||
},
|
||||
"vueVersion": "3",
|
||||
"locale": "zh-Hans",
|
||||
"h5": {
|
||||
"router": {
|
||||
"base": "./",
|
||||
"mode": "hash"
|
||||
},
|
||||
"title": "青岛智慧就业服务",
|
||||
"optimization": {
|
||||
"treeShaking": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"sdkConfigs": {
|
||||
"maps": {
|
||||
"amap": {
|
||||
"key": "9cfc9370bd8a941951da1cea0308e9e3",
|
||||
"securityJsCode": "7b16386c7f744c3ca05595965f2b037f",
|
||||
"serviceHost": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"devServer": {
|
||||
"https": false
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
"name" : "qingdao-employment-service",
|
||||
"appid" : "__UNI__2496162",
|
||||
"description" : "招聘",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
"transformPx" : false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
"usingComponents" : true,
|
||||
"nvueStyleCompiler" : "uni-app",
|
||||
"compilerVersion" : 3,
|
||||
"splashscreen" : {
|
||||
"alwaysShowBeforeRender" : true,
|
||||
"waiting" : true,
|
||||
"autoclose" : true,
|
||||
"delay" : 0
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules" : {},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
/* android打包配置 */
|
||||
"android" : {
|
||||
"permissions" : [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||
]
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios" : {},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs" : {}
|
||||
}
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
"quickapp" : {},
|
||||
/* 小程序特有相关 */
|
||||
"mp-weixin" : {
|
||||
"appid" : "",
|
||||
"setting" : {
|
||||
"urlCheck" : false,
|
||||
"es6" : true,
|
||||
"postcss" : true,
|
||||
"minified" : true
|
||||
},
|
||||
"usingComponents" : true,
|
||||
"permission" : {
|
||||
"scope.userLocation" : {
|
||||
"desc" : "用于用户选择地图查看位置"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mp-alipay" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-baidu" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-toutiao" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
},
|
||||
"vueVersion" : "3",
|
||||
"locale" : "zh-Hans",
|
||||
"h5" : {
|
||||
"router" : {
|
||||
"base" : "./",
|
||||
"mode" : "hash"
|
||||
},
|
||||
"title" : "青岛智慧就业服务",
|
||||
"optimization" : {
|
||||
"treeShaking" : {
|
||||
"enable" : true
|
||||
}
|
||||
},
|
||||
"sdkConfigs" : {
|
||||
"maps" : {
|
||||
"amap" : {
|
||||
"key" : "9cfc9370bd8a941951da1cea0308e9e3",
|
||||
"securityJsCode" : "7b16386c7f744c3ca05595965f2b037f",
|
||||
"serviceHost" : ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"devServer" : {
|
||||
"https" : false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
970
package-lock.json
generated
Normal file
@@ -0,0 +1,970 @@
|
||||
{
|
||||
"name": "qingdao-employment-service",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"devDependencies": {
|
||||
"unplugin-vue-components": "^0.26.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@antfu/utils": {
|
||||
"version": "0.7.10",
|
||||
"resolved": "https://registry.npmmirror.com/@antfu/utils/-/utils-0.7.10.tgz",
|
||||
"integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
"version": "7.27.1",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
|
||||
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.28.5",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
|
||||
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.28.5",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.28.5.tgz",
|
||||
"integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.28.5"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.28.5",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.5.tgz",
|
||||
"integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.27.1",
|
||||
"@babel/helper-validator-identifier": "^7.28.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "2.0.5",
|
||||
"run-parallel": "^1.1.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.stat": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
|
||||
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.walk": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
|
||||
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nodelib/fs.scandir": "2.1.5",
|
||||
"fastq": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/pluginutils": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.3.0.tgz",
|
||||
"integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"rollup": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.5.25",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.25.tgz",
|
||||
"integrity": "sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.28.5",
|
||||
"@vue/shared": "3.5.25",
|
||||
"entities": "^4.5.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.5.25",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.25.tgz",
|
||||
"integrity": "sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.5.25",
|
||||
"@vue/shared": "3.5.25"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "3.5.25",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.25.tgz",
|
||||
"integrity": "sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.28.5",
|
||||
"@vue/compiler-core": "3.5.25",
|
||||
"@vue/compiler-dom": "3.5.25",
|
||||
"@vue/compiler-ssr": "3.5.25",
|
||||
"@vue/shared": "3.5.25",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.21",
|
||||
"postcss": "^8.5.6",
|
||||
"source-map-js": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.5.25",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.25.tgz",
|
||||
"integrity": "sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.25",
|
||||
"@vue/shared": "3.5.25"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity": {
|
||||
"version": "3.5.25",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.25.tgz",
|
||||
"integrity": "sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/shared": "3.5.25"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-core": {
|
||||
"version": "3.5.25",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.25.tgz",
|
||||
"integrity": "sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.5.25",
|
||||
"@vue/shared": "3.5.25"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-dom": {
|
||||
"version": "3.5.25",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.25.tgz",
|
||||
"integrity": "sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.5.25",
|
||||
"@vue/runtime-core": "3.5.25",
|
||||
"@vue/shared": "3.5.25",
|
||||
"csstype": "^3.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/server-renderer": {
|
||||
"version": "3.5.25",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.25.tgz",
|
||||
"integrity": "sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-ssr": "3.5.25",
|
||||
"@vue/shared": "3.5.25"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "3.5.25"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
"version": "3.5.25",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.25.tgz",
|
||||
"integrity": "sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/anymatch/node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fill-range": "^7.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz",
|
||||
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-walker": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz",
|
||||
"integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
"@nodelib/fs.walk": "^1.2.3",
|
||||
"glob-parent": "^5.1.2",
|
||||
"merge2": "^1.3.0",
|
||||
"micromatch": "^4.0.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fastq": {
|
||||
"version": "1.19.1",
|
||||
"resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.19.1.tgz",
|
||||
"integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.16.1",
|
||||
"resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz",
|
||||
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/local-pkg": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-0.4.3.tgz",
|
||||
"integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.21",
|
||||
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz",
|
||||
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz",
|
||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz",
|
||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"braces": "^3.0.3",
|
||||
"picomatch": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/micromatch/node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz",
|
||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz",
|
||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp/node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.11",
|
||||
"resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.11.tgz",
|
||||
"integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.16.1",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"resolve": "bin/resolve"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/reusify": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.1.0.tgz",
|
||||
"integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"iojs": ">=1.0.0",
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"queue-microtask": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-preserve-symlinks-flag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unplugin": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmmirror.com/unplugin/-/unplugin-1.16.1.tgz",
|
||||
"integrity": "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"acorn": "^8.14.0",
|
||||
"webpack-virtual-modules": "^0.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unplugin-vue-components": {
|
||||
"version": "0.26.0",
|
||||
"resolved": "https://registry.npmmirror.com/unplugin-vue-components/-/unplugin-vue-components-0.26.0.tgz",
|
||||
"integrity": "sha512-s7IdPDlnOvPamjunVxw8kNgKNK8A5KM1YpK5j/p97jEKTjlPNrA0nZBiSfAKKlK1gWZuyWXlKL5dk3EDw874LQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@antfu/utils": "^0.7.6",
|
||||
"@rollup/pluginutils": "^5.0.4",
|
||||
"chokidar": "^3.5.3",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.1",
|
||||
"local-pkg": "^0.4.3",
|
||||
"magic-string": "^0.30.3",
|
||||
"minimatch": "^9.0.3",
|
||||
"resolve": "^1.22.4",
|
||||
"unplugin": "^1.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/parser": "^7.15.8",
|
||||
"@nuxt/kit": "^3.2.2",
|
||||
"vue": "2 || 3"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@babel/parser": {
|
||||
"optional": true
|
||||
},
|
||||
"@nuxt/kit": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.5.25",
|
||||
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.25.tgz",
|
||||
"integrity": "sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.25",
|
||||
"@vue/compiler-sfc": "3.5.25",
|
||||
"@vue/runtime-dom": "3.5.25",
|
||||
"@vue/server-renderer": "3.5.25",
|
||||
"@vue/shared": "3.5.25"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-virtual-modules": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
|
||||
"integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
5
package.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"unplugin-vue-components": "^0.26.0"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template>
|
||||
<view v-show="searchFocus" class="search-mask" ></view>
|
||||
<view class="main">
|
||||
<view class="content-title">
|
||||
<view class="title-lf">
|
||||
@@ -74,7 +75,7 @@ const { $api, navBack } = inject('globalFunction');
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
const { getUserResume } = useUserStore();
|
||||
const { userInfo, isMiniProgram } = storeToRefs(useUserStore());
|
||||
const { userInfo, isMiniProgram ,hasLogin,isMachineEnv} = storeToRefs(useUserStore());
|
||||
const popup = ref(null);
|
||||
const selectJobsModel = ref(null);
|
||||
|
||||
@@ -83,6 +84,7 @@ const dataSource = ref([]);
|
||||
const filterList = ref([]);
|
||||
const dataItem = ref(null);
|
||||
const inputVal = ref('');
|
||||
const searchFocus = ref(false);
|
||||
|
||||
onLoad(() => {
|
||||
getTree();
|
||||
@@ -93,12 +95,14 @@ function close() {
|
||||
}
|
||||
|
||||
function handleBlur() {
|
||||
searchFocus.value = false
|
||||
setTimeout(() => {
|
||||
filterList.value = [];
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function handleFocus() {
|
||||
searchFocus.value = true
|
||||
const val = inputVal.value.toLowerCase();
|
||||
if (val && dataSource.value) {
|
||||
filterList.value = dataSource.value.filter((item) => item.lable.toLowerCase().search(val) !== -1);
|
||||
@@ -141,6 +145,10 @@ function deleteItem(item, index) {
|
||||
}
|
||||
|
||||
function changeJobs() {
|
||||
if(isMachineEnv.value && !hasLogin.value){
|
||||
useUserStore().logOut()
|
||||
return
|
||||
}
|
||||
selectJobsModel.value?.open({
|
||||
title: '添加岗位',
|
||||
maskClick: true,
|
||||
@@ -217,6 +225,7 @@ function flattenTree(treeData, parentPath = '') {
|
||||
align-items: center;
|
||||
padding: 0 24rpx;
|
||||
position: relative;
|
||||
z-index:10;
|
||||
.search-input{
|
||||
flex: 1;
|
||||
padding: 0 20rpx;
|
||||
@@ -261,6 +270,15 @@ function flattenTree(treeData, parentPath = '') {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.search-mask{
|
||||
position fixed;
|
||||
width 100vw;
|
||||
height:100vh;
|
||||
top:0;
|
||||
left:0
|
||||
z-index:9;
|
||||
background: #33333355;
|
||||
}
|
||||
.main{
|
||||
padding: 54rpx 28rpx 28rpx 28rpx
|
||||
.content-list{
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
</view>
|
||||
<view v-else class="btn-wq button-click" @click="jobApply">
|
||||
<span v-if="jobInfo.isApply">立即前往</span>
|
||||
<span v-if="!jobInfo.isApply">立即投递</span>
|
||||
<span v-if="!jobInfo.isApply">立即前往</span>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -185,7 +185,7 @@ import dictLabel from '@/components/dict-Label/dict-Label.vue';
|
||||
import RadarMap from './component/radarMap.vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
const { isMiniProgram } = storeToRefs(useUserStore());
|
||||
const { isMiniProgram, hasLogin } = storeToRefs(useUserStore());
|
||||
|
||||
const { $api, navTo, getLenPx, parseQueryParams, navBack, isEmptyObject } = inject('globalFunction');
|
||||
import config from '@/config.js';
|
||||
@@ -252,7 +252,10 @@ function getDetail(jobId) {
|
||||
const { latitude, longitude, companyName, companyId } = resData.data;
|
||||
jobInfo.value = resData.data;
|
||||
getCompanyIsAJobs(companyId);
|
||||
getCompetivetuveness(jobId);
|
||||
|
||||
if (hasLogin.value) {
|
||||
getCompetivetuveness(jobId);
|
||||
}
|
||||
|
||||
if (latitude && longitude) {
|
||||
initMapCovers(latitude, longitude, companyName);
|
||||
@@ -285,12 +288,12 @@ function getCompanyIsAJobs(...args) {
|
||||
if (dataType.value === 2) {
|
||||
// 第三方数据获取公司职位数量
|
||||
const [gsID, gsmc, zphID] = args;
|
||||
const params={
|
||||
const params = {
|
||||
gsID,
|
||||
gsmc,
|
||||
zphID
|
||||
}
|
||||
$api.createRequest(`/app/internal/jobThirdPart`,params).then((resData) => {
|
||||
zphID,
|
||||
};
|
||||
$api.createRequest(`/app/internal/jobThirdPart`, params).then((resData) => {
|
||||
companyCount.value = resData.total;
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -281,7 +281,7 @@
|
||||
// "enablePullDownRefresh": false,
|
||||
// "navigationStyle": "custom",
|
||||
"rpxCalcBaseDeviceWidth": 375,
|
||||
"rpxCalcMaxDeviceWidth": 1200,
|
||||
"rpxCalcMaxDeviceWidth": 960,
|
||||
"rpxCalcIncludeWidth": 750
|
||||
},
|
||||
"uniIdRouter": {}
|
||||
|
||||
@@ -1,544 +0,0 @@
|
||||
<template>
|
||||
<view class="app-custom-root">
|
||||
<view class="app-container">
|
||||
<!-- 顶部头部区域 -->
|
||||
<view class="container-header">
|
||||
<view class="header-top">
|
||||
<view class="header-btnLf button-click" @click="seemsg(0)" :class="{ active: state.current === 0 }">
|
||||
现场招聘
|
||||
</view>
|
||||
<view class="header-btnLf button-click" @click="seemsg(1)" :class="{ active: state.current === 1 }">
|
||||
VR虚拟招聘会
|
||||
</view>
|
||||
</view>
|
||||
<view class="header-input btn-feel">
|
||||
<my-icons class="iconsearch" color="#666666" type="search" size="32"></my-icons>
|
||||
<input class="input" placeholder="招聘会" placeholder-class="inputplace" />
|
||||
</view>
|
||||
<view class="header-date">
|
||||
<view class="data-week">
|
||||
<view
|
||||
class="weel-days button-click"
|
||||
:class="{ active: currentDay.fullDate === item.fullDate }"
|
||||
v-for="(item, index) in weekList"
|
||||
:key="index"
|
||||
@click="selectDate(item)"
|
||||
>
|
||||
<view class="label">{{ item.day }}</view>
|
||||
<view class="day">{{ item.date }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="data-all">
|
||||
<image class="allimg button-click" @click="toSelectDate" src="/static/icon/date1.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 主体内容区域 -->
|
||||
<view class="container-main">
|
||||
<scroll-view scroll-y class="main-scroll" @scrolltolower="handleScrollToLower">
|
||||
<view class="cards">
|
||||
<view
|
||||
class="card press-button"
|
||||
v-for="(item, index) in fairList"
|
||||
:key="index"
|
||||
@click="navTo('/packageA/pages/exhibitors/exhibitors?jobFairId=' + item.jobFairId)"
|
||||
>
|
||||
<view class="card-title">{{ item.zphmc }}</view>
|
||||
<view class="card-row">
|
||||
<text class="">{{ item.zphdz }}</text>
|
||||
<text class="">
|
||||
<convert-distance
|
||||
:alat="item.latitude"
|
||||
:along="item.longitude"
|
||||
:blat="latitudeVal"
|
||||
:blong="longitudeVal"
|
||||
></convert-distance>
|
||||
</text>
|
||||
</view>
|
||||
<view class="card-times">
|
||||
<view class="time-left">
|
||||
<view class="left-date">{{ parseDateTime(item.zphjbsj).time }}</view>
|
||||
<view class="left-dateDay">{{ parseDateTime(item.zphjbsj).date }}</view>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="time-center">
|
||||
<view class="center-date">
|
||||
{{ getTimeStatus(item.zphjbsj, item.zphjzsj).statusText }}
|
||||
</view>
|
||||
<view class="center-dateDay">
|
||||
{{ getHoursBetween(item.zphjbsj, item.zphjzsj) }}小时
|
||||
</view>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="time-right">
|
||||
<view class="left-date">{{ parseDateTime(item.zphjzsj).time }}</view>
|
||||
<view class="left-dateDay">{{ parseDateTime(item.zphjzsj).date }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="recommend-card-line"></view>
|
||||
<view class="card-footer">内容简介:{{ item.zphjj }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<empty v-if="!fairList.length" pdTop="200"></empty>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<Tabbar :currentpage="1"></Tabbar>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import Tabbar from '@/components/tabbar/midell-box.vue';
|
||||
import useLocationStore from '@/stores/useLocationStore';
|
||||
import { storeToRefs } from 'pinia';
|
||||
const { longitudeVal, latitudeVal } = storeToRefs(useLocationStore());
|
||||
const { $api, navTo, cloneDeep } = inject('globalFunction');
|
||||
const weekList = ref([]);
|
||||
const fairList = ref([]);
|
||||
const currentDay = ref({});
|
||||
const state = reactive({
|
||||
current: 0,
|
||||
all: [{}],
|
||||
});
|
||||
const pageState = reactive({
|
||||
page: 0,
|
||||
total: 0,
|
||||
maxPage: 2,
|
||||
pageSize: 10,
|
||||
search: {},
|
||||
});
|
||||
|
||||
onLoad(() => {
|
||||
const today = new Date();
|
||||
const year = today.getFullYear();
|
||||
const month = String(today.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(today.getDate()).padStart(2, '0');
|
||||
|
||||
const currentDate = `${year}-${month}-${day}`;
|
||||
const result = getNextDates({
|
||||
startDate: currentDate,
|
||||
});
|
||||
weekList.value = result;
|
||||
currentDay.value.fullDate = result[0].fullDate;
|
||||
getFair('refresh');
|
||||
});
|
||||
|
||||
function toSelectDate() {
|
||||
navTo('/packageA/pages/selectDate/selectDate', {
|
||||
query: {
|
||||
date: currentDay.value.fullDate,
|
||||
},
|
||||
onBack: (res) => {
|
||||
console.log(res);
|
||||
const result = getNextDates({
|
||||
startDate: res.date,
|
||||
});
|
||||
const formattedDate = res.date.slice(5); // MM-DD
|
||||
const dateFull = {
|
||||
date: res.date.slice(5),
|
||||
day: '周' + res.week,
|
||||
fullDate: res.date,
|
||||
};
|
||||
currentDay.value = dateFull;
|
||||
weekList.value = result;
|
||||
getFair('refresh');
|
||||
},
|
||||
});
|
||||
}
|
||||
// 查看消息类型
|
||||
function changeSwiperMsgType(e) {
|
||||
const currented = e.detail.current;
|
||||
state.current = currented;
|
||||
}
|
||||
|
||||
function seemsg(index) {
|
||||
if (index === 1) {
|
||||
return $api.msg('功能确定中');
|
||||
}
|
||||
state.current = index;
|
||||
}
|
||||
|
||||
const handleScrollToLower = () => {
|
||||
return;
|
||||
getFair();
|
||||
console.log('触底');
|
||||
};
|
||||
|
||||
function getFair(type = 'add') {
|
||||
if (type === 'refresh') {
|
||||
pageState.page = 1;
|
||||
pageState.maxPage = 1;
|
||||
}
|
||||
if (type === 'add' && pageState.page < pageState.maxPage) {
|
||||
pageState.page += 1;
|
||||
}
|
||||
let params = {
|
||||
...pageState.search,
|
||||
// current: pageState.page,
|
||||
// pageSize: pageState.pageSize,
|
||||
};
|
||||
// if (currentDay.value?.fullDate) {
|
||||
// params.queryDate = currentDay.value.fullDate;
|
||||
// }
|
||||
if (currentDay.value?.fullDate) {
|
||||
params.zphjbsj = currentDay.value.fullDate.replace(/-/g, '');
|
||||
}
|
||||
$api.createRequest('/app/internal/jobFairThirdPart', params).then((resData) => {
|
||||
const { rows, total } = resData;
|
||||
if (type === 'add') {
|
||||
// const str = pageState.pageSize * (pageState.page - 1);
|
||||
// const end = fairList.value.length;
|
||||
// const reslist = rows;
|
||||
// fairList.value.splice(str, end, ...reslist);
|
||||
fairList.value = rows;
|
||||
} else {
|
||||
fairList.value = rows;
|
||||
}
|
||||
// pageState.list = resData.rows;
|
||||
pageState.total = resData.total;
|
||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
||||
});
|
||||
}
|
||||
|
||||
function parseDateTime(datetimeStr) {
|
||||
if (!datetimeStr) return { time: '', date: '' };
|
||||
|
||||
const dateObj = new Date(datetimeStr);
|
||||
|
||||
if (isNaN(dateObj.getTime())) return { time: '', date: '' }; // 无效时间
|
||||
|
||||
const year = dateObj.getFullYear();
|
||||
const month = String(dateObj.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(dateObj.getDate()).padStart(2, '0');
|
||||
const hours = String(dateObj.getHours()).padStart(2, '0');
|
||||
const minutes = String(dateObj.getMinutes()).padStart(2, '0');
|
||||
|
||||
return {
|
||||
time: `${hours}:${minutes}`,
|
||||
date: `${year}年${month}月${day}日`,
|
||||
};
|
||||
}
|
||||
|
||||
function getTimeStatus(startTimeStr, endTimeStr) {
|
||||
const now = new Date();
|
||||
const startTime = new Date(startTimeStr);
|
||||
const endTime = new Date(endTimeStr);
|
||||
|
||||
// 判断状态:0 开始中,1 过期,2 待开始
|
||||
let status = 0;
|
||||
let statusText = '开始中';
|
||||
if (now < startTime) {
|
||||
status = 2; // 待开始
|
||||
statusText = '待开始';
|
||||
} else if (now > endTime) {
|
||||
status = 1; // 已过期
|
||||
statusText = '已过期';
|
||||
} else {
|
||||
status = 0; // 进行中
|
||||
statusText = '进行中';
|
||||
}
|
||||
return {
|
||||
status, // 0: 进行中,1: 已过期,2: 待开始
|
||||
statusText,
|
||||
};
|
||||
}
|
||||
|
||||
function getHoursBetween(startTimeStr, endTimeStr) {
|
||||
const start = new Date(startTimeStr);
|
||||
const end = new Date(endTimeStr);
|
||||
|
||||
const diffMs = end - start;
|
||||
const diffHours = diffMs / (1000 * 60 * 60);
|
||||
|
||||
return +diffHours.toFixed(2); // 保留 2 位小数
|
||||
}
|
||||
|
||||
const selectDate = (item) => {
|
||||
if (currentDay.value?.fullDate === item.fullDate) {
|
||||
currentDay.value = {};
|
||||
getFair('refresh');
|
||||
return;
|
||||
}
|
||||
currentDay.value = item;
|
||||
getFair('refresh');
|
||||
};
|
||||
|
||||
function getNextDates({ startDate = '', count = 6 }) {
|
||||
const baseDate = startDate ? new Date(startDate) : new Date(); // 指定起点或今天
|
||||
const dates = [];
|
||||
const dayNames = ['日', '一', '二', '三', '四', '五', '六'];
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const date = new Date(baseDate);
|
||||
date.setDate(baseDate.getDate() + i);
|
||||
|
||||
const fullDate = date.toISOString().slice(0, 10); // YYYY-MM-DD
|
||||
const formattedDate = fullDate.slice(5); // MM-DD
|
||||
const dayOfWeek = dayNames[date.getDay()];
|
||||
|
||||
dates.push({
|
||||
date: formattedDate,
|
||||
fullDate,
|
||||
day: '周' + dayOfWeek,
|
||||
});
|
||||
}
|
||||
|
||||
// 可选设置默认选中项
|
||||
// currentDay.value = dates[0];
|
||||
|
||||
return dates;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.app-custom-root {
|
||||
position: fixed;
|
||||
z-index: 10;
|
||||
width: 100vw;
|
||||
height: calc(100% - var(--window-bottom));
|
||||
overflow: hidden;
|
||||
}
|
||||
.app-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
.container-header {
|
||||
background: url('@/static/icon/background2.png') 0 0 no-repeat;
|
||||
background-size: 100% 400rpx;
|
||||
.header-top{
|
||||
display: flex;
|
||||
line-height: calc(88rpx - 14rpx);
|
||||
padding: 16rpx 44rpx 14rpx 44rpx;
|
||||
.header-btnLf {
|
||||
display: flex;
|
||||
width: fit-content;
|
||||
white-space: nowrap
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: calc(60rpx * 3);
|
||||
font-weight: 500;
|
||||
font-size: 40rpx;
|
||||
color: #696969;
|
||||
margin-right: 44rpx;
|
||||
position: relative;
|
||||
.btns-wd{
|
||||
position: absolute
|
||||
top: 2rpx;
|
||||
right: 2rpx
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
background: #F73636;
|
||||
border-radius: 50%;
|
||||
border: 4rpx solid #EEEEFF;
|
||||
}
|
||||
}
|
||||
.active {
|
||||
font-weight: 600;
|
||||
font-size: 40rpx;
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
.header-input{
|
||||
padding: 0 24rpx
|
||||
width: calc(100% - 48rpx);
|
||||
position: relative
|
||||
.iconsearch{
|
||||
position: absolute
|
||||
left: 50rpx;
|
||||
top: 50%
|
||||
transform: translate(0, -50%)
|
||||
}
|
||||
.input{
|
||||
padding: 0 30rpx 0 80rpx
|
||||
height: 80rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 75rpx 75rpx 75rpx 75rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.inputplace{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #B5B5B5;
|
||||
}
|
||||
|
||||
}
|
||||
.header-date{
|
||||
padding: 28rpx
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
align-items: center
|
||||
.data-week{
|
||||
flex: 1
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
flex-wrap: nowrap
|
||||
overflow: hidden
|
||||
.weel-days{
|
||||
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
|
||||
display: flex
|
||||
justify-content: center
|
||||
flex-direction: column
|
||||
text-align: center
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
width: 96rpx;
|
||||
height: 88rpx;
|
||||
|
||||
.label{}
|
||||
.day{
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
.active{
|
||||
background: rgba(37,107,250,0.1);
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
color: #256BFA;
|
||||
}
|
||||
}
|
||||
.data-all{
|
||||
width: 66rpx;
|
||||
height: 66rpx;
|
||||
margin-left: 18rpx
|
||||
.allimg{
|
||||
width: 100%;
|
||||
height: 100%
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container-main {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.main-scroll {
|
||||
width: 100%
|
||||
height: 100%;
|
||||
}
|
||||
.cards{
|
||||
padding: 28rpx 28rpx 28rpx 28rpx;
|
||||
.card{
|
||||
margin-top: 28rpx
|
||||
padding: 32rpx;
|
||||
background: #FFFFFF
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 0rpx 8rpx 0rpx rgba(0,0,0,0.04);
|
||||
border-radius: 20rpx 20rpx 20rpx 20rpx;
|
||||
.card-title{
|
||||
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.card-row{
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #495265;
|
||||
margin-top: 4rpx
|
||||
}
|
||||
.card-times{
|
||||
display: flex;
|
||||
justify-content: space-between
|
||||
align-items: center
|
||||
margin-top: 24rpx
|
||||
.time-left,
|
||||
.time-right{
|
||||
text-align: center
|
||||
.left-date{
|
||||
font-weight: 500;
|
||||
font-size: 48rpx;
|
||||
color: #333333;
|
||||
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
|
||||
}
|
||||
.left-dateDay{
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
margin-top: 12rpx
|
||||
}
|
||||
}
|
||||
.line{
|
||||
width: 40rpx;
|
||||
height: 0rpx;
|
||||
border: 2rpx solid #D4D4D4;
|
||||
margin-top: 64rpx
|
||||
}
|
||||
.time-center{
|
||||
text-align: center;
|
||||
display: flex
|
||||
flex-direction: column
|
||||
justify-content: center
|
||||
align-items: center
|
||||
.center-date{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #FF881A;
|
||||
padding-top: 10rpx
|
||||
}
|
||||
.center-dateDay{
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
margin-top: 6rpx
|
||||
line-height: 48rpx;
|
||||
width: 104rpx;
|
||||
height: 48rpx;
|
||||
background: #F9F9F9;
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.recommend-card-line{
|
||||
width: calc(100%);
|
||||
height: 0rpx;
|
||||
border-radius: 0rpx 0rpx 0rpx 0rpx;
|
||||
border: 2rpx dashed rgba(0,0,0,0.14);
|
||||
margin-top: 32rpx
|
||||
position: relative
|
||||
}
|
||||
|
||||
.recommend-card-line::before{
|
||||
position: absolute
|
||||
content: ''
|
||||
left: 0
|
||||
top: 0
|
||||
transform: translate(-50% - 110rpx, -50%)
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
background: #F4F4F4;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.recommend-card-line::after{
|
||||
position: absolute
|
||||
content: ''
|
||||
right: 0
|
||||
top: 0
|
||||
transform: translate(50% + 100rpx, -50%)
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
background: #F4F4F4;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.card-footer{
|
||||
margin-top: 32rpx
|
||||
min-height: 50rpx;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
}
|
||||
}
|
||||
.card:first-child{
|
||||
margin-top: 0
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -7,7 +7,7 @@
|
||||
<view class="header-btnLf button-click" @click="seemsg(0)" :class="{ active: state.current === 0 }">
|
||||
现场招聘
|
||||
</view>
|
||||
<view class="header-btnLf button-click" @click="seemsg(1)" :class="{ active: state.current === 1 }">
|
||||
<view v-if="!isMachineEnv" class="header-btnLf button-click" @click="seemsg(1)" :class="{ active: state.current === 1 }">
|
||||
VR虚拟招聘会
|
||||
</view>
|
||||
</view>
|
||||
@@ -113,6 +113,8 @@ import useLocationStore from '@/stores/useLocationStore';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import config from '@/config';
|
||||
const { longitudeVal, latitudeVal } = storeToRefs(useLocationStore());
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
const { isMachineEnv } = storeToRefs(useUserStore());
|
||||
const { $api, navTo, cloneDeep, debounce } = inject('globalFunction');
|
||||
import useScreenStore from '@/stores/useScreenStore'
|
||||
|
||||
@@ -195,7 +197,6 @@ function changeSwiperMsgType(e) {
|
||||
function seemsg(index) {
|
||||
if (index === 1) {
|
||||
handleItemClick();
|
||||
// $api.msg('功能确定中');
|
||||
return;
|
||||
}
|
||||
state.current = index;
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
class="msg-files btn-light"
|
||||
v-for="(file, vInex) in msg.files"
|
||||
:key="vInex"
|
||||
@click="jumpUrl(file)"
|
||||
@click="handleMsgFileClick(file)"
|
||||
>
|
||||
<image class="msg-file-icon" src="/static/icon/Vector2.png"></image>
|
||||
<text class="msg-file-text">{{ file.name || '附件' }}</text>
|
||||
@@ -216,9 +216,10 @@
|
||||
>
|
||||
<image
|
||||
class="file-iconImg"
|
||||
@click="jumpUrl(file)"
|
||||
@click="preViewImage(file)"
|
||||
v-if="isImage(file.type)"
|
||||
:src="file.url"
|
||||
mode="scaleToFill"
|
||||
></image>
|
||||
<view class="file-doc" @click="jumpUrl(file)" v-else>
|
||||
<FileIcon class="doc-icon" :type="file.type"></FileIcon>
|
||||
@@ -241,6 +242,7 @@
|
||||
</view>
|
||||
</view>
|
||||
<PopupFeeBack ref="feeback" @onClose="colseFeeBack" @onSend="confirmFeeBack"></PopupFeeBack>
|
||||
<UploadQrcode ref="qrcodeRef" @onSend="handleFileSend" :leaveFileCount="leaveFileCount" :sessionId="chatSessionID"></UploadQrcode>
|
||||
<MsgTips ref="feeBackTips" content="已收到反馈,感谢您的关注" title="反馈成功" :icon="successIcon"></MsgTips>
|
||||
</view>
|
||||
</template>
|
||||
@@ -263,6 +265,7 @@ import useChatGroupDBStore from '@/stores/userChatGroupStore';
|
||||
import MdRender from '@/components/md-render/md-render.vue';
|
||||
import CollapseTransition from '@/components/CollapseTransition/CollapseTransition.vue';
|
||||
import PopupFeeBack from './popupbadFeeback.vue';
|
||||
import UploadQrcode from './uploadQrcode.vue';
|
||||
import AudioWave from './AudioWave.vue';
|
||||
import WaveDisplay from './WaveDisplay.vue';
|
||||
import FileIcon from './fileIcon.vue';
|
||||
@@ -279,6 +282,8 @@ const { $api, navTo, throttle } = inject('globalFunction');
|
||||
const emit = defineEmits(['onConfirm']);
|
||||
const { messages, isTyping, textInput, chatSessionID } = storeToRefs(useChatGroupDBStore());
|
||||
import successIcon from '@/static/icon/success.png';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
const { isMachineEnv } = storeToRefs(useUserStore());
|
||||
// hook
|
||||
// 语音识别
|
||||
const {
|
||||
@@ -316,6 +321,7 @@ const feeBackTips = ref(null);
|
||||
const state = reactive({
|
||||
uploadFileTips: '请根据以上附件,帮我推荐岗位。',
|
||||
});
|
||||
const qrcodeRef = ref(null);
|
||||
|
||||
const statusText = computed(() => {
|
||||
switch (status.value) {
|
||||
@@ -336,6 +342,10 @@ const audiowaveStyle = computed(() => {
|
||||
: '#f1f1f1';
|
||||
});
|
||||
|
||||
const leaveFileCount = computed(()=>{ //还剩多少文件可以上传 给扫码传参使用
|
||||
return config.allowedFileNumber - filesList.value.length
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
changeQueries();
|
||||
scrollToBottom();
|
||||
@@ -458,7 +468,15 @@ function getGuess() {
|
||||
}
|
||||
|
||||
function isImage(type) {
|
||||
return new RegExp('image').test(type);
|
||||
if (!type || typeof type !== 'string') return false;
|
||||
const imageTypes = [
|
||||
'jpg', 'jpeg', 'png', 'gif', 'bmp',
|
||||
'webp', 'svg', 'tiff', 'tif', 'ico',
|
||||
'apng', 'avif', 'heic', 'heif', 'jfif'
|
||||
];
|
||||
const lowerType = type.toLowerCase();
|
||||
|
||||
return imageTypes.some(item=>lowerType.includes(item))
|
||||
}
|
||||
|
||||
function isFile(type) {
|
||||
@@ -471,11 +489,40 @@ function isFile(type) {
|
||||
|
||||
function jumpUrl(file) {
|
||||
if (file.url) {
|
||||
window.open(file.url);
|
||||
if(!isMachineEnv.value)window.open(file.url);
|
||||
else $api.msg('该文件无法预览');
|
||||
} else {
|
||||
$api.msg('文件地址丢失');
|
||||
}
|
||||
}
|
||||
function preViewImage(file) {
|
||||
if (file.url) {
|
||||
uni.previewImage({
|
||||
urls: [file.url]
|
||||
})
|
||||
} else {
|
||||
$api.msg('文件地址丢失');
|
||||
}
|
||||
}
|
||||
function handleMsgFileClick(file) {
|
||||
if(isImage(file.type)){
|
||||
if (file.url) {
|
||||
uni.previewImage({
|
||||
urls: [file.url]
|
||||
})
|
||||
} else {
|
||||
$api.msg('文件地址丢失');
|
||||
}
|
||||
}else{
|
||||
if (file.url) {
|
||||
if(!isMachineEnv.value)window.open(file.url);
|
||||
else $api.msg('该文件无法预览');
|
||||
} else {
|
||||
$api.msg('文件地址丢失');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function VerifyNumberFiles(num) {
|
||||
if (filesList.value.length >= config.allowedFileNumber) {
|
||||
@@ -498,6 +545,7 @@ function uploadCamera(type = 'camera') {
|
||||
// 继续上传
|
||||
$api.uploadFile(tempFilePaths[0], true).then((resData) => {
|
||||
resData = JSON.parse(resData);
|
||||
console.log(file.type,'++')
|
||||
if (isImage(file.type)) {
|
||||
filesList.value.push({
|
||||
url: resData.msg,
|
||||
@@ -521,7 +569,7 @@ function getUploadFile(type = 'camera') {
|
||||
const allowedTypes = config.allowedFileTypes || [];
|
||||
const size = $api.formatFileSize(file.size);
|
||||
if (!allowedTypes.includes(file.type)) {
|
||||
return $api.msg('仅支持 txt md html word pdf ppt csv excel 格式类型');
|
||||
return $api.msg('仅支持 txt md word pdf ppt csv excel 格式类型');
|
||||
}
|
||||
// 继续上传
|
||||
$api.uploadFile(tempFilePaths[0], true).then((resData) => {
|
||||
@@ -538,6 +586,30 @@ function getUploadFile(type = 'camera') {
|
||||
});
|
||||
}
|
||||
|
||||
const handleFileSend = (rows)=>{
|
||||
try {
|
||||
rows.map(item=>{
|
||||
if(isImage(item.fileSuffix)){
|
||||
filesList.value.push({
|
||||
url: item.fileUrl,
|
||||
type: item.fileSuffix,
|
||||
name: item.originalName,
|
||||
});
|
||||
}else{
|
||||
filesList.value.push({
|
||||
url: item.fileUrl,
|
||||
type: item.fileSuffix,
|
||||
name: item.originalName,
|
||||
});
|
||||
}
|
||||
})
|
||||
textInput.value = state.uploadFileTips;
|
||||
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
const tipsPermisson = () => {
|
||||
uni.showToast({
|
||||
title: '需要授权麦克风权限才能使用语音功能',
|
||||
@@ -599,6 +671,14 @@ function changeVoice() {
|
||||
}
|
||||
|
||||
function changeShowFile() {
|
||||
if(isMachineEnv.value){
|
||||
if (filesList.value.length >= config.allowedFileNumber){
|
||||
return $api.msg(`最大上传文件数量 ${config.allowedFileNumber} 个`);
|
||||
}else{
|
||||
qrcodeRef.value?.open()
|
||||
return
|
||||
}
|
||||
}
|
||||
showfile.value = !showfile.value;
|
||||
}
|
||||
|
||||
@@ -1012,6 +1092,7 @@ image-margin-top = 40rpx
|
||||
left: 0
|
||||
padding: 10rpx 0 10rpx 30rpx
|
||||
box-shadow: 0rpx -4rpx 10rpx 0rpx rgba(11,44,112,0.06);
|
||||
z-index:1
|
||||
.uploadfiles-scroll
|
||||
height: 100%
|
||||
.uploadfiles-list
|
||||
@@ -1074,7 +1155,7 @@ image-margin-top = 40rpx
|
||||
color: #7B7B7B;
|
||||
max-width: 100%
|
||||
.file-iconImg
|
||||
height: 100%
|
||||
// height: 100%
|
||||
width: 100%
|
||||
.filerow
|
||||
display: flex
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<image v-if="type === 'application/pdf'" :src="pdfIcon" class="file-icon" />
|
||||
<image v-if="type === 'application/pdf' || type === 'pdf'" :src="pdfIcon" class="file-icon" />
|
||||
<image
|
||||
v-else-if="
|
||||
type === 'application/msword' ||
|
||||
type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
||||
type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ||
|
||||
type === 'doc' ||
|
||||
type === 'docx'
|
||||
"
|
||||
:src="docIcon"
|
||||
class="file-icon"
|
||||
@@ -11,18 +13,22 @@
|
||||
<image
|
||||
v-else-if="
|
||||
type === 'application/vnd.ms-powerpoint' ||
|
||||
type === 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
|
||||
type === 'application/vnd.openxmlformats-officedocument.presentationml.presentation'||
|
||||
type === 'ppt' ||
|
||||
type === 'pptx'
|
||||
"
|
||||
:src="pptIcon"
|
||||
class="file-icon"
|
||||
/>
|
||||
<image v-else-if="type === 'text/markdown'" :src="mdIcon" class="file-icon" />
|
||||
<image v-else-if="type === 'text/plain'" :src="txtIcon" class="file-icon" />
|
||||
<image v-else-if="type === 'text/html'" :src="htmlIcon" class="file-icon" />
|
||||
<image v-else-if="type === 'text/markdown' || type === 'md'" :src="mdIcon" class="file-icon" />
|
||||
<image v-else-if="type === 'text/plain' || type=== 'txt'" :src="txtIcon" class="file-icon" />
|
||||
<image v-else-if="type === 'text/html' || type === 'html'" :src="htmlIcon" class="file-icon" />
|
||||
<image
|
||||
v-else-if="
|
||||
type === 'application/vnd.ms-excel' ||
|
||||
type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'||
|
||||
type === 'xls' ||
|
||||
type === 'xlsx'
|
||||
"
|
||||
:src="excelIcon"
|
||||
class="file-icon"
|
||||
|
||||
@@ -23,6 +23,25 @@ const fileAbbreviation = computed(() => {
|
||||
'text/markdown': 'MD',
|
||||
'text/plain': 'TXT',
|
||||
'text/html': 'HTML',
|
||||
'pdf':'PDF',
|
||||
'doc':'DOC',
|
||||
'docx':'DOCX',
|
||||
'ppt':'PPT',
|
||||
'pptx':'PPTX',
|
||||
'xls': 'XLS',
|
||||
'xlsx': 'XLSX',
|
||||
'md':'MD',
|
||||
'txt':'TXT',
|
||||
'html':'HTML',
|
||||
'jpg':'JPG',
|
||||
'img':'IMG',
|
||||
'png':'PNG',
|
||||
'jpeg':'JPEG',
|
||||
'gif':'GIF',
|
||||
'webp':'WEBP',
|
||||
'svg':'SVG',
|
||||
'tiff':'TIFF',
|
||||
|
||||
};
|
||||
return typeMap[props.type] || 'OTHER';
|
||||
});
|
||||
|
||||
560
pages/chat/components/uploadQrcode.vue
Normal file
@@ -0,0 +1,560 @@
|
||||
<template>
|
||||
<uni-popup ref="popup" type="center" borderRadius="12px 12px 0 0" @change="changePopup">
|
||||
<view class="popup-inner">
|
||||
<view v-show="!fileCount" class="title">请扫码上传附件</view>
|
||||
<view v-show="!fileCount" class="img-box">
|
||||
<!-- 加载状态 -->
|
||||
<view v-if="loading" class="loading-container">
|
||||
<uni-load-more status="loading" :icon-size="24" :content-text="loadingText" />
|
||||
</view>
|
||||
<canvas canvas-id="qrcode" id="qrcode" />
|
||||
</view>
|
||||
<view class="tips" v-if="!loading">
|
||||
已上传
|
||||
<span class="num">{{ fileCount }}</span>
|
||||
个文件
|
||||
</view>
|
||||
<view v-show="!fileCount" class="tips" v-if="!loading">请使用手机扫描二维码上传文件</view>
|
||||
<view v-show="fileCount" class="file-list">
|
||||
<view v-for="(file, index) in fileList" class="file-item">
|
||||
<image
|
||||
class="file-icon"
|
||||
@click="preViewImage(file)"
|
||||
v-if="isImage(file.fileSuffix)"
|
||||
:src="file.fileUrl"
|
||||
mode="scaleToFill"
|
||||
></image>
|
||||
<FileIcon v-else class="file-icon" :type="file.fileSuffix"></FileIcon>
|
||||
<view class="right">
|
||||
<view class="file-name">{{ file.originalName }}</view>
|
||||
<FileText :type="file.fileSuffix"></FileText>
|
||||
</view>
|
||||
<view class="remove-btn" @click="delFile(file, index)">×</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-show="fileCount" class="confirm-btn btn-feel" @click="handleConfirm">确认</view>
|
||||
<view class="close-btn" @click="close"></view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, inject, onUnmounted, watch, computed } from 'vue';
|
||||
import FileIcon from './fileIcon.vue';
|
||||
import FileText from './fileText.vue';
|
||||
import uQRCode from '@/static/js/qrcode';
|
||||
import config from '@/config';
|
||||
import { onShow, onHide } from '@dcloudio/uni-app';
|
||||
import { UUID } from '../../../lib/uuid-min';
|
||||
const props = defineProps({
|
||||
sessionId: {
|
||||
type: [Number, String],
|
||||
default: '',
|
||||
},
|
||||
leaveFileCount: {
|
||||
type: [Number, String],
|
||||
default: 2,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['onSend', 'onClose']);
|
||||
const { $api } = inject('globalFunction');
|
||||
|
||||
const popup = ref(null);
|
||||
const loading = ref(false);
|
||||
const pollingTimer = ref(null);
|
||||
const isPolling = ref(false);
|
||||
const isVisible = ref(false);
|
||||
const uuid = ref(null);
|
||||
const fileCount = ref(0);
|
||||
const fileList = ref([]);
|
||||
const delFiles = ref([]); //本地记录删除的文件
|
||||
|
||||
// 计算加载文本
|
||||
const loadingText = computed(() => ({
|
||||
contentdown: '二维码生成中',
|
||||
contentrefresh: '二维码生成中',
|
||||
}));
|
||||
|
||||
onUnmounted(() => {
|
||||
stopPolling();
|
||||
clearResources();
|
||||
});
|
||||
|
||||
function isImage(type) {
|
||||
if (!type || typeof type !== 'string') return false;
|
||||
const imageTypes = [
|
||||
'jpg',
|
||||
'jpeg',
|
||||
'png',
|
||||
'gif',
|
||||
'bmp',
|
||||
'webp',
|
||||
'svg',
|
||||
'tiff',
|
||||
'tif',
|
||||
'ico',
|
||||
'apng',
|
||||
'avif',
|
||||
'heic',
|
||||
'heif',
|
||||
'jfif',
|
||||
];
|
||||
const lowerType = type.toLowerCase();
|
||||
|
||||
return imageTypes.some((item) => lowerType.includes(item));
|
||||
}
|
||||
function preViewImage(file) {
|
||||
if (file.fileUrl) {
|
||||
uni.previewImage({
|
||||
urls: [file.fileUrl],
|
||||
});
|
||||
} else {
|
||||
$api.msg('文件地址丢失');
|
||||
}
|
||||
}
|
||||
function delFile(file, idx) {
|
||||
fileList.value.splice(idx, 1);
|
||||
fileCount.value = fileList.value.length
|
||||
delFiles.value.push(file.fileUrl);
|
||||
}
|
||||
|
||||
function open() {
|
||||
uuid.value = UUID.generate();
|
||||
resetState();
|
||||
isVisible.value = true;
|
||||
popup.value.open();
|
||||
initQrCode();
|
||||
}
|
||||
|
||||
function close() {
|
||||
isVisible.value = false;
|
||||
stopPolling();
|
||||
popup.value.close();
|
||||
resetState();
|
||||
}
|
||||
|
||||
function changePopup(e) {
|
||||
if (e.show) {
|
||||
} else {
|
||||
stopPolling();
|
||||
emit('onClose');
|
||||
}
|
||||
}
|
||||
|
||||
function handleConfirm() {
|
||||
emit('onSend', fileList.value);
|
||||
close();
|
||||
}
|
||||
|
||||
// 重置所有状态
|
||||
function resetState() {
|
||||
delFiles.value = []
|
||||
fileList.value = [];
|
||||
fileCount.value = 0;
|
||||
loading.value = false;
|
||||
stopPolling();
|
||||
}
|
||||
|
||||
async function initQrCode() {
|
||||
try {
|
||||
loading.value = true;
|
||||
// 清除之前的二维码
|
||||
clearCanvas();
|
||||
await makeQrcode();
|
||||
// 二维码生成成功后开始轮询
|
||||
if (isVisible.value) {
|
||||
startPolling();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('生成二维码失败:', error);
|
||||
uni.showToast({
|
||||
title: '生成二维码失败,请重试',
|
||||
icon: 'none',
|
||||
});
|
||||
close();
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function makeQrcode() {
|
||||
const protocol = window.location.protocol;
|
||||
const host = window.location.host;
|
||||
const isLocal = host.includes('localhost') || host.includes('127.0.0.1');
|
||||
// const pathPrefix = isLocal ? '' : '/rgpp-api/all-in-one';
|
||||
let pathPrefix = '';
|
||||
if (host.includes('localhost') || host.includes('127.0.0.1')) {
|
||||
pathPrefix = '';
|
||||
} else if (host.includes('qd.zhaopinzao8dian.com')) {
|
||||
// 外网测试环境
|
||||
pathPrefix = '/app';
|
||||
} else if (host.includes('fw.rc.qingdao.gov.cn')) {
|
||||
// 青岛政务网环境
|
||||
pathPrefix = '/rgpp-api/all-in-one';
|
||||
} else {
|
||||
pathPrefix = '';
|
||||
}
|
||||
const htmlPath = `${protocol}//${host}${pathPrefix}/static/upload.html?sessionId=${uuid.value}&uploadApi=${config.baseUrl}/app/kiosk/upload&fileCount=${props.leaveFileCount}`;
|
||||
|
||||
// const htmlPath = `${window.location.host}/static/upload.html?sessionId=${uuid.value}&uploadApi=${
|
||||
// config.baseUrl + '/app/kiosk/upload'
|
||||
// }`;
|
||||
// const htmlPath = `${window.location.host}/static/upload.html?sessionId=${props.sessionId}&uploadApi=${
|
||||
// config.baseUrl + '/app/kiosk/upload'
|
||||
// }`;
|
||||
console.log(htmlPath);
|
||||
console.log('剩余可上传文件数量:',props.leaveFileCount)
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
uQRCode.make({
|
||||
canvasId: 'qrcode',
|
||||
text: htmlPath,
|
||||
size: uni.upx2px(300),
|
||||
margin: 0,
|
||||
backgroundColor: '#ffffff',
|
||||
foregroundColor: '#1677ff',
|
||||
fileType: 'png',
|
||||
correctLevel: uQRCode.defaults.correctLevel,
|
||||
});
|
||||
resolve();
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
// 清除画布
|
||||
function clearCanvas() {
|
||||
const ctx = uni.createCanvasContext('qrcode');
|
||||
ctx.clearRect(0, 0, uni.upx2px(300), uni.upx2px(300));
|
||||
ctx.draw();
|
||||
}
|
||||
|
||||
function startPolling() {
|
||||
if (isPolling.value) return;
|
||||
|
||||
isPolling.value = true;
|
||||
console.log('开始轮询');
|
||||
|
||||
// 轮询检查上传状态
|
||||
const poll = async () => {
|
||||
if (!isPolling.value || !isVisible.value) return;
|
||||
const { data } = await $api.createRequest('/app/kiosk/list', { sessionId: uuid.value });
|
||||
// const { data } = await $api.createRequest('/app/kiosk/list',{sessionId:props.sessionId});
|
||||
if (data && data.length) {
|
||||
// 上传完成,触发事件
|
||||
fileList.value = data.filter((item) => !delFiles.value.includes(item.fileUrl))
|
||||
fileCount.value = fileList.value.length;
|
||||
// emit('onSend', data);
|
||||
}
|
||||
if (isPolling.value && isVisible.value) {
|
||||
pollingTimer.value = setTimeout(poll, 2000); // 每2秒轮询一次
|
||||
}
|
||||
};
|
||||
|
||||
poll();
|
||||
}
|
||||
|
||||
function stopPolling() {
|
||||
isPolling.value = false;
|
||||
if (pollingTimer.value) {
|
||||
clearTimeout(pollingTimer.value);
|
||||
pollingTimer.value = null;
|
||||
}
|
||||
console.log('停止轮询');
|
||||
}
|
||||
|
||||
function clearResources() {
|
||||
stopPolling();
|
||||
clearCanvas();
|
||||
}
|
||||
|
||||
defineExpose({ open, close });
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.popup-inner {
|
||||
padding: 40rpx 30rpx 50rpx;
|
||||
width: 520rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
border-radius: 20rpx;
|
||||
background: linear-gradient(135deg, #fafafa 0%, #f0f7ff 100%);
|
||||
box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
color: #1a1a1a;
|
||||
margin-bottom: 30rpx;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
padding-bottom: 16rpx;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 60rpx;
|
||||
height: 4rpx;
|
||||
background: linear-gradient(90deg, #4191fe 0%, #256bfa 100%);
|
||||
border-radius: 2rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.img-box {
|
||||
margin: 0 auto 30rpx;
|
||||
width: 300rpx;
|
||||
height: 300rpx;
|
||||
background: linear-gradient(145deg, #ffffff 0%, #f8faff 100%);
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
box-shadow: 0 8rpx 32rpx rgba(65, 145, 254, 0.2);
|
||||
padding: 20rpx;
|
||||
border: 2rpx solid rgba(65, 145, 254, 0.1);
|
||||
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 8rpx;
|
||||
transition: all 0.3s ease;
|
||||
animation: canvasFadeIn 0.5s ease;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes canvasFadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(20rpx);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.file-list {
|
||||
margin-top: 30rpx;
|
||||
width: 470rpx;
|
||||
max-height: 60vh;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-right: 10rpx;
|
||||
|
||||
.file-item {
|
||||
width: 100%;
|
||||
padding: 25rpx;
|
||||
padding-right: 15rpx;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #bbc5d1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
animation: fadeIn 0.5s ease;
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f0f8ff 100%);
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 6rpx;
|
||||
height: 100%;
|
||||
background: linear-gradient(180deg, #4191fe 0%, #256bfa 100%);
|
||||
border-radius: 3rpx 0 0 3rpx;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2rpx);
|
||||
box-shadow: 0 8rpx 24rpx rgba(65, 145, 254, 0.15);
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
margin-right: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
|
||||
transition: transform 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
|
||||
.file-name {
|
||||
font-size: 30rpx;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-weight: 500;
|
||||
color: #1a1a1a;
|
||||
margin-bottom: 8rpx;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.file-size {
|
||||
font-size: 24rpx;
|
||||
color: #838383;
|
||||
}
|
||||
}
|
||||
|
||||
.remove-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #ff6b6b;
|
||||
font-size: 52rpx;
|
||||
cursor: pointer;
|
||||
margin-left: 20rpx;
|
||||
flex-shrink: 0;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
transition: all 0.3s ease;
|
||||
margin-top: -15rpx;
|
||||
|
||||
&:active {
|
||||
background-color: rgba(255, 107, 107, 0.1);
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
width: 350rpx;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
background: linear-gradient(135deg, #4191fe 0%, #256bfa 100%);
|
||||
border-radius: 16rpx;
|
||||
margin-top: 30rpx;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 8rpx 24rpx rgba(37, 107, 250, 0.3);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
transition: left 0.6s ease;
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 4rpx 16rpx rgba(37, 107, 250, 0.4);
|
||||
|
||||
&::after {
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(145deg, #ffffff 0%, #f8faff 100%);
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.tips {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
line-height: 1.6;
|
||||
padding: 0 20rpx;
|
||||
margin-top: 10rpx;
|
||||
animation: fadeIn 0.5s ease;
|
||||
|
||||
.num {
|
||||
color: #4191fe;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
margin: 0 8rpx;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 20rpx;
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f8faff 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
z-index: 10;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.9) rotate(90deg);
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 24rpx;
|
||||
height: 2rpx;
|
||||
background: #5a5a68;
|
||||
border-radius: 1rpx;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
&::before {
|
||||
transform: translate(-50%, -50%) rotate(45deg);
|
||||
}
|
||||
|
||||
&::after {
|
||||
transform: translate(-50%, -50%) rotate(-45deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,911 +0,0 @@
|
||||
<template>
|
||||
<view class="app-container">
|
||||
<view class="nav-hidden hidden-animation" :class="{ 'hidden-height': isScrollingDown }">
|
||||
<view class="container-search">
|
||||
<view class="search-input button-click" @click="navTo('/pages/search/search')">
|
||||
<my-icons class="iconsearch" color="#666666" type="search" size="32"></my-icons>
|
||||
<text class="inpute">职位名称、薪资要求等</text>
|
||||
</view>
|
||||
<!-- <view class="chart button-click">职业图谱</view> -->
|
||||
</view>
|
||||
<view class="cards">
|
||||
<view class="card press-button" @click="navTo('/pages/nearby/nearby')">
|
||||
<view class="card-title">附近工作</view>
|
||||
<view class="card-text">好岗职等你来</view>
|
||||
</view>
|
||||
<view class="card press-button" @click="navTo('/packageA/pages/choiceness/choiceness')">
|
||||
<view class="card-title">精选企业</view>
|
||||
<view class="card-text">优选职得信赖</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="nav-filter">
|
||||
<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)"
|
||||
>
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="jobs-add button-click" @click="navTo('/packageA/pages/addPosition/addPosition')">
|
||||
<my-icons class="iconsearch" color="#666D7F" type="plusempty" size="32"></my-icons>
|
||||
<text>添加</text>
|
||||
</view>
|
||||
</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"
|
||||
>
|
||||
{{ item.text }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="btm-right button-click" @click="openFilter">
|
||||
筛选
|
||||
<image class="right-sx" :class="{ active: showFilter }" src="@/static/icon/shaixun.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="table-list">
|
||||
<scroll-view :scroll-y="true" class="falls-scroll" @scroll="handleScroll" @scrolltolower="scrollBottom">
|
||||
<view class="falls">
|
||||
<custom-waterfalls-flow
|
||||
:column="columnCount"
|
||||
:columnSpace="columnSpace"
|
||||
ref="waterfallsFlowRef"
|
||||
:value="list"
|
||||
>
|
||||
<template v-slot:default="job">
|
||||
<view class="item btn-feel" v-if="!job.recommend">
|
||||
<view class="falls-card" @click="nextDetail(job)">
|
||||
<view class="falls-card-pay">
|
||||
<view class="pay-text">
|
||||
<Salary-Expectation
|
||||
:max-salary="job.maxSalary"
|
||||
:min-salary="job.minSalary"
|
||||
:is-month="true"
|
||||
></Salary-Expectation>
|
||||
</view>
|
||||
<image v-if="job.isHot" class="flame" src="/static/icon/flame.png"></image>
|
||||
</view>
|
||||
<view class="falls-card-title">{{ job.jobTitle }}</view>
|
||||
<view class="fl_box fl_warp">
|
||||
<view class="falls-card-education mar_ri10" v-if="job.education">
|
||||
<dict-Label dictType="education" :value="job.education"></dict-Label>
|
||||
</view>
|
||||
<view class="falls-card-experience" v-if="job.experience">
|
||||
<dict-Label dictType="experience" :value="job.experience"></dict-Label>
|
||||
</view>
|
||||
</view>
|
||||
<view class="falls-card-company">
|
||||
青岛
|
||||
<dict-Label dictType="area" :value="job.jobLocationAreaCode"></dict-Label>
|
||||
</view>
|
||||
<view class="falls-card-pepleNumber">
|
||||
<view>
|
||||
<image class="point2" src="/static/icon/pintDate.png"></image>
|
||||
<view class="fl_1">
|
||||
{{ job.postingDate || '发布日期' }}
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<image class="point3" src="/static/icon/pointpeople.png"></image>
|
||||
<view class="fl_1">
|
||||
{{ vacanciesTo(job.vacancies) }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="falls-card-company2">
|
||||
<image class="point3" src="/static/icon/point3.png"></image>
|
||||
<view class="fl_1">
|
||||
{{ job.companyName }}
|
||||
</view>
|
||||
</view>
|
||||
<!-- <view class="falls-card-matchingrate">
|
||||
<view class=""><matchingDegree :job="job"></matchingDegree></view>
|
||||
<my-icons type="star" size="60"></my-icons>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
<view class="item" :class="{ isBut: job.isBut }" v-else>
|
||||
<view class="recommend-card">
|
||||
<view class="card-content">
|
||||
<view class="recommend-card-title">在找「{{ job.jobCategory }}」工作吗?</view>
|
||||
<view class="recommend-card-tip">{{ job.tip }}</view>
|
||||
<view class="recommend-card-line"></view>
|
||||
<view class="recommend-card-controll">
|
||||
<view class="controll-no" @click="clearfindJob(job)">不是</view>
|
||||
<view class="controll-yes" @click="findJob(job)">是的</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</custom-waterfalls-flow>
|
||||
<loadmore ref="loadmoreRef"></loadmore>
|
||||
</view>
|
||||
<empty v-if="!list.length"></empty>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<!-- 筛选 -->
|
||||
<select-filter ref="selectFilterModel"></select-filter>
|
||||
|
||||
<view class="maskFristEntry" v-if="maskFristEntry">
|
||||
<view class="entry-content">
|
||||
<text class="text1">左滑查看视频</text>
|
||||
<text class="text2">左滑查看视频</text>
|
||||
<view class="goExperience">去体验</view>
|
||||
<view class="maskFristEntry-Close" @click="closeFristEntry">1</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted, watchEffect, nextTick } from 'vue';
|
||||
import img from '@/static/icon/filter.png';
|
||||
import dictLabel from '@/components/dict-Label/dict-Label.vue';
|
||||
const { $api, navTo, vacanciesTo, formatTotal } = 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';
|
||||
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';
|
||||
const { isScrollingDown, handleScroll } = useScrollDirection();
|
||||
const recommedIndexDb = useRecommedIndexedDBStore();
|
||||
const emits = defineEmits(['onShowTabbar']);
|
||||
|
||||
const waterfallsFlowRef = ref(null);
|
||||
const loadmoreRef = ref(null);
|
||||
const conditionSearch = ref({});
|
||||
const waterfallcolumn = ref(2);
|
||||
const maskFristEntry = ref(true);
|
||||
const state = reactive({
|
||||
tabIndex: 'all',
|
||||
});
|
||||
const list = ref([]);
|
||||
const pageState = reactive({
|
||||
page: 0,
|
||||
total: 0,
|
||||
maxPage: 2,
|
||||
pageSize: 10,
|
||||
search: {
|
||||
order: 0,
|
||||
},
|
||||
});
|
||||
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: '最新发布' },
|
||||
]);
|
||||
const isLoaded = ref(false);
|
||||
|
||||
const { columnCount, columnSpace } = useColumnCount(() => {
|
||||
pageState.pageSize = 10 * (columnCount.value - 1);
|
||||
getJobRecommend('refresh');
|
||||
nextTick(() => {
|
||||
waterfallsFlowRef.value?.refresh?.();
|
||||
useLocationStore().getLocation();
|
||||
});
|
||||
});
|
||||
|
||||
async function loadData() {
|
||||
try {
|
||||
if (isLoaded.value) return;
|
||||
isLoaded.value = true;
|
||||
} catch (err) {
|
||||
isLoaded.value = false; // 重置状态允许重试
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
function scrollBottom() {
|
||||
loadmoreRef.value.change('loading');
|
||||
if (state.tabIndex === 'all') {
|
||||
getJobRecommend();
|
||||
} else {
|
||||
getJobList();
|
||||
}
|
||||
}
|
||||
|
||||
function findJob(job) {
|
||||
if (job.isBut) {
|
||||
$api.msg('已确认');
|
||||
} else {
|
||||
list.value = list.value.map((item) => {
|
||||
if (item.recommend && item.jobCategory === job.jobCategory) {
|
||||
return {
|
||||
...item,
|
||||
isBut: true,
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
const jobstr = job.jobCategory;
|
||||
const jobsObj = {
|
||||
地区: 'area',
|
||||
岗位: 'jobTitle',
|
||||
经验: 'experience',
|
||||
};
|
||||
const [name, value] = jobstr.split(':');
|
||||
const nameAttr = jobsObj[name];
|
||||
if (name === '岗位') {
|
||||
conditionSearch.value[nameAttr] = value;
|
||||
} else {
|
||||
const valueAttr = oneDictData(nameAttr).filter((item) => item.label === value);
|
||||
if (valueAttr.length) {
|
||||
const val = valueAttr[0].value;
|
||||
conditionSearch.value[nameAttr] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearfindJob(job) {
|
||||
if (job.isBut) {
|
||||
$api.msg('已确认');
|
||||
} else {
|
||||
list.value = list.value.map((item) => {
|
||||
if (item.recommend && item.jobCategory === job.jobCategory) {
|
||||
return {
|
||||
...item,
|
||||
isBut: true,
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
recommedIndexDb.deleteRecords(job);
|
||||
}
|
||||
}
|
||||
|
||||
function nextDetail(job) {
|
||||
// 记录岗位类型,用作数据分析
|
||||
if (job.jobCategory) {
|
||||
const recordData = recommedIndexDb.JobParameter(job);
|
||||
recommedIndexDb.addRecord(recordData);
|
||||
}
|
||||
navTo(`/packageA/pages/post/post?jobId=${btoa(job.jobId)}`);
|
||||
}
|
||||
|
||||
function openFilter() {
|
||||
showFilter.value = true;
|
||||
emits('onShowTabbar', false);
|
||||
uni.hideTabBar();
|
||||
selectFilterModel.value?.open({
|
||||
title: '筛选',
|
||||
maskClick: true,
|
||||
success: (values) => {
|
||||
pageState.search = {
|
||||
...pageState.search,
|
||||
};
|
||||
for (const [key, value] of Object.entries(values)) {
|
||||
pageState.search[key] = value.join(',');
|
||||
}
|
||||
showFilter.value = false;
|
||||
getJobList('refresh');
|
||||
uni.showTabBar();
|
||||
},
|
||||
cancel: () => {
|
||||
showFilter.value = false;
|
||||
emits('onShowTabbar', true);
|
||||
uni.showTabBar();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleFilterConfirm(e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
function choosePosition(index) {
|
||||
state.tabIndex = index;
|
||||
list.value = [];
|
||||
if (index === 'all') {
|
||||
pageState.search = {
|
||||
order: pageState.search.order,
|
||||
};
|
||||
inputText.value = '';
|
||||
getJobRecommend('refresh');
|
||||
} else {
|
||||
// const id = useUserStore().userInfo.jobTitleId.split(',')[index];
|
||||
pageState.search.jobTitle = userInfo.value.jobTitle[index];
|
||||
inputText.value = '';
|
||||
getJobList('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
function handelHostestSearch(val) {
|
||||
pageState.search.order = val.value;
|
||||
if (state.tabIndex === 'all') {
|
||||
getJobRecommend('refresh');
|
||||
} else {
|
||||
getJobList('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
function getJobRecommend(type = 'add') {
|
||||
if (type === 'refresh') {
|
||||
list.value = [];
|
||||
if (waterfallsFlowRef.value) waterfallsFlowRef.value.refresh();
|
||||
}
|
||||
let params = {
|
||||
pageSize: pageState.pageSize,
|
||||
sessionId: useUserStore().seesionId,
|
||||
...pageState.search,
|
||||
...conditionSearch.value,
|
||||
};
|
||||
let comd = {
|
||||
recommend: true,
|
||||
jobCategory: '',
|
||||
tip: '确认你的兴趣,为您推荐更多合适的岗位',
|
||||
};
|
||||
$api.createRequest('/app/job/recommend', params).then((resData) => {
|
||||
const { data, total } = resData;
|
||||
pageState.total = 0;
|
||||
if (type === 'add') {
|
||||
// 记录系统
|
||||
recommedIndexDb.getRecord().then((res) => {
|
||||
if (res.length) {
|
||||
// 数据分析系统
|
||||
const resultData = recommedIndexDb.analyzer(res);
|
||||
const { sort, result } = resultData;
|
||||
// 岗位询问系统
|
||||
const conditionCounts = Object.fromEntries(
|
||||
sort.filter((item) => item[1] > 1) // 过滤掉次数为 1 的项
|
||||
);
|
||||
jobRecommender.updateConditions(conditionCounts);
|
||||
|
||||
const question = jobRecommender.getNextQuestion();
|
||||
|
||||
if (question) {
|
||||
comd.jobCategory = question;
|
||||
// 生成随机插入位置,排除前两个和最后两个位置
|
||||
let insertIndex;
|
||||
if (data.length <= 4) {
|
||||
// 如果数据长度小于等于4,直接插入到中间位置
|
||||
insertIndex = Math.floor(data.length / 2);
|
||||
} else {
|
||||
// 生成2到data.length-2之间的随机位置
|
||||
insertIndex = Math.floor(Math.random() * (data.length - 4)) + 2;
|
||||
}
|
||||
data.splice(insertIndex, 0, comd);
|
||||
}
|
||||
}
|
||||
const reslist = dataToImg(data);
|
||||
list.value.push(...reslist);
|
||||
});
|
||||
} else {
|
||||
list.value = dataToImg(data);
|
||||
}
|
||||
// 切换状态
|
||||
if (loadmoreRef.value && typeof loadmoreRef.value.change === 'function') {
|
||||
if (data.length < pageState.pageSize) {
|
||||
loadmoreRef.value.change('noMore');
|
||||
} else {
|
||||
loadmoreRef.value.change('more');
|
||||
}
|
||||
}
|
||||
// 当没有岗位,刷新sessionId重新啦
|
||||
if (!data.length) {
|
||||
useUserStore().initSeesionId();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getJobList(type = 'add') {
|
||||
if (type === 'add' && pageState.page < pageState.maxPage) {
|
||||
pageState.page += 1;
|
||||
}
|
||||
if (type === 'refresh') {
|
||||
list.value = [];
|
||||
pageState.page = 1;
|
||||
pageState.maxPage = 2;
|
||||
// waterfallsFlowRef.value.refresh();
|
||||
if (waterfallsFlowRef.value) waterfallsFlowRef.value.refresh();
|
||||
}
|
||||
let params = {
|
||||
current: pageState.page,
|
||||
pageSize: pageState.pageSize,
|
||||
...pageState.search,
|
||||
// ...conditionSearch.value,
|
||||
};
|
||||
|
||||
$api.createRequest('/app/job/list', params).then((resData) => {
|
||||
const { rows, total } = resData;
|
||||
if (type === 'add') {
|
||||
const str = pageState.pageSize * (pageState.page - 1);
|
||||
const end = list.value.length;
|
||||
const reslist = dataToImg(rows);
|
||||
list.value.splice(str, end, ...reslist);
|
||||
} else {
|
||||
list.value = dataToImg(rows);
|
||||
}
|
||||
pageState.total = resData.total;
|
||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
||||
// 切换状态
|
||||
if (loadmoreRef.value && typeof loadmoreRef.value.change === 'function') {
|
||||
if (rows.length < pageState.pageSize) {
|
||||
loadmoreRef.value?.change('noMore');
|
||||
} else {
|
||||
loadmoreRef.value?.change('more');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function dataToImg(data) {
|
||||
return data.map((item) => ({
|
||||
...item,
|
||||
image: img,
|
||||
hide: true,
|
||||
}));
|
||||
}
|
||||
|
||||
defineExpose({ loadData });
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
// .maskFristEntry
|
||||
// position: fixed;
|
||||
// // right: 20rpx;
|
||||
// // bottom: calc(50% - 200rpx);
|
||||
// height: 100vh
|
||||
// width: 100vw
|
||||
// background: rgba(0,0,0,0.3)
|
||||
// .entry-content
|
||||
// display: flex;
|
||||
// align-items: center
|
||||
// position: absolute
|
||||
// left: 50%
|
||||
// top: 40%
|
||||
// transform: translate(-50%, -50%)
|
||||
// flex-direction: column
|
||||
// background: url('@/static/imgs/fristEntry.png') 0 0 no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
// width: 480rpx
|
||||
// height: 584rpx
|
||||
// // padding-left: 80rpx
|
||||
// .text1
|
||||
// margin-top: 370rpx
|
||||
// font-size: 36rpx
|
||||
// background: linear-gradient(273.34deg, #356CFA 3.58%, #A47FFD 85.84%);
|
||||
// -webkit-background-clip: text;
|
||||
// -webkit-text-fill-color: transparent;
|
||||
// background-clip: text; /* 有些浏览器兼容用 */
|
||||
// text-fill-color: transparent;
|
||||
// padding-left: 28rpx
|
||||
// .text2
|
||||
// padding-left: 28rpx
|
||||
// margin-top: 8rpx
|
||||
// font-size: 20rpx;
|
||||
// color: #666666;
|
||||
// text-align: center;
|
||||
// .indicateArrow
|
||||
// height: 76rpx
|
||||
// width: 68rpx
|
||||
// .indicatefristEntry
|
||||
// width: 244rpx
|
||||
// height: 244rpx
|
||||
// .goExperience
|
||||
// margin-left: 28rpx
|
||||
// margin-top: 28rpx
|
||||
// width: 160rpx;
|
||||
// height: 60rpx;
|
||||
// background: linear-gradient( 180deg, #9974FD 0%, #286BFA 100%);
|
||||
// border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
// font-size: 28rpx;
|
||||
// color: #FFFFFF;
|
||||
// text-align: center;
|
||||
// line-height: 60rpx
|
||||
// .maskFristEntry-Close
|
||||
// position: absolute;
|
||||
// left: calc(50% - 10rpx);
|
||||
// bottom: -130rpx
|
||||
// width: 42rpx
|
||||
// height: 42rpx
|
||||
// background: linear-gradient(273.34deg, #356CFA 3.58%, #A47FFD 85.84%);
|
||||
// border-radius: 50%;
|
||||
// .maskFristEntry-Close::before
|
||||
// position: absolute;
|
||||
// left: calc( 50% - 2rpx)
|
||||
// top: calc( 50% - 10rpx)
|
||||
// transform: rotate(45deg);
|
||||
// content: ''
|
||||
// background: #FFFFFF
|
||||
// width: 4rpx
|
||||
// height: 20rpx
|
||||
// .maskFristEntry-Close::after
|
||||
// position: absolute;
|
||||
// left: calc( 50% - 2rpx)
|
||||
// top: calc( 50% - 10rpx)
|
||||
// transform: rotate(-45deg);
|
||||
// content: ''
|
||||
// background: #FFFFFF
|
||||
// width: 4rpx
|
||||
// height: 20rpx
|
||||
|
||||
|
||||
.app-container
|
||||
width: 100%;
|
||||
height: calc(100vh - var(--window-top) - var(--status-bar-height) - var(--window-bottom));
|
||||
background: url('@/static/icon/background2.png') 0 0 no-repeat;
|
||||
background-size: 100% 728rpx;
|
||||
background-color: #FFFFFF;
|
||||
display: flex;
|
||||
flex-direction: column
|
||||
.hidden-animation
|
||||
max-height: 1000px;
|
||||
transition: all 0.3s ease;
|
||||
overflow: hidden;
|
||||
.hidden-height
|
||||
max-height: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
.container-search
|
||||
padding: 16rpx 24rpx
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
.search-input
|
||||
display: flex
|
||||
align-items: center;
|
||||
width: 100%
|
||||
height: 80rpx;
|
||||
line-height: 80rpx
|
||||
// margin-right: 24rpx
|
||||
background: #FFFFFF;
|
||||
border-radius: 75rpx 75rpx 75rpx 75rpx;
|
||||
.iconsearch
|
||||
padding-left: 36rpx
|
||||
.inpute
|
||||
margin-left: 20rpx
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #B5B5B5;
|
||||
width: 100%
|
||||
.chart
|
||||
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
|
||||
width: 170rpx;
|
||||
background: radial-gradient( 0% 56% at 87% 61%, rgba(255,255,255,0.82) 0%, rgba(255,255,255,0.47) 100%);
|
||||
box-shadow: 0rpx 8rpx 40rpx 0rpx rgba(210,210,210,0.14);
|
||||
border-radius: 80rpx 80rpx 80rpx 80rpx;
|
||||
border: 2rpx solid #FFFFFF;
|
||||
text-align: center
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
height: 36rpx;
|
||||
color: #000000;
|
||||
padding: 20rpx 30rpx
|
||||
.cards
|
||||
padding: 10rpx 28rpx
|
||||
display: grid
|
||||
grid-gap: 38rpx;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
.card
|
||||
height: calc(158rpx - 40rpx);
|
||||
padding: 22rpx 26rpx
|
||||
box-shadow: 0rpx 8rpx 40rpx 0rpx rgba(210,210,210,0.14);
|
||||
border-radius: 16rpx 16rpx 16rpx 16rpx;
|
||||
border: 2rpx solid #FFFFFF;
|
||||
.card-title
|
||||
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 32rpx;
|
||||
color: #000000;
|
||||
.card-text
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #9E9E9E;
|
||||
margin-top: 4rpx
|
||||
.card:first-child
|
||||
background: radial-gradient( 0% 56% at 87% 61%, rgba(255,255,255,0.82) 0%, rgba(255,255,255,0.47) 100%),
|
||||
url('@/static/icon/fujin.png');
|
||||
background-size: 100%, 100%
|
||||
.card:last-child
|
||||
background: radial-gradient( 0% 56% at 87% 61%, rgba(255,255,255,0.82) 0%, rgba(255,255,255,0.47) 100%),
|
||||
url('@/static/icon/jinxuan.png');
|
||||
background-size: 100%, 100%
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
|
||||
.nav-filter
|
||||
padding: 16rpx 28rpx 0 28rpx
|
||||
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
|
||||
.filter-top
|
||||
display: flex
|
||||
justify-content: space-between;
|
||||
.tab-scroll
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
margin-right: 20rpx
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: clip;
|
||||
-webkit-mask-image: linear-gradient(to right, black 60%, transparent);
|
||||
mask-image: linear-gradient(to right, black 60%, transparent);
|
||||
.jobs-left
|
||||
display: flex
|
||||
flex-wrap: nowrap
|
||||
.job
|
||||
font-weight: 400;
|
||||
font-size: 36rpx;
|
||||
color: #666D7F;
|
||||
margin-right: 32rpx;
|
||||
white-space: nowrap
|
||||
.active
|
||||
font-weight: 500;
|
||||
font-size: 36rpx;
|
||||
color: #000000;
|
||||
.jobs-add
|
||||
font-family: 'PingFangSC-Regular', 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
display: flex
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
color: #666D7F;
|
||||
line-height: 38rpx;
|
||||
.filter-bottom
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
padding: 24rpx 0
|
||||
.btm-left
|
||||
display: flex
|
||||
font-family: 'PingFangSC-Regular', 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
.filterbtm
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
color: #666D7F;
|
||||
margin-right: 24rpx
|
||||
padding: 0rpx 16rpx
|
||||
.active
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #256BFA;
|
||||
.btm-right
|
||||
font-family: 'PingFangSC-Regular', 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
color: #6C7282;
|
||||
.right-sx
|
||||
width: 26rpx;
|
||||
height: 26rpx;
|
||||
.active
|
||||
transform: rotate(180deg)
|
||||
.table-list
|
||||
background: #F4F4F4
|
||||
flex: 1
|
||||
overflow: hidden
|
||||
.falls-scroll
|
||||
width: 100%
|
||||
height: 100%
|
||||
.falls
|
||||
padding: 28rpx 28rpx;
|
||||
.item
|
||||
position: relative;
|
||||
// background: linear-gradient( 180deg, rgba(19, 197, 124, 0.4) 0%, rgba(255, 255, 255, 0) 30%), rgba(255, 255, 255, 0);
|
||||
.falls-card
|
||||
padding: 30rpx;
|
||||
.falls-card-title
|
||||
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
|
||||
color: #606060;
|
||||
text-align: left;
|
||||
word-break:break-all
|
||||
font-weight: 500;
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
margin-top: 10rpx
|
||||
.falls-card-pay
|
||||
// height: 50rpx;
|
||||
word-break:break-all
|
||||
color: #002979;
|
||||
text-align: left;
|
||||
display: flex;
|
||||
align-items: end;
|
||||
position: relative
|
||||
.pay-text
|
||||
font-family: DIN-Medium;
|
||||
color: #4C6EFB;
|
||||
padding-right: 10rpx
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #4C6EFB;
|
||||
line-height: 45rpx;
|
||||
text-align: left;
|
||||
.flame
|
||||
position: absolute
|
||||
bottom: 0
|
||||
right: -10rpx
|
||||
transform: translate(0, -30%)
|
||||
width: 24rpx
|
||||
height: 31rpx
|
||||
.falls-card-education,.falls-card-experience
|
||||
width: fit-content;
|
||||
height: 30rpx;
|
||||
background: #F4F4F4;
|
||||
border-radius: 4rpx;
|
||||
padding: 6rpx 20rpx;
|
||||
line-height: 30rpx;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #6C7282;
|
||||
text-align: center;
|
||||
margin-top: 20rpx;
|
||||
white-space: nowrap
|
||||
|
||||
.falls-card-company,.falls-card-pepleNumber
|
||||
margin-top: 20rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
line-height: 25rpx;
|
||||
text-align: left;
|
||||
.falls-card-pepleNumber
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap
|
||||
margin-top: 10rpx;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
line-height: 46rpx
|
||||
view
|
||||
display:flex
|
||||
align-items: center
|
||||
white-space: nowrap;
|
||||
.point2
|
||||
margin: 0rpx 6rpx 0 2rpx
|
||||
height: 22rpx
|
||||
width: 22rpx
|
||||
.point3
|
||||
margin: 0rpx 4rpx 0 0
|
||||
height: 28rpx
|
||||
width: 28rpx
|
||||
.falls-card-matchingrate
|
||||
margin-top: 10rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 21rpx;
|
||||
color: #4778EC;
|
||||
text-align: left;
|
||||
.falls-card-company2
|
||||
margin-top: 4rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
text-align: left;
|
||||
display: flex
|
||||
.point3
|
||||
margin: 4rpx 4rpx 0 0
|
||||
height: 26rpx
|
||||
width: 26rpx
|
||||
// 推荐卡片
|
||||
.recommend-card::before
|
||||
position: absolute
|
||||
left: 0
|
||||
top: 0
|
||||
content: ''
|
||||
height: 60rpx
|
||||
width: 100%
|
||||
height: 8rpx;
|
||||
background: linear-gradient( to left, #9E74FD 0%, #256BFA 100%);
|
||||
box-shadow: 0rpx 8rpx 40rpx 0rpx rgba(0,54,170,0.15);
|
||||
.recommend-card::after
|
||||
content ''
|
||||
position absolute
|
||||
z-index 0
|
||||
left 50%
|
||||
top 40%
|
||||
transform: translate(-50%, -50%)
|
||||
width 250rpx
|
||||
height 250rpx
|
||||
background url('@/static/icon/backAI.png') no-repeat center center
|
||||
opacity 0.6
|
||||
background-size contain
|
||||
pointer-events none
|
||||
filter: blur(3rpx)
|
||||
.recommend-card
|
||||
padding 36rpx 24rpx
|
||||
background: linear-gradient( 360deg, #DFE9FF 0%, #FFFFFF 52%, #FFFFFF 100%);
|
||||
border-radius: 20rpx 20rpx 20rpx 20rpx;
|
||||
position relative
|
||||
box-shadow 0rpx 4rpx 8rpx 0rpx rgba(72, 89, 123, 0.3)
|
||||
.card-content
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
.recommend-card-title
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
.recommend-card-tip
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
margin-top: 28rpx
|
||||
.recommend-card-line
|
||||
width: calc(100%);
|
||||
height: 0rpx;
|
||||
border-radius: 0rpx 0rpx 0rpx 0rpx;
|
||||
border: 2rpx dashed rgba(0,0,0,0.14);
|
||||
margin-top: 50rpx
|
||||
position: relative
|
||||
// .recommend-card-line::before
|
||||
// position: absolute
|
||||
// content: ''
|
||||
// left: 0
|
||||
// top: 0
|
||||
// transform: translate(-50% - 90rpx, -50%)
|
||||
// width: 28rpx;
|
||||
// height: 28rpx;
|
||||
// background: #F4F4F4;
|
||||
// border-radius: 50%;
|
||||
// .recommend-card-line::after
|
||||
// position: absolute
|
||||
// content: ''
|
||||
// right: 0
|
||||
// top: 0
|
||||
// transform: translate(50% + 90rpx, -50%)
|
||||
// width: 28rpx;
|
||||
// height: 28rpx;
|
||||
// background: #F4F4F4;
|
||||
// border-radius: 50%;
|
||||
.recommend-card-controll
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: space-between
|
||||
margin-top: 40rpx
|
||||
padding: 0 6rpx;
|
||||
.controll-yes
|
||||
width: 124rpx;
|
||||
height: 60rpx;
|
||||
background: rgba(37,107,250,0.1);
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
text-align: center;
|
||||
line-height: 60rpx
|
||||
color: #256BFA
|
||||
.controll-no
|
||||
width: 124rpx;
|
||||
height: 56rpx;
|
||||
line-height: 56rpx
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
border: 2rpx solid #DEDEDE;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
text-align: center;
|
||||
.controll-yes:active, .controll-no:active
|
||||
width: 120rpx;
|
||||
height: 66rpx;
|
||||
line-height: 66rpx
|
||||
background: #e8e8e8
|
||||
border: 2rpx solid #e8e8e8
|
||||
.isBut{
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
</style>
|
||||
@@ -20,7 +20,7 @@
|
||||
<image class="bg-robot button-click" mode="widthFix" src="@/static/icon/index-robot.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="ai-card-out">
|
||||
<view v-if="!isMachineEnv" class="ai-card-out" >
|
||||
<view class="ai-card">
|
||||
<image class="ai-card-bg" src="@/static/icon/ai-card-bg.png" />
|
||||
<view class="ai-card-inner">
|
||||
@@ -56,7 +56,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="match-card-out">
|
||||
<view v-if="hasLogin" :class="{'match-move-top':isMachineEnv}" class="match-card-out">
|
||||
<view class="match-card">
|
||||
<image class="match-card-bg" src="@/static/icon/match-card-bg.png" />
|
||||
<view class="title">简历匹配职位</view>
|
||||
@@ -65,8 +65,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="cards">
|
||||
<view :class="{'cards-move-top':isMachineEnv && !hasLogin}" class="cards">
|
||||
<view class="card card1 press-button" @click="navTo('/pages/nearby/nearby')">
|
||||
<view class="card-title">附近工作</view>
|
||||
<view class="card-text">好岗职等你来</view>
|
||||
@@ -259,7 +258,7 @@ const { $api, navTo, vacanciesTo, formatTotal, throttle } = inject('globalFuncti
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
const { userInfo } = storeToRefs(useUserStore());
|
||||
const { userInfo, hasLogin ,isMachineEnv} = storeToRefs(useUserStore());
|
||||
import useDictStore from '@/stores/useDictStore';
|
||||
const { getTransformChildren, oneDictData } = useDictStore();
|
||||
import useLocationStore from '@/stores/useLocationStore';
|
||||
@@ -272,6 +271,7 @@ const recommedIndexDb = useRecommedIndexedDBStore();
|
||||
import config from '@/config';
|
||||
import AIMatch from './AIMatch.vue';
|
||||
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
const maskFirstEntry = ref(true);
|
||||
@@ -316,24 +316,85 @@ const isLoaded = ref(false);
|
||||
|
||||
const colors = ['#0069FE', '#FF9400', '#FF6969', '#21EA85', '#87E2EC'];
|
||||
|
||||
const occupations = [
|
||||
'律师',
|
||||
'工程师',
|
||||
'医生',
|
||||
'教师',
|
||||
'设计师',
|
||||
'程序员',
|
||||
'会计师',
|
||||
'建筑师',
|
||||
'护士',
|
||||
'销售',
|
||||
'经理',
|
||||
'顾问',
|
||||
'分析师',
|
||||
'研究员',
|
||||
'编辑',
|
||||
'记者',
|
||||
'摄影师',
|
||||
'厨师',
|
||||
'司机',
|
||||
'保安',
|
||||
'客服',
|
||||
'行政',
|
||||
'人事',
|
||||
'市场',
|
||||
'运营',
|
||||
'产品',
|
||||
'测试',
|
||||
'运维',
|
||||
'前端',
|
||||
'后端',
|
||||
'全栈',
|
||||
'数据',
|
||||
'策划',
|
||||
'导演',
|
||||
'演员',
|
||||
'歌手',
|
||||
'作家',
|
||||
'画家',
|
||||
'翻译',
|
||||
'导游',
|
||||
];
|
||||
|
||||
onMounted(() => {
|
||||
let firstEntry = uni.getStorageSync('firstEntry') === false ? false : true; // 默认未读
|
||||
maskFirstEntry.value = firstEntry;
|
||||
getMatchTags();
|
||||
console.log(isMachineEnv.value,'+++++++++')
|
||||
});
|
||||
|
||||
async function getMatchTags() {
|
||||
try {
|
||||
matchLoading.value = true;
|
||||
const { data } = await $api.createRequest('/app/user/getJobAdviceByResume');
|
||||
matchTags.value = data;
|
||||
matchLoading.value = false;
|
||||
} catch (err) {
|
||||
console.err('简历匹配职位获取失败');
|
||||
} finally {
|
||||
if (hasLogin.value) {
|
||||
try {
|
||||
matchLoading.value = true;
|
||||
const { data } = await $api.createRequest('/app/user/getJobAdviceByResume');
|
||||
matchTags.value = data;
|
||||
matchLoading.value = false;
|
||||
} catch (err) {
|
||||
console.error('简历匹配职位获取失败');
|
||||
}
|
||||
} else {
|
||||
const vals = getRandomStrings(occupations).map((text) => ({
|
||||
job_name: text,
|
||||
score: 0,
|
||||
}));
|
||||
matchTags.value = vals;
|
||||
}
|
||||
}
|
||||
|
||||
function getRandomStrings(arr, count = 10) {
|
||||
const size = Math.min(arr.length, count);
|
||||
const shuffled = [...arr];
|
||||
for (let i = shuffled.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
||||
}
|
||||
return shuffled.slice(0, size);
|
||||
}
|
||||
|
||||
const checkStickyStatus = (e) => {
|
||||
scrollTop.value = e.detail.scrollTop;
|
||||
nextTick(() => {
|
||||
@@ -830,6 +891,12 @@ defineExpose({ loadData });
|
||||
height: 36rpx;
|
||||
color: #000000;
|
||||
padding: 20rpx 30rpx
|
||||
.match-move-top
|
||||
margin-top:-20rpx !important;
|
||||
.cards-move-top
|
||||
margin-top:-60rpx !important;
|
||||
position:relative;
|
||||
z-index:1
|
||||
.ai-card-out
|
||||
width:100%;
|
||||
box-sizing:border-box
|
||||
|
||||
@@ -18,25 +18,11 @@
|
||||
v-for="(_, index) in 2"
|
||||
:key="index"
|
||||
>
|
||||
<!-- #ifndef MP-WEIXIN -->
|
||||
<component
|
||||
:is="components[index]"
|
||||
@onShowTabbar="changeShowTabbar"
|
||||
:ref="(el) => handelComponentsRef(el, index)"
|
||||
/>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<IndexOne
|
||||
v-show="currentIndex === 0"
|
||||
@onShowTabbar="changeShowTabbar"
|
||||
:ref="(el) => handelComponentsRef(el, index)"
|
||||
/>
|
||||
<IndexTwo
|
||||
v-show="currentIndex === 1"
|
||||
@onShowTabbar="changeShowTabbar"
|
||||
:ref="(el) => handelComponentsRef(el, index)"
|
||||
/>
|
||||
<!-- #endif -->
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
@@ -61,17 +47,14 @@ import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import Tabbar from '@/components/tabbar/midell-box.vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import IndexRefactor from './components/index-refactor.vue';
|
||||
import IndexOne from './components/index-one.vue';
|
||||
import IndexTwo from './components/index-two.vue';
|
||||
import useScreenStore from '@/stores/useScreenStore'
|
||||
|
||||
const screenStore = useScreenStore()
|
||||
const {isWideScreen} = screenStore
|
||||
import useScreenStore from '@/stores/useScreenStore';
|
||||
|
||||
const screenStore = useScreenStore();
|
||||
const { isWideScreen } = screenStore;
|
||||
|
||||
const loadedMap = reactive([false, false]);
|
||||
const swiperRefs = [ref(null), ref(null)];
|
||||
// const components = [IndexOne, IndexTwo];
|
||||
const components = [IndexRefactor, IndexTwo];
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useReadMsg } from '@/stores/useReadMsg';
|
||||
@@ -87,21 +70,20 @@ const THRESHOLD = 5;
|
||||
watch(
|
||||
() => screenStore.isWideScreen,
|
||||
(newVal) => {
|
||||
showTabbar.value = newVal
|
||||
showTabbar.value = newVal;
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
onLoad(() => {
|
||||
// 判断浏览器是否有 fristEntry 第一次进入
|
||||
let fristEntry = uni.getStorageSync('fristEntry') === false ? false : true; // 默认未读
|
||||
maskFristEntry.value = fristEntry
|
||||
maskFristEntry.value = fristEntry;
|
||||
if (fristEntry) {
|
||||
if(!isWideScreen)uni.hideTabBar();
|
||||
else showTabbar.value = false
|
||||
}else{
|
||||
if(isWideScreen)showTabbar.value = true
|
||||
if (!isWideScreen) uni.hideTabBar();
|
||||
else showTabbar.value = false;
|
||||
} else {
|
||||
if (isWideScreen) showTabbar.value = true;
|
||||
}
|
||||
// 预加载较重页面
|
||||
setTimeout(() => {
|
||||
@@ -163,11 +145,11 @@ function handleTouchMove(e) {
|
||||
}
|
||||
|
||||
function changeShowTabbar(val) {
|
||||
if(isWideScreen){
|
||||
showTabbar.value=val
|
||||
}else{
|
||||
if(val)uni.showTabBar()
|
||||
else uni.hideTabBar()
|
||||
if (isWideScreen) {
|
||||
showTabbar.value = val;
|
||||
} else {
|
||||
if (val) uni.showTabBar();
|
||||
else uni.hideTabBar();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,14 +205,14 @@ function changeSwiperMsgType(e) {
|
||||
function closeFristEntry() {
|
||||
uni.setStorageSync('fristEntry', false);
|
||||
maskFristEntry.value = false;
|
||||
if(!isWideScreen)uni.showTabBar();
|
||||
else showTabbar.value=true
|
||||
if (!isWideScreen) uni.showTabBar();
|
||||
else showTabbar.value = true;
|
||||
}
|
||||
|
||||
function goExperience() {
|
||||
closeFristEntry();
|
||||
if(!isWideScreen)uni.showTabBar();
|
||||
else showTabbar.value = true
|
||||
if (!isWideScreen) uni.showTabBar();
|
||||
else showTabbar.value = true;
|
||||
state.current = 1;
|
||||
}
|
||||
</script>
|
||||
@@ -393,4 +375,4 @@ function goExperience() {
|
||||
background: #FFFFFF
|
||||
width: 4rpx
|
||||
height: 20rpx
|
||||
</style>
|
||||
</style>
|
||||
@@ -1,6 +1,78 @@
|
||||
<template>
|
||||
<AppLayout title="就业服务程序">
|
||||
<tabcontrolVue :current="tabCurrent">
|
||||
<view v-if="isMachineEnv" class="alipay-login-container">
|
||||
<!-- 切换 -->
|
||||
<view class="login-method-switch">
|
||||
<view
|
||||
class="method-item"
|
||||
:class="{ active: loginMethod === 'face' }"
|
||||
@click="switchLoginMethod('face')"
|
||||
>
|
||||
扫脸登录
|
||||
</view>
|
||||
<view
|
||||
class="method-item"
|
||||
:class="{ active: loginMethod === 'qrcode' }"
|
||||
@click="switchLoginMethod('qrcode')"
|
||||
>
|
||||
扫码登录
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="login-scan-area">
|
||||
<view class="login-title">{{ loginMethod === 'qrcode' ? '扫码登录' : '扫脸登录' }}</view>
|
||||
<view class="qrcode-tips">
|
||||
<text class="tips-text">
|
||||
{{ loginMethod === 'qrcode' ? '请将二维码对准机器下方' : '请将面部对准摄像头区域' }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 扫码登录 -->
|
||||
<view v-if="loginMethod === 'qrcode'" class="qrcode-container">
|
||||
<view class="qrcode-wrapper">
|
||||
<view class="qrcode-border">
|
||||
<view class="qrcode-content">
|
||||
<view class="qrcode-pattern">
|
||||
<image class="qrcode-img" src="@/static/icon/qrcode.png" />
|
||||
<view class="qrcode-corner top-left"></view>
|
||||
<view class="qrcode-corner top-right"></view>
|
||||
<view class="qrcode-corner bottom-left"></view>
|
||||
<view class="qrcode-corner bottom-right"></view>
|
||||
<view class="scan-line" :style="{ top: scanLineTop + 'rpx' }"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 扫脸登录 -->
|
||||
<view v-else class="face-container">
|
||||
<view class="face-wrapper">
|
||||
<view class="face-border">
|
||||
<view class="face-content">
|
||||
<view class="face-pattern">
|
||||
<image class="face-img" src="@/static/icon/face-icon.png" />
|
||||
<view class="face-scan-arc arc-1"></view>
|
||||
<view class="face-scan-arc arc-2"></view>
|
||||
<view class="face-scan-arc arc-3"></view>
|
||||
<view class="scan-line" :style="{ top: scanLineTop + 'rpx' }"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="countdown-container">
|
||||
<view class="countdown-wrapper">
|
||||
<text class="countdown-number">{{ countdown }}</text>
|
||||
<text class="countdown-text">秒后自动返回</text>
|
||||
</view>
|
||||
<view class="cancel-btn" @click="cancelLogin">取消登录</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 正常登录-->
|
||||
<tabcontrolVue v-else :current="tabCurrent">
|
||||
<template v-slot:tab0>
|
||||
<view class="login-content">
|
||||
<image class="logo" src="@/static/logo.png"></image>
|
||||
@@ -110,21 +182,23 @@
|
||||
</tabcontrolVue>
|
||||
<SelectJobs ref="selectJobsModel"></SelectJobs>
|
||||
<!-- 后门 -->
|
||||
<view class="backdoor" @click="loginbackdoor">
|
||||
<view class="backdoor" v-if="!isMachineEnv" @click="loginbackdoor">
|
||||
<my-icons type="gift-filled" size="60"></my-icons>
|
||||
</view>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { storeToRefs } from 'pinia';
|
||||
import tabcontrolVue from './components/tabcontrol.vue';
|
||||
import SelectJobs from '@/components/selectJobs/selectJobs.vue';
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import { reactive, inject, watch, ref, onMounted, onUnmounted } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import useDictStore from '@/stores/useDictStore';
|
||||
const { $api, navTo } = inject('globalFunction');
|
||||
const { loginSetToken, getUserResume } = useUserStore();
|
||||
const { isMachineEnv } = storeToRefs(useUserStore());
|
||||
const { getDictSelectOption, oneDictData } = useDictStore();
|
||||
const openSelectPopup = inject('openSelectPopup');
|
||||
// status
|
||||
@@ -152,12 +226,85 @@ const fromValue = reactive({
|
||||
experience: '1',
|
||||
});
|
||||
|
||||
// 扫码扫脸登录
|
||||
const scanLineTop = ref(0);
|
||||
let scanInterval = null;
|
||||
const countdown = ref(60);
|
||||
let countdownTimer = null;
|
||||
const loginMethod = ref('face'); // 'qrcode' / 'face'
|
||||
|
||||
onLoad((parmas) => {
|
||||
getTreeselect();
|
||||
$api.msg('请完善微简历');
|
||||
if (!isMachineEnv.value) $api.msg('请完善微简历');
|
||||
});
|
||||
|
||||
onMounted(() => {});
|
||||
onMounted(() => {
|
||||
if (isMachineEnv) {
|
||||
startCountdown();
|
||||
startScanAnimation();
|
||||
}
|
||||
});
|
||||
onUnmounted(() => {
|
||||
stopScanAnimation();
|
||||
stopCountdown();
|
||||
});
|
||||
|
||||
const startCountdown = () => {
|
||||
stopCountdown();
|
||||
countdown.value = 60;
|
||||
countdownTimer = setInterval(() => {
|
||||
countdown.value--;
|
||||
if (countdown.value <= 0) {
|
||||
returnToHome();
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const stopCountdown = () => {
|
||||
if (countdownTimer) {
|
||||
clearInterval(countdownTimer);
|
||||
countdownTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
const resetCountdown = () => {
|
||||
stopCountdown();
|
||||
startCountdown();
|
||||
};
|
||||
|
||||
// 返回首页
|
||||
const returnToHome = () => {
|
||||
stopCountdown();
|
||||
stopScanAnimation();
|
||||
useUserStore().logOutApp();
|
||||
};
|
||||
|
||||
// 取消登录
|
||||
const cancelLogin = () => {
|
||||
returnToHome();
|
||||
};
|
||||
|
||||
// 切换登录方式
|
||||
const switchLoginMethod = (method) => {
|
||||
if (loginMethod.value !== method) {
|
||||
loginMethod.value = method;
|
||||
resetCountdown();
|
||||
}
|
||||
};
|
||||
|
||||
// 开始动画
|
||||
const startScanAnimation = () => {
|
||||
clearInterval(scanInterval);
|
||||
|
||||
scanInterval = setInterval(() => {
|
||||
scanLineTop.value = (scanLineTop.value + 2) % 300;
|
||||
}, 30);
|
||||
};
|
||||
|
||||
// 停止动画
|
||||
const stopScanAnimation = () => {
|
||||
clearInterval(scanInterval);
|
||||
};
|
||||
|
||||
function changeSex(sex) {
|
||||
fromValue.sex = sex;
|
||||
@@ -250,6 +397,11 @@ function getTreeselect() {
|
||||
}
|
||||
|
||||
function loginbackdoor() {
|
||||
if (isMachineEnv.value) {
|
||||
useUserStore().logOutApp();
|
||||
$api.msg('返回首页');
|
||||
return;
|
||||
}
|
||||
$api.createRequest('/app/mock/login', {}, 'post').then((resData) => {
|
||||
$api.msg('模拟帐号密码测试登录成功');
|
||||
loginSetToken(resData.token).then((resume) => {
|
||||
@@ -311,6 +463,316 @@ function complete() {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.alipay-login-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 40rpx 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 登录方式切换 */
|
||||
.login-method-switch {
|
||||
display: flex;
|
||||
width: 80%;
|
||||
margin-bottom: 40rpx;
|
||||
background: #f5f5f5;
|
||||
border-radius: 50rpx;
|
||||
padding: 6rpx;
|
||||
}
|
||||
|
||||
.method-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 20rpx 0;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
border-radius: 50rpx;
|
||||
transition: all 0.3s;
|
||||
|
||||
&.active {
|
||||
background: #1677ff;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
/* 扫码登录区域样式 */
|
||||
.login-scan-area {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0 40rpx;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #1677ff;
|
||||
margin-bottom: 20rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.qrcode-tips {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.tips-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 二维码容器 */
|
||||
.qrcode-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.qrcode-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.qrcode-border {
|
||||
width: 400rpx;
|
||||
height: 400rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 20rpx;
|
||||
padding: 20rpx;
|
||||
box-shadow: 0 8rpx 30rpx rgba(22, 119, 255, 0.1);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.qrcode-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 10rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.qrcode-pattern {
|
||||
width: 300rpx;
|
||||
height: 300rpx;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.qrcode-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.qrcode-corner {
|
||||
position: absolute;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 6rpx solid #1677ff;
|
||||
|
||||
&.top-left {
|
||||
top: 0;
|
||||
left: 0;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
border-radius: 10rpx 0 0 0;
|
||||
}
|
||||
|
||||
&.top-right {
|
||||
top: 0;
|
||||
right: 0;
|
||||
border-left: none;
|
||||
border-bottom: none;
|
||||
border-radius: 0 10rpx 0 0;
|
||||
}
|
||||
|
||||
&.bottom-left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
border-radius: 0 0 0 10rpx;
|
||||
}
|
||||
|
||||
&.bottom-right {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-left: none;
|
||||
border-top: none;
|
||||
border-radius: 0 0 10rpx 0;
|
||||
}
|
||||
}
|
||||
|
||||
.scan-line {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 6rpx;
|
||||
background: linear-gradient(90deg, transparent, #217bf9, transparent);
|
||||
box-shadow: 0 -6rpx 4rpx #ffffff;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/* 扫脸登录样式 */
|
||||
.face-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.face-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.face-border {
|
||||
width: 400rpx;
|
||||
height: 400rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
padding: 20rpx;
|
||||
box-shadow: 0 8rpx 30rpx rgba(22, 119, 255, 0.1);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.face-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.face-pattern {
|
||||
width: 300rpx;
|
||||
height: 300rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.face-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.face-scan-arc {
|
||||
position: absolute;
|
||||
border: 4rpx solid transparent;
|
||||
border-top-color: #1677ff;
|
||||
border-radius: 50%;
|
||||
width: 300rpx;
|
||||
height: 300rpx;
|
||||
top: 0rpx;
|
||||
left: 0rpx;
|
||||
|
||||
&.arc-1 {
|
||||
animation: faceScanRotate1 3s linear infinite;
|
||||
}
|
||||
|
||||
&.arc-2 {
|
||||
transform: rotate(120deg);
|
||||
animation: faceScanRotate2 3s linear infinite;
|
||||
}
|
||||
|
||||
&.arc-3 {
|
||||
transform: rotate(240deg);
|
||||
animation: faceScanRotate3 3s linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes faceScanRotate1 {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@keyframes faceScanRotate2 {
|
||||
0% {
|
||||
transform: rotate(120deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(480deg);
|
||||
}
|
||||
}
|
||||
@keyframes faceScanRotate3 {
|
||||
0% {
|
||||
transform: rotate(240deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(600deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* 底部操作区域 */
|
||||
.bottom-action-area {
|
||||
width: 100%;
|
||||
padding: 40rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 30rpx;
|
||||
}
|
||||
|
||||
.countdown-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.countdown-number {
|
||||
font-size: 40rpx;
|
||||
font-weight: 600;
|
||||
color: #1677ff;
|
||||
min-width: 60rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.countdown-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
margin-top: 20rpx;
|
||||
width: 300rpx;
|
||||
height: 80rpx;
|
||||
background: transparent;
|
||||
border: 2rpx solid #1677ff;
|
||||
border-radius: 50rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32rpx;
|
||||
color: #1677ff;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s;
|
||||
&:active {
|
||||
background: rgba(22, 119, 255, 0.1);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.backdoor{
|
||||
position: fixed;
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
</view>
|
||||
<view class="row-right">已认证</view>
|
||||
</view>
|
||||
<view class="main-row btn-feel" @click="handleItemClick('素质测评')">
|
||||
<view v-if="!isMachineEnv" class="main-row btn-feel" @click="handleItemClick('素质测评')">
|
||||
<view class="row-left">
|
||||
<image class="left-img" src="@/static/icon/server2.png"></image>
|
||||
<text class="left-text">素质测评</text>
|
||||
@@ -65,7 +65,7 @@
|
||||
<my-icons color="#909090" type="right" size="28"></my-icons>
|
||||
</view>
|
||||
</view>
|
||||
<view class="main-row btn-feel" @click="handleItemClick('模拟面试')">
|
||||
<view v-if="!isMachineEnv" class="main-row btn-feel" @click="handleItemClick('模拟面试')">
|
||||
<view class="row-left">
|
||||
<image class="left-img" src="@/static/icon/server3.png"></image>
|
||||
<text class="left-text">AI面试</text>
|
||||
@@ -82,7 +82,7 @@
|
||||
<view class="row-right">已开启</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- <view class="card-back button-click" @click="logOut">退出登录</view> -->
|
||||
<view class="card-back button-click" v-if="isMachineEnv" @click="logOut">退出登录</view>
|
||||
<uni-popup ref="popup" type="dialog">
|
||||
<uni-popup-dialog
|
||||
mode="base"
|
||||
@@ -112,22 +112,20 @@ const { $api, navTo } = inject('globalFunction');
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
|
||||
const popup = ref(null);
|
||||
const { userInfo, Completion, counts } = storeToRefs(useUserStore());
|
||||
const { userInfo, Completion, counts, isMachineEnv } = storeToRefs(useUserStore());
|
||||
|
||||
import useScreenStore from '@/stores/useScreenStore'
|
||||
const screenStore = useScreenStore()
|
||||
import useScreenStore from '@/stores/useScreenStore';
|
||||
const screenStore = useScreenStore();
|
||||
|
||||
const showTabbar = ref(false)
|
||||
const showTabbar = ref(false);
|
||||
|
||||
watch(
|
||||
() => screenStore.isWideScreen,
|
||||
(newVal) => {
|
||||
showTabbar.value = newVal
|
||||
showTabbar.value = newVal;
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
|
||||
);
|
||||
|
||||
function logOut() {
|
||||
popup.value.open();
|
||||
@@ -357,4 +355,4 @@ const handleItemClick = (item) => {
|
||||
border-radius: 2rpx
|
||||
background: #A2A2A2;
|
||||
transform: rotate(45deg)
|
||||
</style>
|
||||
</style>
|
||||
@@ -2,7 +2,7 @@
|
||||
<scroll-view :scroll-y="true" class="nearby-scroll" @scrolltolower="scrollBottom">
|
||||
<view class="nearby-map" @touchmove.stop.prevent>
|
||||
<map
|
||||
style="width: 100%; height:410rpx "
|
||||
style="width: 100%; height: 410rpx"
|
||||
:latitude="latitudeVal"
|
||||
:longitude="longitudeVal"
|
||||
:markers="mapCovers"
|
||||
@@ -16,7 +16,7 @@
|
||||
<image class="view-sx" :class="{ active: rangeShow }" src="@/static/icon/shaixun.png"></image>
|
||||
</view>
|
||||
<transition name="fade-slide">
|
||||
<view class="select-list" v-if="rangeShow">
|
||||
<view class="select-list" v-show="rangeShow">
|
||||
<view class="list-item button-click" v-for="(item, index) in range" @click="changeRadius(item)">
|
||||
{{ item }}km
|
||||
</view>
|
||||
@@ -147,6 +147,7 @@ function changeRangeShow() {
|
||||
}
|
||||
|
||||
function changeRadius(item) {
|
||||
console.log(item);
|
||||
pageState.search.radius = item;
|
||||
rangeShow.value = false;
|
||||
progressChange(item);
|
||||
@@ -244,7 +245,7 @@ function getInit() {
|
||||
}
|
||||
|
||||
function progressChange(value) {
|
||||
const range = 1 + value;
|
||||
const range = value < 1 ? 1 : value;
|
||||
pageState.search.radius = range;
|
||||
mapCircles.value = [
|
||||
{
|
||||
|
||||
BIN
static/font/DIN-Medium.woff2
Normal file
BIN
static/font/PingFangSC-Medium.woff2
Normal file
BIN
static/font/PingFangSC-Regular.woff2
Normal file
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.3 KiB |
BIN
static/icon/face-icon.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
BIN
static/icon/qrcode.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 4.9 KiB |
69
static/js/jsbridge.js
Normal file
@@ -0,0 +1,69 @@
|
||||
(() => {
|
||||
if (!/android/.test(navigator.userAgent.toLowerCase())) {
|
||||
console.error("当前环境不支持WebView桥接通信, 请检查是否为安卓环境");
|
||||
return
|
||||
}
|
||||
let bridge;
|
||||
function setupWebViewJavascriptBridge(callback) {
|
||||
return new Promise((reslove, reject) => {
|
||||
if (window.WebViewJavascriptBridge) {
|
||||
bridge = window.WebViewJavascriptBridge;
|
||||
callback && callback()
|
||||
reslove()
|
||||
} else {
|
||||
document.addEventListener(
|
||||
"WebViewJavascriptBridgeReady",
|
||||
function () {
|
||||
bridge = window.WebViewJavascriptBridge;
|
||||
callback && callback()
|
||||
reslove()
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
})
|
||||
}
|
||||
let funcs = {}
|
||||
setupWebViewJavascriptBridge(() => {
|
||||
bridge.init()
|
||||
bridge.registerHandler("ampeHHCommunication", (data) => {
|
||||
console.log('[zyh][registerHandler]',data);
|
||||
data = JSON.parse(data || '{}');
|
||||
let eventName = data.eventName || '{}';
|
||||
let eventData = JSON.parse(data.eventData || '{}');
|
||||
if (funcs[eventName]) {
|
||||
for (let callback of funcs[eventName]) {
|
||||
callback({type: eventName, data: eventData})
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
window.hh = {
|
||||
async call(funcName, params, callback) {
|
||||
if (!bridge) {
|
||||
await setupWebViewJavascriptBridge()
|
||||
}
|
||||
bridge.callHandler(funcName, params, callback);
|
||||
},
|
||||
async on(funcName, callback) {
|
||||
if (funcs[funcName]) {
|
||||
funcs[funcName].add(callback)
|
||||
} else {
|
||||
funcs[funcName] = new Set([callback])
|
||||
}
|
||||
},
|
||||
off(funcName, callback) {
|
||||
if (!funcs[funcName]) {
|
||||
return false
|
||||
}
|
||||
if (!callback) {
|
||||
return delete funcs[funcName]
|
||||
}
|
||||
let res = funcs[funcName].delete(callback)
|
||||
if(funcs[funcName].size <= 0) {
|
||||
delete funcs[funcName]
|
||||
}
|
||||
return res
|
||||
}
|
||||
};
|
||||
})();
|
||||
1360
static/js/qrcode.js
Normal file
1249
static/upload.html
Normal file
@@ -14,26 +14,48 @@ const useLocationStore = defineStore("location", () => {
|
||||
const longitudeVal = ref(null) // 经度
|
||||
const latitudeVal = ref(null) //纬度
|
||||
|
||||
function getLocation() {
|
||||
function getLocation() { // 获取经纬度两个平台
|
||||
return new Promise((resole, reject) => {
|
||||
try {
|
||||
lightAppJssdk.map.getLocation({
|
||||
success: function(data) {
|
||||
longitudeVal.value = Number(data.longitude)
|
||||
latitudeVal.value = Number(data.latitude)
|
||||
resole(data)
|
||||
},
|
||||
fail: function(data) {
|
||||
longitudeVal.value = 120.382665
|
||||
latitudeVal.value = 36.066938
|
||||
resole({
|
||||
longitude: 120.382665,
|
||||
latitude: 36.066938
|
||||
})
|
||||
msg('用户位置获取失败')
|
||||
console.log('失败', data)
|
||||
}
|
||||
})
|
||||
if (lightAppJssdk.map) {
|
||||
lightAppJssdk.map.getLocation({
|
||||
success: function(data) {
|
||||
longitudeVal.value = Number(data.longitude)
|
||||
latitudeVal.value = Number(data.latitude)
|
||||
resole(data)
|
||||
},
|
||||
fail: function(data) {
|
||||
longitudeVal.value = 120.382665
|
||||
latitudeVal.value = 36.066938
|
||||
resole({
|
||||
longitude: 120.382665,
|
||||
latitude: 36.066938
|
||||
})
|
||||
msg('用户位置获取失败')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
uni.getLocation({
|
||||
type: 'gcj02',
|
||||
highAccuracyExpireTime: 3000,
|
||||
isHighAccuracy: true,
|
||||
timeout: 2000,
|
||||
success: function(data) {
|
||||
longitudeVal.value = Number(data.longitude)
|
||||
latitudeVal.value = Number(data.latitude)
|
||||
resole(data)
|
||||
},
|
||||
fail: function(data) {
|
||||
longitudeVal.value = 120.382665
|
||||
latitudeVal.value = 36.066938
|
||||
resole({
|
||||
longitude: 120.382665,
|
||||
latitude: 36.066938
|
||||
})
|
||||
msg('用户位置获取失败')
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
longitudeVal.value = 120.382665
|
||||
latitudeVal.value = 36.066938
|
||||
@@ -62,6 +84,8 @@ const useLocationStore = defineStore("location", () => {
|
||||
latitudeVal
|
||||
|
||||
}
|
||||
},{
|
||||
unistorage: true,
|
||||
})
|
||||
|
||||
export default useLocationStore;
|
||||
@@ -1,283 +1,329 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
// 屏幕检测管理器类
|
||||
class ScreenDetectionManager {
|
||||
constructor() {
|
||||
this.WIDE_SCREEN_CSS_ID = 'wide-screen-css';
|
||||
this.WIDE_SCREEN_CSS_PATH = '../common/wide-screen.css';
|
||||
this.resizeTimer = null;
|
||||
this.resizeListeners = [];
|
||||
this.cssLink = null;
|
||||
}
|
||||
|
||||
// 获取屏幕宽度
|
||||
getScreenWidth() {
|
||||
if (typeof window === 'undefined') return 0;
|
||||
|
||||
// 优先使用 uni.getSystemInfo
|
||||
if (typeof uni !== 'undefined' && uni.getSystemInfo) {
|
||||
return new Promise((resolve) => {
|
||||
uni.getSystemInfo({
|
||||
success: (res) => {
|
||||
const width = res.screenWidth || res.windowWidth || window.innerWidth;
|
||||
resolve(width);
|
||||
},
|
||||
fail: () => {
|
||||
resolve(this.getWindowWidth());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve(this.getWindowWidth());
|
||||
}
|
||||
|
||||
// 备用方案:使用 window 对象
|
||||
getWindowWidth() {
|
||||
if (typeof window === 'undefined') return 0;
|
||||
return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||
}
|
||||
|
||||
// 检测折叠屏
|
||||
checkVisualViewport() {
|
||||
if (window.visualViewport?.segments?.length > 1) {
|
||||
return {
|
||||
foldable: true,
|
||||
count: window.visualViewport.segments.length - 1
|
||||
}
|
||||
}
|
||||
else {
|
||||
return {
|
||||
foldable: false,
|
||||
count: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 动态加载 CSS
|
||||
loadWideScreenCSS() {
|
||||
if (typeof window === 'undefined' || this.cssLink) return null;
|
||||
|
||||
try {
|
||||
this.cssLink = document.createElement('link');
|
||||
this.cssLink.id = this.WIDE_SCREEN_CSS_ID;
|
||||
this.cssLink.rel = 'stylesheet';
|
||||
this.cssLink.href = this.WIDE_SCREEN_CSS_PATH;
|
||||
|
||||
// 添加加载成功/失败监听
|
||||
this.cssLink.onload = () => {
|
||||
console.log('🎨 宽屏 CSS 文件加载成功');
|
||||
};
|
||||
|
||||
this.cssLink.onerror = () => {
|
||||
console.error('❌ 宽屏 CSS 文件加载失败');
|
||||
this.cssLink = null;
|
||||
};
|
||||
|
||||
document.head.appendChild(this.cssLink);
|
||||
return this.cssLink;
|
||||
} catch (error) {
|
||||
console.error('加载 CSS 失败:', error);
|
||||
this.cssLink = null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 移除 CSS
|
||||
removeWideScreenCSS() {
|
||||
if (this.cssLink && this.cssLink.parentNode) {
|
||||
try {
|
||||
this.cssLink.parentNode.removeChild(this.cssLink);
|
||||
this.cssLink = null;
|
||||
console.log('🗑️ 宽屏 CSS 文件已移除');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('移除 CSS 失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 更新 CSS 状态
|
||||
updateWideScreenCSS(isWideScreen) {
|
||||
if (isWideScreen) {
|
||||
return this.loadWideScreenCSS();
|
||||
} else {
|
||||
return this.removeWideScreenCSS();
|
||||
}
|
||||
}
|
||||
//显示/隐藏默认tabbar
|
||||
updateTabbar(isWideScreen){
|
||||
if(isWideScreen) uni.hideTabBar()
|
||||
else uni.showTabBar()
|
||||
}
|
||||
|
||||
// 添加 resize 监听器
|
||||
addResizeListener(callback, delay = 250) {
|
||||
if (typeof window === 'undefined') return () => {};
|
||||
|
||||
const handler = () => {
|
||||
clearTimeout(this.resizeTimer);
|
||||
this.resizeTimer = setTimeout(() => {
|
||||
callback();
|
||||
}, delay);
|
||||
};
|
||||
|
||||
window.addEventListener('resize', handler);
|
||||
this.resizeListeners.push({ callback, handler });
|
||||
|
||||
// 返回清理函数
|
||||
return () => this.removeResizeListener(callback);
|
||||
}
|
||||
|
||||
// 移除 resize 监听器
|
||||
removeResizeListener(callback) {
|
||||
const index = this.resizeListeners.findIndex(item => item.callback === callback);
|
||||
if (index > -1) {
|
||||
const { handler } = this.resizeListeners[index];
|
||||
window.removeEventListener('resize', handler);
|
||||
this.resizeListeners.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 创建屏幕状态 store
|
||||
const useScreenStore = defineStore('screen', () => {
|
||||
// 状态
|
||||
const screenWidth = ref(0);
|
||||
const isInitialized = ref(false);
|
||||
const isLoading = ref(false);
|
||||
const foldFeature = ref(false);
|
||||
const foldCount = ref(0);
|
||||
|
||||
|
||||
const isWideScreen = computed(() => {
|
||||
return screenWidth.value >= 1080;
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 管理器实例
|
||||
const manager = new ScreenDetectionManager();
|
||||
|
||||
// 初始化屏幕检测
|
||||
const initScreenDetection = async () => {
|
||||
if (isLoading.value || isInitialized.value) return;
|
||||
isLoading.value = true;
|
||||
try {
|
||||
// 检测屏幕状态
|
||||
const width = await manager.getScreenWidth();
|
||||
const { foldable, count } = manager.checkVisualViewport();
|
||||
|
||||
foldFeature.value = foldable;
|
||||
foldCount.value = count;
|
||||
screenWidth.value = width;
|
||||
isInitialized.value = true;
|
||||
|
||||
console.log(`📱 屏幕检测完成: ${width}px, 宽屏: ${isWideScreen.value}`);
|
||||
console.log(`是否为折叠屏: ${foldFeature.value},折叠屏数量:${foldCount.value}`);
|
||||
|
||||
// 根据状态加载或移除 CSS
|
||||
manager.updateWideScreenCSS(isWideScreen.value);
|
||||
manager.updateTabbar(isWideScreen.value);
|
||||
|
||||
// 设置 resize 监听
|
||||
setupResizeListener();
|
||||
return {
|
||||
screenWidth: width,
|
||||
isWideScreen: isWideScreen.value,
|
||||
foldable,
|
||||
count
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('初始化屏幕检测失败:', error);
|
||||
return null;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 手动更新屏幕状态
|
||||
const updateScreenStatus = async () => {
|
||||
try {
|
||||
const width = await manager.getScreenWidth();
|
||||
const { foldable, count } = manager.checkVisualViewport();
|
||||
|
||||
// 保存旧状态
|
||||
const oldWidth = screenWidth.value;
|
||||
const oldIsWideScreen = isWideScreen.value;
|
||||
const oldFoldable = foldFeature.value;
|
||||
const oldFoldCount = foldCount.value;
|
||||
|
||||
// 更新状态
|
||||
screenWidth.value = width;
|
||||
foldFeature.value = foldable;
|
||||
foldCount.value = count;
|
||||
|
||||
// 检查宽屏状态是否发生变化
|
||||
if (oldIsWideScreen !== isWideScreen.value) {
|
||||
console.log(`🔄 屏幕状态变化: ${oldIsWideScreen ? '宽屏' : '非宽屏'} -> ${isWideScreen.value ? '宽屏' : '非宽屏'}`);
|
||||
console.log(`屏幕宽度变化: ${oldWidth}px -> ${width}px`);
|
||||
manager.updateWideScreenCSS(isWideScreen.value);
|
||||
manager.updateTabbar(isWideScreen.value);
|
||||
}
|
||||
|
||||
// 检查折叠屏状态是否发生变化
|
||||
if (oldFoldable !== foldable || oldFoldCount !== count) {
|
||||
console.log(`折叠屏状态变化: ${oldFoldable ? '是' : '否'}->${foldable ? '是' : '否'}, 折叠数: ${oldFoldCount}->${count}`);
|
||||
}
|
||||
|
||||
return {
|
||||
screenWidth: width,
|
||||
isWideScreen: isWideScreen.value,
|
||||
foldable,
|
||||
count
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('更新屏幕状态失败:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// 设置 resize 监听
|
||||
let cleanupResizeListener = () => {};
|
||||
const setupResizeListener = () => {
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
cleanupResizeListener = manager.addResizeListener(async () => {
|
||||
await updateScreenStatus();
|
||||
}, 300);
|
||||
};
|
||||
|
||||
// 手动触发屏幕检测
|
||||
const detectScreen = () => {
|
||||
return updateScreenStatus();
|
||||
};
|
||||
|
||||
|
||||
|
||||
return {
|
||||
// 状态
|
||||
foldFeature,
|
||||
foldCount,
|
||||
screenWidth,
|
||||
isInitialized,
|
||||
isLoading,
|
||||
|
||||
// 响应式计算属性
|
||||
isWideScreen,
|
||||
|
||||
// 方法
|
||||
initScreenDetection,
|
||||
updateScreenStatus,
|
||||
detectScreen,
|
||||
};
|
||||
});
|
||||
|
||||
import {
|
||||
defineStore
|
||||
} from 'pinia';
|
||||
import {
|
||||
ref,
|
||||
computed
|
||||
} from 'vue';
|
||||
import wideScreenStyles from '../common/wide-screen.css?inline';
|
||||
|
||||
// 屏幕检测管理器类
|
||||
class ScreenDetectionManager {
|
||||
constructor() {
|
||||
this.WIDE_SCREEN_CSS_ID = 'wide-screen-css';
|
||||
this.WIDE_SCREEN_CSS_PATH = '../common/wide-screen.css';
|
||||
this.resizeTimer = null;
|
||||
this.resizeListeners = [];
|
||||
this.cssLink = null;
|
||||
this.STYLE_ID = 'wide-screen-style-tag';
|
||||
this.styleTag = null;
|
||||
}
|
||||
|
||||
// 获取屏幕宽度
|
||||
getScreenWidth() {
|
||||
if (typeof window === 'undefined') return 0;
|
||||
|
||||
// 优先使用 uni.getSystemInfo
|
||||
if (typeof uni !== 'undefined' && uni.getSystemInfo) {
|
||||
return new Promise((resolve) => {
|
||||
uni.getSystemInfo({
|
||||
success: (res) => {
|
||||
const width = res.screenWidth || res.windowWidth || window.innerWidth;
|
||||
resolve(width);
|
||||
},
|
||||
fail: () => {
|
||||
resolve(this.getWindowWidth());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve(this.getWindowWidth());
|
||||
}
|
||||
|
||||
// 备用方案:使用 window 对象
|
||||
getWindowWidth() {
|
||||
if (typeof window === 'undefined') return 0;
|
||||
return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||
}
|
||||
|
||||
// 检测折叠屏
|
||||
checkVisualViewport() {
|
||||
if (window.visualViewport?.segments?.length > 1) {
|
||||
return {
|
||||
foldable: true,
|
||||
count: window.visualViewport.segments.length - 1
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
foldable: false,
|
||||
count: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 动态加载 CSS
|
||||
loadWideScreenCSS() {
|
||||
if (typeof window === 'undefined' || this.cssLink) return null;
|
||||
|
||||
try {
|
||||
this.cssLink = document.createElement('link');
|
||||
this.cssLink.id = this.WIDE_SCREEN_CSS_ID;
|
||||
this.cssLink.rel = 'stylesheet';
|
||||
this.cssLink.href = this.WIDE_SCREEN_CSS_PATH;
|
||||
|
||||
// 添加加载成功/失败监听
|
||||
this.cssLink.onload = () => {
|
||||
console.log('🎨 宽屏 CSS 文件加载成功');
|
||||
};
|
||||
|
||||
this.cssLink.onerror = () => {
|
||||
console.error('❌ 宽屏 CSS 文件加载失败');
|
||||
this.cssLink = null;
|
||||
};
|
||||
|
||||
document.head.appendChild(this.cssLink);
|
||||
return this.cssLink;
|
||||
} catch (error) {
|
||||
console.error('加载 CSS 失败:', error);
|
||||
this.cssLink = null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 移除 CSS
|
||||
removeWideScreenCSS() {
|
||||
if (this.cssLink && this.cssLink.parentNode) {
|
||||
try {
|
||||
this.cssLink.parentNode.removeChild(this.cssLink);
|
||||
this.cssLink = null;
|
||||
console.log('🗑️ 宽屏 CSS 文件已移除');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('移除 CSS 失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 更新 CSS 状态
|
||||
// updateWideScreenCSS(isWideScreen) {
|
||||
// if (isWideScreen) {
|
||||
// return this.loadWideScreenCSS();
|
||||
// } else {
|
||||
// return this.removeWideScreenCSS();
|
||||
// }
|
||||
// }
|
||||
|
||||
updateWideScreenCSS(isWideScreen) {
|
||||
if (typeof document === 'undefined') return;
|
||||
|
||||
if (isWideScreen) {
|
||||
// 如果已经是宽屏且标签已存在,则不重复创建
|
||||
if (document.getElementById(this.STYLE_ID)) return;
|
||||
|
||||
this.styleTag = document.createElement('style');
|
||||
this.styleTag.id = this.STYLE_ID;
|
||||
this.styleTag.innerHTML = wideScreenStyles; // 将 CSS 文本注入
|
||||
document.head.appendChild(this.styleTag);
|
||||
console.log('宽屏样式已通过内联方式注入');
|
||||
} else {
|
||||
// 非宽屏时移除标签
|
||||
const existingTag = document.getElementById(this.STYLE_ID);
|
||||
if (existingTag) {
|
||||
existingTag.remove();
|
||||
this.styleTag = null;
|
||||
console.log('宽屏样式已移除');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//显示/隐藏默认tabbar
|
||||
updateTabbar(isWideScreen) {
|
||||
if (isWideScreen) uni.hideTabBar()
|
||||
else uni.showTabBar()
|
||||
}
|
||||
|
||||
// 添加 resize 监听器
|
||||
addResizeListener(callback, delay = 250) {
|
||||
if (typeof window === 'undefined') return () => {};
|
||||
|
||||
const handler = () => {
|
||||
clearTimeout(this.resizeTimer);
|
||||
this.resizeTimer = setTimeout(() => {
|
||||
callback();
|
||||
}, delay);
|
||||
};
|
||||
|
||||
window.addEventListener('resize', handler);
|
||||
this.resizeListeners.push({
|
||||
callback,
|
||||
handler
|
||||
});
|
||||
|
||||
// 返回清理函数
|
||||
return () => this.removeResizeListener(callback);
|
||||
}
|
||||
|
||||
// 移除 resize 监听器
|
||||
removeResizeListener(callback) {
|
||||
const index = this.resizeListeners.findIndex(item => item.callback === callback);
|
||||
if (index > -1) {
|
||||
const {
|
||||
handler
|
||||
} = this.resizeListeners[index];
|
||||
window.removeEventListener('resize', handler);
|
||||
this.resizeListeners.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 创建屏幕状态 store
|
||||
const useScreenStore = defineStore('screen', () => {
|
||||
// 状态
|
||||
const screenWidth = ref(0);
|
||||
const isInitialized = ref(false);
|
||||
const isLoading = ref(false);
|
||||
const foldFeature = ref(false);
|
||||
const foldCount = ref(0);
|
||||
|
||||
|
||||
const isWideScreen = computed(() => {
|
||||
return screenWidth.value >= 900;
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 管理器实例
|
||||
const manager = new ScreenDetectionManager();
|
||||
|
||||
// 初始化屏幕检测
|
||||
const initScreenDetection = async () => {
|
||||
if (isLoading.value || isInitialized.value) return;
|
||||
isLoading.value = true;
|
||||
try {
|
||||
// 检测屏幕状态
|
||||
const width = await manager.getScreenWidth();
|
||||
const {
|
||||
foldable,
|
||||
count
|
||||
} = manager.checkVisualViewport();
|
||||
|
||||
foldFeature.value = foldable;
|
||||
foldCount.value = count;
|
||||
screenWidth.value = width;
|
||||
isInitialized.value = true;
|
||||
|
||||
console.log(`📱 屏幕检测完成: ${width}px, 宽屏: ${isWideScreen.value}`);
|
||||
console.log(`是否为折叠屏: ${foldFeature.value},折叠屏数量:${foldCount.value}`);
|
||||
|
||||
// 根据状态加载或移除 CSS
|
||||
manager.updateWideScreenCSS(isWideScreen.value);
|
||||
manager.updateTabbar(isWideScreen.value);
|
||||
|
||||
// 设置 resize 监听
|
||||
setupResizeListener();
|
||||
return {
|
||||
screenWidth: width,
|
||||
isWideScreen: isWideScreen.value,
|
||||
foldable,
|
||||
count
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('初始化屏幕检测失败:', error);
|
||||
return null;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 手动更新屏幕状态
|
||||
const updateScreenStatus = async () => {
|
||||
try {
|
||||
const width = await manager.getScreenWidth();
|
||||
const {
|
||||
foldable,
|
||||
count
|
||||
} = manager.checkVisualViewport();
|
||||
|
||||
// 保存旧状态
|
||||
const oldWidth = screenWidth.value;
|
||||
const oldIsWideScreen = isWideScreen.value;
|
||||
const oldFoldable = foldFeature.value;
|
||||
const oldFoldCount = foldCount.value;
|
||||
|
||||
// 更新状态
|
||||
screenWidth.value = width;
|
||||
foldFeature.value = foldable;
|
||||
foldCount.value = count;
|
||||
|
||||
// 检查宽屏状态是否发生变化
|
||||
if (oldIsWideScreen !== isWideScreen.value) {
|
||||
console.log(
|
||||
`🔄 屏幕状态变化: ${oldIsWideScreen ? '宽屏' : '非宽屏'} -> ${isWideScreen.value ? '宽屏' : '非宽屏'}`
|
||||
);
|
||||
console.log(`屏幕宽度变化: ${oldWidth}px -> ${width}px`);
|
||||
manager.updateWideScreenCSS(isWideScreen.value);
|
||||
manager.updateTabbar(isWideScreen.value);
|
||||
}
|
||||
|
||||
// 检查折叠屏状态是否发生变化
|
||||
if (oldFoldable !== foldable || oldFoldCount !== count) {
|
||||
console.log(
|
||||
`折叠屏状态变化: ${oldFoldable ? '是' : '否'}->${foldable ? '是' : '否'}, 折叠数: ${oldFoldCount}->${count}`
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
screenWidth: width,
|
||||
isWideScreen: isWideScreen.value,
|
||||
foldable,
|
||||
count
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('更新屏幕状态失败:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// 设置 resize 监听
|
||||
let cleanupResizeListener = () => {};
|
||||
const setupResizeListener = () => {
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
cleanupResizeListener = manager.addResizeListener(async () => {
|
||||
await updateScreenStatus();
|
||||
}, 300);
|
||||
};
|
||||
|
||||
// 手动触发屏幕检测
|
||||
const detectScreen = () => {
|
||||
return updateScreenStatus();
|
||||
};
|
||||
|
||||
|
||||
|
||||
return {
|
||||
// 状态
|
||||
foldFeature,
|
||||
foldCount,
|
||||
screenWidth,
|
||||
isInitialized,
|
||||
isLoading,
|
||||
|
||||
// 响应式计算属性
|
||||
isWideScreen,
|
||||
|
||||
// 方法
|
||||
initScreenDetection,
|
||||
updateScreenStatus,
|
||||
detectScreen,
|
||||
};
|
||||
});
|
||||
|
||||
export default useScreenStore;
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
msg,
|
||||
$api,
|
||||
} from '../common/globalFunction';
|
||||
import baseDB from '@/utils/db.js';
|
||||
|
||||
// 简历完成度计算
|
||||
function getResumeCompletionPercentage(resume) {
|
||||
@@ -59,6 +60,7 @@ const useUserStore = defineStore("user", () => {
|
||||
const seesionId = ref('')
|
||||
const counts = ref({})
|
||||
const isMiniProgram = ref(false)
|
||||
const isMachineEnv = ref(false)
|
||||
|
||||
const login = (value) => {
|
||||
hasLogin.value = true;
|
||||
@@ -84,6 +86,20 @@ const useUserStore = defineStore("user", () => {
|
||||
});
|
||||
}
|
||||
|
||||
const logOutApp = () => {
|
||||
hasLogin.value = false;
|
||||
token.value = ''
|
||||
resume.value = {}
|
||||
userInfo.value = {}
|
||||
role.value = {}
|
||||
uni.clearStorageSync('userInfo')
|
||||
uni.clearStorageSync('token')
|
||||
uni.switchTab({
|
||||
url: '/pages/index/index',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const getUserInfo = () => {
|
||||
return new Promise((reslove, reject) => {
|
||||
createRequest('/getInfo', {}, 'get').then((userInfo) => {
|
||||
@@ -110,7 +126,9 @@ const useUserStore = defineStore("user", () => {
|
||||
// 获取消息列表
|
||||
useReadMsg().fetchMessages()
|
||||
// 获取用户信息
|
||||
return getUserResume()
|
||||
const resume = await getUserResume()
|
||||
await baseDB.init(); // 登录成功初始化
|
||||
return resume
|
||||
}
|
||||
|
||||
const setUserInfo = (values) => {
|
||||
@@ -145,6 +163,9 @@ const useUserStore = defineStore("user", () => {
|
||||
isMiniProgram.value = val
|
||||
}
|
||||
|
||||
function changMachineEnv(val) {
|
||||
isMachineEnv.value = val
|
||||
}
|
||||
|
||||
// 导入
|
||||
return {
|
||||
@@ -154,6 +175,7 @@ const useUserStore = defineStore("user", () => {
|
||||
resume,
|
||||
login,
|
||||
logOut,
|
||||
logOutApp,
|
||||
loginSetToken,
|
||||
getUserResume,
|
||||
initSeesionId,
|
||||
@@ -162,7 +184,9 @@ const useUserStore = defineStore("user", () => {
|
||||
getUserstatistics,
|
||||
counts,
|
||||
isMiniProgram,
|
||||
changMiniProgramAppStatus
|
||||
changMiniProgramAppStatus,
|
||||
changMachineEnv,
|
||||
isMachineEnv
|
||||
}
|
||||
}, {
|
||||
unistorage: true,
|
||||
|
||||
@@ -34,11 +34,12 @@ const useChatGroupDBStore = defineStore("messageGroup", () => {
|
||||
const chatSessionID = ref('')
|
||||
const lastDateRef = ref('')
|
||||
|
||||
async function init() {
|
||||
async function init() { // 初始化数据,有则用,无则更新
|
||||
// 获取所有数据
|
||||
setTimeout(async () => {
|
||||
if (!baseDB.isDBReady) await baseDB.initDB();
|
||||
const result = await baseDB.db.getAll(tableName.value);
|
||||
console.log('result', result)
|
||||
// 1、判断是否有数据,没数据请求服务器
|
||||
if (result.length) {
|
||||
console.warn('本地数据库存在数据')
|
||||
|
||||
76
utils/GlobalInactivityManager.js
Normal file
@@ -0,0 +1,76 @@
|
||||
// utils/GlobalInactivityManager.js
|
||||
|
||||
export class GlobalInactivityManager {
|
||||
constructor(callback, timeout = 60000) {
|
||||
this.callback = callback
|
||||
this.timeout = timeout
|
||||
this.timer = null
|
||||
this.isPaused = false
|
||||
this.lastActivityTime = 0
|
||||
this.THROTTLE_DELAY = 300
|
||||
|
||||
this.lowFreqEvents = ['mousedown', 'click', 'keydown', 'touchstart']
|
||||
this.highFreqEvents = ['mousemove', 'scroll', 'wheel', 'pointermove']
|
||||
}
|
||||
|
||||
resetTimer = () => {
|
||||
if (this.isPaused) return
|
||||
if (this.timer) clearTimeout(this.timer)
|
||||
this.timer = setTimeout(() => {
|
||||
this.callback()
|
||||
this.pause()
|
||||
}, this.timeout)
|
||||
}
|
||||
|
||||
handleUserActivity = () => {
|
||||
const now = Date.now()
|
||||
if (now - this.lastActivityTime > this.THROTTLE_DELAY) {
|
||||
this.lastActivityTime = now
|
||||
this.resetTimer()
|
||||
}
|
||||
}
|
||||
|
||||
handleVisibilityChange = () => {
|
||||
if (document.hidden) {
|
||||
this.pause()
|
||||
} else {
|
||||
this.resume()
|
||||
}
|
||||
}
|
||||
|
||||
start() {
|
||||
if (this.isPaused) return
|
||||
this.resetTimer()
|
||||
|
||||
this.lowFreqEvents.forEach(event => {
|
||||
document.addEventListener(event, this.resetTimer, true)
|
||||
})
|
||||
this.highFreqEvents.forEach(event => {
|
||||
document.addEventListener(event, this.handleUserActivity, true)
|
||||
})
|
||||
document.addEventListener('visibilitychange', this.handleVisibilityChange)
|
||||
}
|
||||
|
||||
pause() {
|
||||
this.isPaused = true
|
||||
if (this.timer) clearTimeout(this.timer)
|
||||
|
||||
this.lowFreqEvents.forEach(event => {
|
||||
document.removeEventListener(event, this.resetTimer, true)
|
||||
})
|
||||
this.highFreqEvents.forEach(event => {
|
||||
document.removeEventListener(event, this.handleUserActivity, true)
|
||||
})
|
||||
document.removeEventListener('visibilitychange', this.handleVisibilityChange)
|
||||
}
|
||||
|
||||
resume() {
|
||||
this.isPaused = false
|
||||
this.start() // 现在 this 指向正确,事件能正常绑定和触发
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.pause()
|
||||
this.callback = null
|
||||
}
|
||||
}
|
||||
105
utils/db.js
@@ -1,24 +1,50 @@
|
||||
// BaseDBStore.js
|
||||
import IndexedDBHelper from '@/common/IndexedDBHelper.js'
|
||||
// import UniStorageHelper from '../common/UniStorageHelper'
|
||||
import useChatGroupDBStore from '@/stores/userChatGroupStore'
|
||||
import config from '@/config'
|
||||
|
||||
class BaseStore {
|
||||
db = null
|
||||
isDBReady = false
|
||||
dbName = 'BrowsingHistory' // 'AppMainDB'
|
||||
dbName = 'AppMainDB'
|
||||
initPromise = null
|
||||
|
||||
constructor() {
|
||||
this.initPromise = this.checkAndInitDB()
|
||||
// 不再自动执行初始化
|
||||
}
|
||||
|
||||
async getDB() {
|
||||
if (!this.initPromise) {
|
||||
this.initPromise = this.checkAndInitDB();
|
||||
/**
|
||||
* 手动初始化入口、建立连接、如果版本号不对付才会清理
|
||||
* 建议在登录成功后调用:await baseDB.init()
|
||||
*/
|
||||
async init() {
|
||||
// 如果已经有初始化任务在进行了,直接返回该任务
|
||||
if (this.initPromise) {
|
||||
return this.initPromise;
|
||||
}
|
||||
|
||||
// 创建初始化任务
|
||||
this.initPromise = this.checkAndInitDB();
|
||||
|
||||
try {
|
||||
await this.initPromise;
|
||||
console.log('数据库初始化成功');
|
||||
} catch (error) {
|
||||
this.initPromise = null; // 初始化失败允许下次重试
|
||||
console.error('数据库初始化失败:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
return this.db;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库实例
|
||||
* 如果没初始化,会强制触发一次 init
|
||||
*/
|
||||
async getDB() {
|
||||
if (!this.isDBReady) {
|
||||
return await this.init();
|
||||
}
|
||||
await this.initPromise; // 等待初始化完成
|
||||
return this.db;
|
||||
}
|
||||
|
||||
@@ -28,30 +54,28 @@ class BaseStore {
|
||||
}
|
||||
const localVersion = uni.getStorageSync('indexedDBVersion') || 1
|
||||
console.log('DBVersion: ', localVersion, config.DBversion)
|
||||
if (localVersion === config.DBversion) {
|
||||
return this.initDB() // 🟢 记得加 return
|
||||
|
||||
if (Number(localVersion) === Number(config.DBversion)) {
|
||||
return this.initDB()
|
||||
} else {
|
||||
console.log('清空本地数据库')
|
||||
await this.clearDB() // 🟢 建议用 await
|
||||
console.log('检测到版本更新,清空重置旧数据库')
|
||||
await this.clearDB()
|
||||
uni.setStorageSync('indexedDBVersion', config.DBversion);
|
||||
return this.initDB(); // 🟢 记得加 return
|
||||
return this.initDB();
|
||||
}
|
||||
}
|
||||
|
||||
initDB() {
|
||||
// // #ifdef H5
|
||||
this.db = new IndexedDBHelper(this.dbName, config.DBversion);
|
||||
// // #endif
|
||||
|
||||
return this.db.openDB([{
|
||||
name: 'record',
|
||||
keyPath: "id",
|
||||
autoIncrement: true,
|
||||
autoIncrement: true
|
||||
},
|
||||
{
|
||||
name: 'messageGroup',
|
||||
keyPath: "id",
|
||||
autoIncrement: true,
|
||||
autoIncrement: true
|
||||
},
|
||||
{
|
||||
name: 'messages',
|
||||
@@ -65,12 +89,12 @@ class BaseStore {
|
||||
},
|
||||
{
|
||||
name: 'api_cache',
|
||||
keyPath: "cacheKey", // 使用 URL+参数 作为主键
|
||||
keyPath: "cacheKey",
|
||||
indexes: []
|
||||
}
|
||||
]).then(async () => {
|
||||
// 这里原来的逻辑保留
|
||||
if (useChatGroupDBStore) {
|
||||
// 确保 Pinia Store 已准备好后再初始化子项
|
||||
useChatGroupDBStore().init()
|
||||
}
|
||||
this.isDBReady = true
|
||||
@@ -79,13 +103,44 @@ class BaseStore {
|
||||
}
|
||||
|
||||
async clearDB() {
|
||||
return new Promise((resolve, rejetc) => {
|
||||
new IndexedDBHelper().deleteDB(this.dbName).then(() => {
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
// 修正拼写错误并优化 Promise 写法
|
||||
return new IndexedDBHelper().deleteDB(this.dbName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 彻底清空数据库并重新初始化
|
||||
* 适用于切换账号或手动清理缓存
|
||||
* 非特殊情况不要重置!!!!!!!!!!!!!!!
|
||||
*/
|
||||
async resetAndReinit() {
|
||||
console.warn('开始执行数据库重置...');
|
||||
|
||||
if (this.db && this.db.db) {
|
||||
this.db.db.close();
|
||||
}
|
||||
|
||||
try {
|
||||
await this.clearDB();
|
||||
|
||||
// 3. 重置内部状态
|
||||
this.db = null;
|
||||
this.isDBReady = false;
|
||||
this.initPromise = null;
|
||||
|
||||
uni.setStorageSync('indexedDBVersion', config.DBversion);
|
||||
|
||||
// 5. 重新调用初始化流程
|
||||
await this.init();
|
||||
|
||||
console.log('数据库重置及初始化完成');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('数据库重置失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 导出实例
|
||||
const baseDB = new BaseStore()
|
||||
export default baseDB
|
||||
46
utils/modal.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 全局弹窗调用工具
|
||||
* @param {Object} options - 配置项 (title, content, type, success, fail, confirmColor...)
|
||||
*/
|
||||
export const $confirm = (options = {}) => {
|
||||
return new Promise((resolve) => {
|
||||
// 1. 稍微延迟发送,确保注入的页面组件已完成 uni.$on 监听挂载
|
||||
// 如果是用户点击触发,延迟可以设为 0;如果是拦截器自动触发,建议保留 200ms
|
||||
setTimeout(() => {
|
||||
uni.$emit('show-global-popup', {
|
||||
title: options.title || '提示',
|
||||
content: options.content || '',
|
||||
type: options.type || 'info',
|
||||
// 核心:重新包装 resolve 逻辑
|
||||
resolve: (isConfirm) => {
|
||||
if (isConfirm) {
|
||||
// 执行成功回调
|
||||
if (typeof options.success === 'function') {
|
||||
options.success({
|
||||
confirm: true,
|
||||
cancel: false
|
||||
});
|
||||
}
|
||||
resolve(true);
|
||||
} else {
|
||||
// 执行失败/取消回调
|
||||
if (typeof options.fail === 'function') {
|
||||
options.fail({
|
||||
confirm: false,
|
||||
cancel: true
|
||||
});
|
||||
}
|
||||
resolve(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
}, options.delay || 200);
|
||||
});
|
||||
};
|
||||
// // 页面中使用
|
||||
// import {
|
||||
// $confirm
|
||||
// } from '@/utils/modal.js';
|
||||
// const ok = await $confirm({
|
||||
// title: '测试'
|
||||
// });
|
||||
66
vite-inject-popup.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
// 读取并解析 pages.json
|
||||
function getPagesConfig() {
|
||||
const pagesJsonPath = path.resolve(__dirname, 'pages.json');
|
||||
let rawContent = fs.readFileSync(pagesJsonPath, 'utf8');
|
||||
|
||||
// 核心修复:使用正则去除 JSON 中的 // 和 /* */ 注释
|
||||
const jsonContent = rawContent.replace(/\/\/.*|\/\*[\s\S]*?\*\//g, "");
|
||||
|
||||
const pagesJson = JSON.parse(jsonContent);
|
||||
const pagePaths = [];
|
||||
|
||||
// 1. 提取主包页面
|
||||
if (pagesJson.pages) {
|
||||
pagesJson.pages.forEach(p => pagePaths.push(p.path));
|
||||
}
|
||||
|
||||
// 2. 提取分包页面
|
||||
if (pagesJson.subPackages) {
|
||||
pagesJson.subPackages.forEach(sub => {
|
||||
if (sub.pages) {
|
||||
sub.pages.forEach(p => {
|
||||
pagePaths.push(`${sub.root}/${p.path}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return pagePaths;
|
||||
}
|
||||
|
||||
const allPages = getPagesConfig();
|
||||
|
||||
export default function viteInjectPopup() {
|
||||
return {
|
||||
name: 'vite-inject-popup',
|
||||
enforce: 'pre',
|
||||
transform(code, id) {
|
||||
// 将绝对路径转为相对项目的路径,便于匹配
|
||||
// 例如: /Users/.../pages/index/index.vue -> pages/index/index
|
||||
const relativePath = id.replace(/\\/g, '/').split('.vue')[0];
|
||||
|
||||
// 校验当前文件是否在 pages.json 的定义中
|
||||
const isTargetPage = allPages.some(pagePath => relativePath.endsWith(pagePath));
|
||||
|
||||
if (isTargetPage && !code.includes('global-popup')) {
|
||||
const lastTemplateEndIndex = code.lastIndexOf('</template>');
|
||||
if (lastTemplateEndIndex !== -1) {
|
||||
const newCode =
|
||||
code.slice(0, lastTemplateEndIndex) +
|
||||
'\n <global-popup />\n' +
|
||||
code.slice(lastTemplateEndIndex);
|
||||
|
||||
console.log(`[精准注入]: ${relativePath}`);
|
||||
return {
|
||||
code: newCode,
|
||||
map: null
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
13
vite.config.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import {
|
||||
defineConfig
|
||||
} from 'vite';
|
||||
import uni from '@dcloudio/vite-plugin-uni';
|
||||
import viteInjectPopup from './vite-inject-popup.js'; // 你的自定义插件
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
// 只保留这一个自定义插件,它只负责改 template 字符串
|
||||
viteInjectPopup(),
|
||||
uni(),
|
||||
],
|
||||
});
|
||||