flat: 一体机兼容,添加全局事件扫码回调等

This commit is contained in:
Apcallover
2025-12-17 15:16:48 +08:00
parent 8ccdcbf93b
commit 3d826aec86
6 changed files with 184 additions and 4 deletions

38
App.vue
View File

@@ -1,14 +1,17 @@
<script setup> <script setup>
import { reactive, inject, onMounted } from 'vue'; import { reactive, inject, onMounted } from 'vue';
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'; import { onLaunch, onShow, onHide } from '@dcloudio/uni-app';
import { IncreaseRevie } from '@/common/all-in-one-listen.js';
import useUserStore from './stores/useUserStore'; import useUserStore from './stores/useUserStore';
import usePageAnimation from './hook/usePageAnimation'; import usePageAnimation from './hook/usePageAnimation';
import useDictStore from './stores/useDictStore'; import useDictStore from './stores/useDictStore';
import { useGlobalInactivity } from '@/hook/useGlobalInactivity';
const { $api, navTo, appendScriptTagElement, aes_Decrypt, sm2_Decrypt, safeReLaunch } = inject('globalFunction'); const { $api, navTo, appendScriptTagElement, aes_Decrypt, sm2_Decrypt, safeReLaunch } = inject('globalFunction');
import config from '@/config.js'; import config from '@/config.js';
import baseDB from '@/utils/db.js'; import baseDB from '@/utils/db.js';
usePageAnimation(); usePageAnimation();
const appword = 'aKd20dbGdFvmuwrt'; // 固定值 const appword = 'aKd20dbGdFvmuwrt'; // 固定值
let uQRListen = null;
onLaunch((options) => { onLaunch((options) => {
useDictStore().getDictData(); useDictStore().getDictData();
@@ -25,6 +28,7 @@ onLaunch((options) => {
useUserStore().logOutApp(); useUserStore().logOutApp();
useUserStore().changMiniProgramAppStatus(true); useUserStore().changMiniProgramAppStatus(true);
useUserStore().changMachineEnv(true); useUserStore().changMachineEnv(true);
uQRListen = new IncreaseRevie();
return; return;
} }
// 正式上线去除此方法 // 正式上线去除此方法
@@ -54,12 +58,40 @@ onHide(() => {
console.log('App Hide'); console.log('App Hide');
}); });
const { resume, pause } = useGlobalInactivity(() => {
console.warn('【全局】60秒无操作执行安全登出...');
uni.showModal({
title: '会话即将过期',
content: '长时间无操作,是否继续使用?',
showCancel: true,
cancelText: '退出',
confirmText: '继续',
success: (res) => {
if (res.confirm) {
resume();
} else {
handleLogout();
}
},
});
}, 60 * 1000);
function handleLogout() {
// 清除 token、跳转登录页
uni.clearStorageSync();
baseDB.resetAndReinit();
useUserStore().logOutApp();
pause();
}
// 一体机环境判断
function isY9MachineType() { function isY9MachineType() {
const ua = navigator.userAgent; const ua = navigator.userAgent;
const isY9Machine = /Y9-ZYYH/i.test(ua); // 匹配机器型号 const isY9Machine = /Y9-ZYYH/i.test(ua); // 匹配机器型号
return isY9Machine; return isY9Machine;
} }
// 爱山东环境登录
function getUserInfo() { function getUserInfo() {
lightAppJssdk.user.getUserInfoWithEncryptedParamByAppId({ lightAppJssdk.user.getUserInfoWithEncryptedParamByAppId({
appId: config.appInfo.loveShandong, // 接入方在成功创建应用后自动生成 appId: config.appInfo.loveShandong, // 接入方在成功创建应用后自动生成
@@ -180,19 +212,19 @@ uni-modal,
@font-face { @font-face {
font-family: PingFangSC-Regular; 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-display: swap;
} }
@font-face { @font-face {
font-family: PingFangSC-Medium; 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-display: swap;
} }
@font-face { @font-face {
font-family: DIN-Medium; font-family: DIN-Medium;
src: url('./static/font/DIN-Medium.woff2') format('woff2'); src: url('/static/font/DIN-Medium.woff2') format('woff2');
font-display: swap; font-display: swap;
} }

View 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('识别失败')
}
}
}

View File

@@ -0,0 +1,80 @@
// hook/useGlobalInactivity.js
import {
onMounted,
onUnmounted
} from 'vue'
export function useGlobalInactivity(callback, timeout = 60000) {
let timer = null
let isPaused = false
// ===== 高频事件节流 =====
let lastActivityTime = 0
const THROTTLE_DELAY = 300 // 300ms 内最多响应一次活动
const handleUserActivity = () => {
const now = Date.now()
if (now - lastActivityTime > THROTTLE_DELAY) {
lastActivityTime = now
resetTimer()
}
}
// 低频事件(可直接绑定)
const lowFreqEvents = ['mousedown', 'click', 'keydown', 'touchstart']
// 高频事件(需节流)
const highFreqEvents = ['mousemove', 'scroll', 'wheel', 'pointermove']
const resetTimer = () => {
if (isPaused) return
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
callback()
pause() // 默认触发后停止
}, timeout)
}
const pause = () => {
isPaused = true
if (timer) {
clearTimeout(timer)
timer = null
}
lowFreqEvents.forEach(e => document.removeEventListener(e, resetTimer, true))
highFreqEvents.forEach(e => document.removeEventListener(e, handleUserActivity, true))
document.removeEventListener('visibilitychange', handleVisibilityChange)
}
const resume = () => {
if (!isPaused) return
isPaused = false
resetTimer()
lowFreqEvents.forEach(e => document.addEventListener(e, resetTimer, true))
highFreqEvents.forEach(e => document.addEventListener(e, handleUserActivity, true))
document.addEventListener('visibilitychange', handleVisibilityChange)
}
const handleVisibilityChange = () => {
if (document.hidden) {
pause()
} else {
resume()
}
}
const start = () => {
if (isPaused) return
resetTimer()
lowFreqEvents.forEach(e => document.addEventListener(e, resetTimer, true))
highFreqEvents.forEach(e => document.addEventListener(e, handleUserActivity, true))
document.addEventListener('visibilitychange', handleVisibilityChange)
}
onMounted(start)
onUnmounted(pause)
return {
resume,
pause
}
}

View File

@@ -368,6 +368,9 @@ function loginbackdoor() {
if (isMachineEnv.value) { if (isMachineEnv.value) {
useUserStore().logOutApp(); useUserStore().logOutApp();
$api.msg('返回首页'); $api.msg('返回首页');
// setTimeout(() => {
// window.location.reload();
// }, 2000);
return; return;
} }
$api.createRequest('/app/mock/login', {}, 'post').then((resData) => { $api.createRequest('/app/mock/login', {}, 'post').then((resData) => {

Binary file not shown.

Binary file not shown.