feat : 一体机定位直到成功,其他环境循环2分钟定位, 上传加入文件校验

This commit is contained in:
2025-12-19 14:46:37 +08:00
parent fdd5577c85
commit 7e8bef0cb9
8 changed files with 343 additions and 263 deletions

12
App.vue
View File

@@ -24,6 +24,7 @@ onLaunch((options) => {
getUserInfo(); getUserInfo();
useUserStore().changMiniProgramAppStatus(false); useUserStore().changMiniProgramAppStatus(false);
useUserStore().changMachineEnv(false); useUserStore().changMachineEnv(false);
useLocationStore().getLocationLoop()//循环获取定位
return; return;
} }
if (isY9MachineType()) { if (isY9MachineType()) {
@@ -32,7 +33,14 @@ onLaunch((options) => {
useUserStore().logOutApp(); useUserStore().logOutApp();
useUserStore().changMiniProgramAppStatus(true); useUserStore().changMiniProgramAppStatus(true);
useUserStore().changMachineEnv(true); useUserStore().changMachineEnv(true);
useLocationStore().getLocation(); useLocationStore().getLocation()
.then(({longitude,latitude})=>{
console.log(`✅一体机获取定位成功:lng:${longitude},lat${latitude}`)
})
.catch(err=>{
console.log('❌一体机获取定位失败,30s后尝试重新获取')
useLocationStore().getLocation()
})
uQRListen = new IncreaseRevie(); uQRListen = new IncreaseRevie();
inactivityManager = new GlobalInactivityManager(handleInactivity, 60 * 1000); inactivityManager = new GlobalInactivityManager(handleInactivity, 60 * 1000);
inactivityManager.start(); inactivityManager.start();
@@ -40,6 +48,7 @@ onLaunch((options) => {
} }
// 正式上线去除此方法 // 正式上线去除此方法
console.warn('浏览器环境'); console.warn('浏览器环境');
useLocationStore().getLocationLoop()//循环获取定位
useUserStore().changMiniProgramAppStatus(true); useUserStore().changMiniProgramAppStatus(true);
useUserStore().changMachineEnv(false); useUserStore().changMachineEnv(false);
useUserStore().initSeesionId(); //更新 useUserStore().initSeesionId(); //更新
@@ -57,6 +66,7 @@ onLaunch((options) => {
onMounted(() => {}); onMounted(() => {});
onShow(() => { onShow(() => {
console.log('App Show'); console.log('App Show');
}); });

View File

@@ -82,6 +82,7 @@ const { userInfo } = storeToRefs(useUserStore());
const { getUserResume } = useUserStore(); const { getUserResume } = useUserStore();
const { dictLabel, oneDictData } = useDictStore(); const { dictLabel, oneDictData } = useDictStore();
const openSelectPopup = inject('openSelectPopup'); const openSelectPopup = inject('openSelectPopup');
import {FileValidator} from "@/utils/fileValidator" //文件校验
const percent = ref('0%'); const percent = ref('0%');
const state = reactive({ const state = reactive({
@@ -278,7 +279,15 @@ function selectAvatar() {
sizeType: ['original', 'compressed'], sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'], sourceType: ['album', 'camera'],
count: 1, count: 1,
success: ({ tempFilePaths, tempFiles }) => { success: async(res) => {
const tempFilePaths = res.tempFilePaths;
const file = res.tempFiles[0];
const imageValidator = new FileValidator()
try {
await imageValidator.validate(file)
$api.uploadFile(tempFilePaths[0], true) $api.uploadFile(tempFilePaths[0], true)
.then((res) => { .then((res) => {
res = JSON.parse(res); res = JSON.parse(res);
@@ -287,6 +296,9 @@ function selectAvatar() {
.catch((err) => { .catch((err) => {
$api.msg('上传失败'); $api.msg('上传失败');
}); });
} catch (error) {
$api.msg(error);
}
}, },
fail: (error) => {}, fail: (error) => {},
}); });

View File

@@ -281,6 +281,8 @@ const { messages, isTyping, textInput, chatSessionID } = storeToRefs(useChatGrou
import successIcon from '@/static/icon/success.png'; import successIcon from '@/static/icon/success.png';
import useUserStore from '@/stores/useUserStore'; import useUserStore from '@/stores/useUserStore';
const { isMachineEnv } = storeToRefs(useUserStore()); const { isMachineEnv } = storeToRefs(useUserStore());
import {FileValidator} from "@/utils/fileValidator" //文件校验
// hook // hook
// 语音识别 // 语音识别
const { const {
@@ -536,10 +538,14 @@ function uploadCamera(type = 'camera') {
count: 1, //默认9 count: 1, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有 sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: [type], //从相册选择 sourceType: [type], //从相册选择
success: function (res) { success: async (res)=> {
const tempFilePaths = res.tempFilePaths; const tempFilePaths = res.tempFilePaths;
const file = res.tempFiles[0]; const file = res.tempFiles[0];
// 继续上传
const imageValidator = new FileValidator()
try {
await imageValidator.validate(file)
$api.uploadFile(tempFilePaths[0], true).then((resData) => { $api.uploadFile(tempFilePaths[0], true).then((resData) => {
resData = JSON.parse(resData); resData = JSON.parse(resData);
console.log(file.type,'++') console.log(file.type,'++')
@@ -552,6 +558,9 @@ function uploadCamera(type = 'camera') {
textInput.value = state.uploadFileTips; textInput.value = state.uploadFileTips;
} }
}); });
} catch (error) {
$api.msg(error)
}
}, },
}); });
} }
@@ -560,15 +569,17 @@ function getUploadFile(type = 'camera') {
if (VerifyNumberFiles()) return; if (VerifyNumberFiles()) return;
uni.chooseFile({ uni.chooseFile({
count: 1, count: 1,
success: (res) => { success: async(res) => {
const tempFilePaths = res.tempFilePaths; const tempFilePaths = res.tempFilePaths;
const file = res.tempFiles[0]; const file = res.tempFiles[0];
const allowedTypes = config.allowedFileTypes || []; const allowedTypes = config.allowedFileTypes || [];
const size = $api.formatFileSize(file.size); const size = $api.formatFileSize(file.size);
if (!allowedTypes.includes(file.type)) {
return $api.msg('仅支持 txt md word pdf ppt csv excel 格式类型'); const imageValidator = new FileValidator({allowedExtensions:config.allowedFileTypes})
}
// 继续上传 try{
await imageValidator.validate(file)
$api.uploadFile(tempFilePaths[0], true).then((resData) => { $api.uploadFile(tempFilePaths[0], true).then((resData) => {
resData = JSON.parse(resData); resData = JSON.parse(resData);
filesList.value.push({ filesList.value.push({
@@ -579,6 +590,9 @@ function getUploadFile(type = 'camera') {
}); });
textInput.value = state.uploadFileTips; textInput.value = state.uploadFileTips;
}); });
}catch(error){
$api.msg(error)
}
}, },
}); });
} }

View File

@@ -470,7 +470,6 @@ const { columnCount, columnSpace } = useColumnCount(() => {
getJobRecommend('refresh'); getJobRecommend('refresh');
nextTick(() => { nextTick(() => {
waterfallsFlowRef.value?.refresh?.(); waterfallsFlowRef.value?.refresh?.();
useLocationStore().getLocation();
}); });
}); });

View File

@@ -129,7 +129,6 @@ const { columnCount, columnSpace } = useColumnCount(() => {
pageSize.value = 10 * (columnCount.value - 1); pageSize.value = 10 * (columnCount.value - 1);
nextTick(() => { nextTick(() => {
waterfallsFlowRef.value?.refresh?.(); waterfallsFlowRef.value?.refresh?.();
useLocationStore().getLocation();
}); });
}); });

View File

@@ -151,7 +151,6 @@ const { columnCount, columnSpace } = useColumnCount(() => {
pageSize.value = 10 * (columnCount.value - 1); pageSize.value = 10 * (columnCount.value - 1);
nextTick(() => { nextTick(() => {
waterfallsFlowRef.value?.refresh?.(); waterfallsFlowRef.value?.refresh?.();
useLocationStore().getLocation();
}); });
}); });

View File

@@ -11,13 +11,15 @@ import config from '../config';
const defalutLongLat = { const defalutLongLat = {
longitude: 120.382665, longitude: 120.382665,
latitude: 36.066938 latitude: 36.066938,
} }
const useLocationStore = defineStore("location", () => { const useLocationStore = defineStore("location", () => {
// 定义状态 // 定义状态
const longitudeVal = ref(null) // 经度 const longitudeVal = ref(null) // 经度
const latitudeVal = ref(null) //纬度 const latitudeVal = ref(null) //纬度
const timer = ref(null)
const count = ref(0)
function getLocation() { // 获取经纬度两个平台 function getLocation() { // 获取经纬度两个平台
return new Promise((resole, reject) => { return new Promise((resole, reject) => {
@@ -66,6 +68,21 @@ const useLocationStore = defineStore("location", () => {
} }
}) })
} }
function getLocationLoop(gap = 1000 * 60 * 2) {
console.log(`🔄开始循环获取定位,间隔:${Math.floor(gap/1000)}`)
const run = () => {
count.value++
console.log(`📍第${count.value}次获取定位`)
getLocation()
}
run()
timer.value = setInterval(run,gap);
}
function clearGetLocationLoop(params) {
clearInterval(timer.value)
timer.value = null
}
function longitude() { function longitude() {
return longitudeVal.value return longitudeVal.value
@@ -78,9 +95,10 @@ const useLocationStore = defineStore("location", () => {
// 导入 // 导入
return { return {
getLocation, getLocation,
getLocationLoop,
clearGetLocationLoop,
longitudeVal, longitudeVal,
latitudeVal latitudeVal,
} }
}, { }, {
unistorage: true, unistorage: true,

View File

@@ -42,30 +42,59 @@ export class FileValidator {
* 构造函数 * 构造函数
* @param {Object} options 配置项 * @param {Object} options 配置项
* @param {number} [options.maxSizeMB=10] 最大文件大小 (MB) * @param {number} [options.maxSizeMB=10] 最大文件大小 (MB)
* @param {string[]} [options.allowedExtensions] 允许的扩展名列表 (如 ['jpg', 'png']),默认允许全部已知类型 * @param {string[]} [options.allowedExtensions = ['png','jpg','jpeg','gif','webp','svg','bmp','ico','pdf','doc','docx','xls','xlsx','csv','ppt','pptx','txt','md']] 允许的扩展名列表 (如 ['jpg', 'png']),默认允许全部已知类型
*/ */
version = '1.0.0'; version = '1.0.0';
constructor(options = {}) { constructor(options = {}) {
// 配置大小 (默认 10MB) // 配置大小 (默认 10MB)
this.maxSizeMB = options.maxSizeMB || 10; this.maxSizeMB = options.maxSizeMB || 10;
// 扩展名到 MIME 的映射(用于反向查找)
this.extToMime = {
png: 'image/png',
jpg: 'image/jpeg',
jpeg: 'image/jpeg',
gif: 'image/gif',
webp: 'image/webp',
pdf: 'application/pdf',
txt: 'text/plain',
md: 'text/markdown',
json: 'application/json',
csv: 'text/csv',
doc: 'application/msword',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
xls: 'application/vnd.ms-excel',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
ppt: 'application/vnd.ms-powerpoint',
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
};
// 如果传入的是 MIME 类型,转换为扩展名
let allowedExtensions = options.allowedExtensions || Object.keys(KNOWN_SIGNATURES);
// 配置允许的类型 // 配置允许的类型
// 如果传入了 allowedExtensions则只使用传入的否则使用全部 KNOWN_SIGNATURES
if (options.allowedExtensions && Array.isArray(options.allowedExtensions)) {
this.allowedConfig = {}; this.allowedConfig = {};
options.allowedExtensions.forEach((ext) => { allowedExtensions.forEach((extOrMime) => {
const key = ext.toLowerCase(); const key = extOrMime.toLowerCase();
if (KNOWN_SIGNATURES[key]) {
this.allowedConfig[key] = KNOWN_SIGNATURES[key]; // 如果是 MIME 类型,尝试转换为扩展名
let ext = key;
if (key.includes('/')) {
// 查找对应的扩展名
for (const [e, mime] of Object.entries(this.extToMime)) {
if (mime === key) {
ext = e;
break;
}
}
}
if (KNOWN_SIGNATURES[ext]) {
this.allowedConfig[ext] = KNOWN_SIGNATURES[ext];
} else { } else {
console.warn(`[FileValidator] 未知的文件类型: .${key},已忽略`); console.warn(`[FileValidator] 未知的文件类型: ${key},已忽略`);
} }
}); });
} else {
this.allowedConfig = {
...KNOWN_SIGNATURES
};
}
} }
/** /**
@@ -75,7 +104,7 @@ export class FileValidator {
try { try {
// fatal: true 会在遇到无效编码时抛出错误,而不是用 替换 // fatal: true 会在遇到无效编码时抛出错误,而不是用 替换
const decoder = new TextDecoder('utf-8', { const decoder = new TextDecoder('utf-8', {
fatal: true fatal: true,
}); });
decoder.decode(buffer); decoder.decode(buffer);
return true; return true;
@@ -128,7 +157,6 @@ export class FileValidator {
return rowCount; return rowCount;
} }
/** /**
* 【核心】:校验纯文本内容 * 【核心】:校验纯文本内容
* 1. 检查是否包含乱码 (非 UTF-8) * 1. 检查是否包含乱码 (非 UTF-8)
@@ -139,7 +167,7 @@ export class FileValidator {
let contentStr = ''; let contentStr = '';
try { try {
const decoder = new TextDecoder('utf-8', { const decoder = new TextDecoder('utf-8', {
fatal: true fatal: true,
}); });
contentStr = decoder.decode(buffer); contentStr = decoder.decode(buffer);
} catch (e) { } catch (e) {
@@ -177,6 +205,7 @@ export class FileValidator {
*/ */
validate(file) { validate(file) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
console.log('开始校验文件');
// 1. 基础对象检查 // 1. 基础对象检查
if (!file || !file.name) return reject('无效的文件对象'); if (!file || !file.name) return reject('无效的文件对象');