diff --git a/common/globalFunction.js b/common/globalFunction.js
index 9febf80..e2ff269 100644
--- a/common/globalFunction.js
+++ b/common/globalFunction.js
@@ -1,705 +1,724 @@
-import '@/lib/encryption/sm4.min.js'
-import useUserStore from "../stores/useUserStore";
-import {
- createRequestWithCache,
- createRequest,
- uploadFile
-} from "../utils/request";
-import streamRequest, {
- chatRequest
-} from "../utils/streamRequest.js";
-
-export const CloneDeep = (props) => {
- if (typeof props !== 'object' || props === null) {
- return props
- }
-
- let result
- if (props) {
- result = []
- } else {
- result = {}
- }
-
- for (let key in props) {
- if (props.hasOwnProperty(key)) {
- result[key] = CloneDeep(props[key])
- }
- }
-
- return result
-}
-
-
-export const msg = (title, duration = 1500, mask = false, icon = 'none', image) => {
- if (Boolean(title) === false) {
- return;
- }
- uni.showToast({
- title,
- duration,
- mask,
- icon,
- image
- });
-}
-
-const prePage = () => {
- let pages = getCurrentPages();
- let prePage = pages[pages.length - 2];
- return prePage.$vm;
-}
-
-
-export function safeReLaunch(url) {
- const pages = getCurrentPages();
- const currentPage = pages[pages.length - 1];
-
- // 移除传入url开头的斜杠用于对比
- const cleanUrl = url.startsWith('/') ? url.slice(1) : url;
-
- if (currentPage && currentPage.route === cleanUrl) {
- console.log('已在当前页');
- return;
- }
-
- uni.reLaunch({
- url
- });
-}
-
-
-
-/**
- * 页面跳转封装,支持 query 参数传递和返回回调
- * @param {string} url - 跳转路径
- * @param {object} options
- * @param {boolean} options.needLogin - 是否需要登录
- * @param {object} options.query - 携带参数
- * @param {function} options.onBack - 页面返回时的回调(目标页调用 uni.navigateBack 时传递数据)
- */
-let isJumping = false
-export const navTo = function(url, {
- needLogin = false,
- query = {},
- onBack = null
-} = {}) {
- const userStore = useUserStore();
- if (isJumping) return
- isJumping = true
- if (needLogin && !userStore.hasLogin) {
- setTimeout(() => {
- uni.navigateTo({
- url: '/pages/login/login'
- });
- isJumping = false
- }, 170);
- return;
- }
-
- const queryStr = Object.entries(query)
- .map(([key, val]) => `${key}=${encodeURIComponent(val)}`)
- .join('&');
- const finalUrl = queryStr ? `${url}?${queryStr}` : url;
-
- if (onBack) {
- const pages = getCurrentPages();
- const currentPage = pages[pages.length - 1];
- currentPage.__onBackCallback__ = onBack;
- }
-
- setTimeout(() => {
- uni.navigateTo({
- url: finalUrl
- });
- isJumping = false
- }, 170);
-};
-
-export const navBack = function({
- delta = 1,
- data = null,
- fallbackUrl = '/pages/index/index'
-} = {}) {
- const pages = getCurrentPages();
-
- if (pages.length > 1) {
- const prevPage = pages[pages.length - 1 - delta];
-
- // 如果上一页存在回调函数,调用
- if (data && prevPage?.__onBackCallback__) {
- prevPage.__onBackCallback__(data);
- }
-
- uni.navigateBack({
- delta
- });
- } else {
- // 没有可返回的页面,直接跳转 fallback 页面
- uni.reLaunch({
- url: fallbackUrl
- });
- }
-};
-// // 默认返回上一页
-// navBack();
-
-// // 返回上两层
-// navBack(2);
-
-// // 没有历史页面时跳转首页
-// navBack(1, '/pages/home/home');
-
-function getdeviceInfo() {
- const globalData = {
- statusBarHeight: 0, // 状态导航栏高度
- topHeight: 0, // 距离顶部高度
- navHeight: 0, // 总体高度
- windowHeight: 0, // 可使用窗口高度
- tabBarHight: 0, //底部导航栏高度
- };
- let systemInfo = uni.getSystemInfoSync()
- globalData.windowHeight = systemInfo.screenHeight
- // 底部导航栏
- globalData.tabBarHight = systemInfo.screenHeight - systemInfo.safeArea.bottom
- // 状态栏高度
- globalData.statusBarHeight = systemInfo.statusBarHeight
- // #ifdef MP-MP-WEIXIN
- let menuButtonInfo = uni.getMenuButtonBoundingClientRect()
- // 胶囊距离顶部高度
- globalData.topHeight = menuButtonInfo.top
- // 胶囊高度
- globalData.navHeight = menuButtonInfo.height
- // #endif
- return {
- ...globalData
- }
-}
-
-function sleep(time) {
- return new Promise((resolve) => setTimeout(resolve, time))
-}
-const cloneDeep = (obj) => {
- // 1.1 判断是否是对象
- const isObject = (obj) => (typeof obj === 'object' || typeof obj === 'function') && obj !== 'null'
-
- if (!isObject(obj)) {
- throw new Error('参数不是对象')
- }
- // 1.3 如果参数为数组,则复制数组各元素,否则复制对象属性
- const newObject = Array.isArray(obj) ? [...obj] : {
- ...obj
- }
- // 1.4 迭代
- Object.keys(newObject).forEach((key) => {
- // 1.5 判断如果遍历到的属性值为对象,则继续递归cloneDeep
- if (isObject(newObject[key])) {
- newObject[key] = cloneDeep(newObject[key])
- }
- })
- return newObject
-}
-
-const CopyText = (text) => {
- let input = document.createElement('textarea');
- input.value = text;
- document.body.appendChild(input);
- input.select();
- let flag = document.execCommand('copy')
- if (flag) {
- message.success('成功复制到剪贴板')
- } else {
- message.success('复制失败')
- }
- document.body.removeChild(input)
-}
-
-// 柯里化 降低使用范围,提高适用性
-function Exp(regExp) {
- return (str) => {
- return regExp.test(str)
- }
-}
-
-const checkingPhoneRegExp = Exp(/^1[3-9]{1}\d{9}/)
-// 手机号校验 checkingPhoneRegExp(phone)
-
-const checkingEmailRegExp = Exp(/^[a-z0-9_\.-]+@[a-z0-9_\.-]+[a-z0-9]{2,6}$/i)
-// 邮箱校验 checkingEmailRegExp(email)
-
-
-function throttle(fn, delay = 300) {
- let valid = true
- let savedArgs = null // 参数存储器
- let savedContext = null // 上下文存储器
-
- return function(...args) {
- // 保存当前参数和上下文
- savedArgs = args
- savedContext = this
-
- if (!valid) return false
- valid = false
- setTimeout(() => {
- fn.apply(savedContext, savedArgs)
- valid = true
- savedArgs = null // 清空存储
- savedContext = null
- }, delay)
- }
-}
-
-function debounce(fun, delay) {
- return function(args) {
- let that = this
- let _args = args
- clearTimeout(fun.id)
- fun.id = setTimeout(function() {
- fun.call(that, _args)
- }, delay)
- }
-}
-
-
-function toRad(degree) {
- return degree * Math.PI / 180;
-}
-
-function haversine(lat1, lon1, lat2, lon2) {
- const R = 6371; // 地球半径,单位为公里
- const a1 = toRad(lat1);
- const a2 = toRad(lat2);
- const b1 = toRad(lat2 - lat1);
- const b2 = toRad(lon2 - lon1);
-
- const a = Math.sin(b1 / 2) * Math.sin(b1 / 2) +
- Math.cos(a1) * Math.cos(a2) * Math.sin(b2 / 2) * Math.sin(b2 / 2);
- const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
- const distance = R * c; // 计算得到的距离,单位为公里
-
- return distance;
-}
-
-export function getDistanceFromLatLonInKm(lat1, lon1, lat2, lon2) {
- const R = 6371; // 地球平均半径,单位为公里
- const dLat = deg2rad(lat2 - lat1);
- const dLon = deg2rad(lon2 - lon1);
- const a =
- Math.sin(dLat / 2) * Math.sin(dLat / 2) +
- Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
- Math.sin(dLon / 2) * Math.sin(dLon / 2);
- const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
- const d = R * c;
- return {
- km: d,
- m: d * 1000
- };
-}
-
-// 将角度转换为弧度
-function deg2rad(deg) {
- return deg * (Math.PI / 180);
-}
-
-function vacanciesTo(vacancies) {
- if (vacancies === null) {
- return '-人'
- } else if (vacancies >= 0) {
- return vacancies + "人"
- } else {
- return '不限人数'
- }
-}
-
-function salaryGlobal(type = 'min') {
- const salay = [2, 5, 10, 15, 20, 25, 30, 50, 80];
- const salaymax = [2, 5, 10, 15, 20, 25, 30, 50, 80, 100];
- const salarys = salay.map((item, index) => ({
- label: item + 'k',
- value: item * 1000,
- children: CloneDeep(salaymax).splice(index).map((vItem) => ({
- label: vItem + 'k',
- value: vItem * 1000,
- }))
- }))
-
- return salarys
-}
-
-class CustomSystem {
- constructor() {
- const systemInfo = uni.getSystemInfoSync();
- this.systemInfo = systemInfo
- }
-}
-const customSystem = new CustomSystem()
-
-function setCheckedNodes(nodes, ids) {
- const isClear = ids.length === 0;
-
- nodes.forEach((firstLayer) => {
- // 每次处理都先重置
- firstLayer.checkednumber = 0;
-
- const traverse = (node) => {
- if (isClear) {
- node.checked = false;
- } else {
- node.checked = ids.includes(node.id);
- }
-
- if (node !== firstLayer && node.checked) {
- firstLayer.checkednumber++;
- }
-
- if (node.children && node.children.length) {
- node.children.forEach(child => traverse(child));
- }
- };
-
- traverse(firstLayer);
- });
-
- return nodes;
-}
-const formatTotal = (total) => {
- if (total < 10) return total.toString(); // 直接返回小于 10 的数
-
- const magnitude = Math.pow(10, Math.floor(Math.log10(total))); // 计算数量级
- const roundedTotal = Math.floor(total / magnitude) * magnitude; // 去掉零头
-
- return `${roundedTotal}+`;
-};
-
-export function formatDate(isoString) {
- const date = new Date(isoString);
- const year = date.getFullYear();
- const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从 0 开始,需要 +1
- const day = String(date.getDate()).padStart(2, '0');
- const hours = String(date.getHours()).padStart(2, '0');
- const minutes = String(date.getMinutes()).padStart(2, '0');
- const seconds = String(date.getSeconds()).padStart(2, '0');
-
- return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
-}
-
-export function insertSortData(data, attribute = 'createTime') {
- const sortedData = data.sort((a, b) => new Date(b[attribute]) - new Date(a[attribute])); // 按时间降序排序
- const result = [];
- let lastDate = '';
- let lastTitle = ''
-
-
- const now = new Date();
- const todayStr = now.toISOString().split('T')[0]; // 获取今天的日期字符串
- const yesterday = new Date(now.setDate(now.getDate() - 1)).toISOString().split('T')[0]; // 获取昨天的日期字符串
- const twoDaysAgo = new Date(now.setDate(now.getDate() - 1)).toISOString().split('T')[0]; // 获取前天的日期字符串
-
- sortedData.forEach(item => {
- const itemAttribute = item[attribute].replace('T', ' ')
- const itemDate = itemAttribute.split(' ')[0]; // 提取日期部分
-
- let title = itemDate;
- if (itemDate === todayStr) {
- title = '今天';
- } else if (itemDate === yesterday) {
- title = '昨天';
- } else if (itemDate === twoDaysAgo) {
- title = '前天';
- }
-
- if (lastDate !== itemDate) {
- result.push({
- title,
- isTitle: true
- });
- lastDate = itemDate;
- lastTitle = title;
- }
-
- result.push({
- ...item,
- isTitle: false
- });
- });
-
- return [result, lastTitle];
-}
-
-function getWeeksOfMonth(year, month) {
- const firstDay = new Date(year, month - 1, 1); // 当月第一天
- const lastDay = new Date(year, month, 0); // 当月最后一天
- const weeks = [];
- let week = [];
-
- for (let d = new Date(firstDay); d <= lastDay; d.setDate(d.getDate() + 1)) {
- // 补充第一周的上个月日期
- if (week.length === 0 && d.getDay() !== 1) {
- let prevMonday = new Date(d);
- prevMonday.setDate(d.getDate() - (d.getDay() === 0 ? 6 : d.getDay() - 1));
- while (prevMonday < d) {
- week.push({
- year: prevMonday.getFullYear(),
- month: prevMonday.getMonth() + 1,
- day: prevMonday.getDate(),
- fullDate: getLocalYYYYMMDD(prevMonday), // 修正
- weekday: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"][prevMonday.getDay()],
- isCurrent: false // 上个月日期
- });
- prevMonday.setDate(prevMonday.getDate() + 1);
- }
- }
-
- // 添加当前月份的日期
- week.push({
- year: d.getFullYear(),
- month: d.getMonth() + 1,
- day: d.getDate(),
- fullDate: getLocalYYYYMMDD(d), // 修正
- weekday: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"][d.getDay()],
- isCurrent: true // 当前月的日期
- });
-
- // 如果到了月末但当前周未满7天,需要补足到周日
- if (d.getTime() === lastDay.getTime() && week.length < 7) {
- let nextDay = new Date(d);
- nextDay.setDate(d.getDate() + 1);
- while (week.length < 7) {
- week.push({
- year: nextDay.getFullYear(),
- month: nextDay.getMonth() + 1,
- day: nextDay.getDate(),
- fullDate: getLocalYYYYMMDD(nextDay), // 修正
- weekday: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"][nextDay.getDay()],
- isCurrent: false // 下个月日期
- });
- nextDay.setDate(nextDay.getDate() + 1);
- }
- }
-
- // 如果本周满了(7天)或者到了月末
- if (week.length === 7 || d.getTime() === lastDay.getTime()) {
- weeks.push([...week]); // 存入当前周
- week = []; // 清空,准备下一周
- }
- }
-
- return weeks;
-}
-
-// 新增工具函数:将日期格式化为本地 YYYY-MM-DD 字符串
-function getLocalYYYYMMDD(date) {
- const y = date.getFullYear();
- const m = String(date.getMonth() + 1).padStart(2, '0');
- const d = String(date.getDate()).padStart(2, '0');
- return `${y}-${m}-${d}`;
-}
-
-function isFutureDate(dateStr) {
- const inputDate = new Date(dateStr);
- const today = new Date();
-
- // 只比较年月日,不考虑具体时间
- today.setHours(0, 0, 0, 0);
- inputDate.setHours(0, 0, 0, 0);
-
- return inputDate > today;
-}
-
-function parseQueryParams(url = window.location.href) {
- const queryString = url.split('?')[1]?.split('#')[0];
- const params = {};
- if (!queryString) return params;
-
- queryString.split('&').forEach(param => {
- const [key, value] = param.split('=');
- if (key) {
- params[decodeURIComponent(key)] = decodeURIComponent(value || '');
- }
- });
-
- return params;
-}
-
-function formatFileSize(bytes) {
- if (bytes < 1024) return bytes + ' B'
- else if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB'
- else if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(2) + ' MB'
- else return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB'
-}
-
-
-function sendingMiniProgramMessage(data = {
- text: 'hello'
-}, action = 'defalut') {
- jWeixin.miniProgram.postMessage({
- data,
- action
- });
-}
-
-function copyText(text) {
- uni.setClipboardData({
- data: text,
- showToast: false,
- success(res) {
- msg('复制成功')
- },
- });
-}
-
-function appendScriptTagElement(src) {
- if (!src) return null;
- return new Promise((resolve, reject) => {
- const script = document.createElement('script');
- script.src = src;
- script.onload = () => {
- resolve()
- };
- script.onerror = () => {
- reject()
- };
- document.body.appendChild(script);
- })
-}
-
-function isInWechatMiniProgramWebview() {
- const ua = navigator.userAgent.toLowerCase()
- return ua.includes('miniprogram') || window.__wxjs_environment === 'miniprogram'
-}
-
-function isEmptyObject(obj) {
- return obj && typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0;
-}
-
-function aes_Decrypt(word, key) {
- var key = CryptoJS.enc.Utf8.parse(key) //转为128bit
- var srcs = CryptoJS.enc.Hex.parse(word) //转为16进制
- var str = CryptoJS.enc.Base64.stringify(srcs) //变为Base64编码的字符串
- var decrypt = CryptoJS.AES.decrypt(str, key, {
- mode: CryptoJS.mode.ECB,
- spadding: CryptoJS.pad.Pkcs7
- })
- return decrypt.toString(CryptoJS.enc.Utf8)
-}
-export function sm2_Decrypt(word, key) {
- return SM.decrypt(word, key);
-}
-
-export function sm2_Encrypt(word, key) {
- return SM.encrypt(word, key);
-}
-
-export function sm4Decrypt(key, value, mode = "hex") {
- try {
- if (key.length !== 32) {
- alert('密钥必须是32位16进制字符串(128位)');
- return;
- }
- const decrypted = sm4.decrypt(value, key, {
- mode: 'ecb',
- cipherType: mode === 'hex' ? 'hex' : 'base64',
- padding: 'pkcs#5'
- });
-
- return decrypted
-
- } catch (e) {
- console.log('解密失败', e)
- }
-}
-
-export function sm4Encrypt(key, value, mode = "hex") {
- try {
-
- if (key.length !== 32) {
- alert('密钥必须是32位16进制字符串(128位)');
- return;
- }
-
- const encrypted = sm4.encrypt(value, key, {
- mode: 'ecb',
- cipherType: mode === 'hex' ? 'hex' : 'base64',
- padding: 'pkcs#5'
- });
-
- return encrypted
-
- } catch (e) {
- console.log('加密失败')
- }
-}
-
-export function reloadBrowser() {
- window.location.reload()
-}
-
-// 一体机环境判断
-export function isY9MachineType() {
- const ua = navigator.userAgent;
- const isY9Machine = /Y9-ZYYH/i.test(ua); // 匹配机器型号
- return isY9Machine;
-}
-
-// 一体机环境判断
-export function isAsdMachineType() {
- // const ua = navigator.userAgent;
- // const isY9Machine = /asd_hanweb/i.test(ua); // 匹配机器型号
- // return isY9Machine;
- return !!lightAppJssdk.user
-}
-
-
-export const $api = {
- msg,
- prePage,
- sleep,
- createRequest,
- streamRequest,
- chatRequest,
- insertSortData,
- uploadFile,
- formatFileSize,
- sendingMiniProgramMessage,
- copyText,
- aes_Decrypt,
- createRequestWithCache,
- safeReLaunch
-}
-
-
-
-export default {
- $api,
- navTo,
- navBack,
- cloneDeep,
- formatDate,
- getdeviceInfo,
- checkingPhoneRegExp,
- checkingEmailRegExp,
- throttle,
- debounce,
- haversine,
- getDistanceFromLatLonInKm,
- vacanciesTo,
- salaryGlobal,
- customSystem,
- setCheckedNodes,
- formatTotal,
- getWeeksOfMonth,
- isFutureDate,
- parseQueryParams,
- appendScriptTagElement,
- insertSortData,
- isInWechatMiniProgramWebview,
- isEmptyObject,
- sm4Decrypt,
- aes_Decrypt,
- sm2_Decrypt,
- sm2_Encrypt,
- safeReLaunch,
- reloadBrowser,
- isAsdMachineType,
- isY9MachineType
+// #ifdef H5
+import '@/lib/encryption/sm4.min.js'
+// #endif
+
+// #ifndef H5
+import { sm4 } from 'sm-crypto';
+// #endif
+
+
+import useUserStore from "../stores/useUserStore";
+import {
+ createRequestWithCache,
+ createRequest,
+ uploadFile
+} from "../utils/request";
+import streamRequest, {
+ chatRequest
+} from "../utils/streamRequest.js";
+
+export const CloneDeep = (props) => {
+ if (typeof props !== 'object' || props === null) {
+ return props
+ }
+
+ let result
+ if (props) {
+ result = []
+ } else {
+ result = {}
+ }
+
+ for (let key in props) {
+ if (props.hasOwnProperty(key)) {
+ result[key] = CloneDeep(props[key])
+ }
+ }
+
+ return result
+}
+
+
+export const msg = (title, duration = 1500, mask = false, icon = 'none', image) => {
+ if (Boolean(title) === false) {
+ return;
+ }
+ uni.showToast({
+ title,
+ duration,
+ mask,
+ icon,
+ image
+ });
+}
+
+const prePage = () => {
+ let pages = getCurrentPages();
+ let prePage = pages[pages.length - 2];
+ return prePage.$vm;
+}
+
+
+export function safeReLaunch(url) {
+ const pages = getCurrentPages();
+ const currentPage = pages[pages.length - 1];
+
+ // 移除传入url开头的斜杠用于对比
+ const cleanUrl = url.startsWith('/') ? url.slice(1) : url;
+
+ if (currentPage && currentPage.route === cleanUrl) {
+ console.log('已在当前页');
+ return;
+ }
+
+ uni.reLaunch({
+ url
+ });
+}
+
+
+
+/**
+ * 页面跳转封装,支持 query 参数传递和返回回调
+ * @param {string} url - 跳转路径
+ * @param {object} options
+ * @param {boolean} options.needLogin - 是否需要登录
+ * @param {object} options.query - 携带参数
+ * @param {function} options.onBack - 页面返回时的回调(目标页调用 uni.navigateBack 时传递数据)
+ */
+let isJumping = false
+export const navTo = function(url, {
+ needLogin = false,
+ query = {},
+ onBack = null
+} = {}) {
+ const userStore = useUserStore();
+ if (isJumping) return
+ isJumping = true
+ if (needLogin && !userStore.hasLogin) {
+ setTimeout(() => {
+ uni.navigateTo({
+ url: '/pages/login/login'
+ });
+ isJumping = false
+ }, 170);
+ return;
+ }
+
+ const queryStr = Object.entries(query)
+ .map(([key, val]) => `${key}=${encodeURIComponent(val)}`)
+ .join('&');
+ const finalUrl = queryStr ? `${url}?${queryStr}` : url;
+
+ if (onBack) {
+ const pages = getCurrentPages();
+ const currentPage = pages[pages.length - 1];
+ currentPage.__onBackCallback__ = onBack;
+ }
+
+ setTimeout(() => {
+ uni.navigateTo({
+ url: finalUrl
+ });
+ isJumping = false
+ }, 170);
+};
+
+export const navBack = function({
+ delta = 1,
+ data = null,
+ fallbackUrl = '/pages/index/index'
+} = {}) {
+ const pages = getCurrentPages();
+
+ if (pages.length > 1) {
+ const prevPage = pages[pages.length - 1 - delta];
+
+ // 如果上一页存在回调函数,调用
+ if (data && prevPage?.__onBackCallback__) {
+ prevPage.__onBackCallback__(data);
+ }
+
+ uni.navigateBack({
+ delta
+ });
+ } else {
+ // 没有可返回的页面,直接跳转 fallback 页面
+ uni.reLaunch({
+ url: fallbackUrl
+ });
+ }
+};
+// // 默认返回上一页
+// navBack();
+
+// // 返回上两层
+// navBack(2);
+
+// // 没有历史页面时跳转首页
+// navBack(1, '/pages/home/home');
+
+function getdeviceInfo() {
+ const globalData = {
+ statusBarHeight: 0, // 状态导航栏高度
+ topHeight: 0, // 距离顶部高度
+ navHeight: 0, // 总体高度
+ windowHeight: 0, // 可使用窗口高度
+ tabBarHight: 0, //底部导航栏高度
+ };
+ let systemInfo = uni.getSystemInfoSync()
+ globalData.windowHeight = systemInfo.screenHeight
+ // 底部导航栏
+ globalData.tabBarHight = systemInfo.screenHeight - systemInfo.safeArea.bottom
+ // 状态栏高度
+ globalData.statusBarHeight = systemInfo.statusBarHeight
+ // #ifdef MP-MP-WEIXIN
+ let menuButtonInfo = uni.getMenuButtonBoundingClientRect()
+ // 胶囊距离顶部高度
+ globalData.topHeight = menuButtonInfo.top
+ // 胶囊高度
+ globalData.navHeight = menuButtonInfo.height
+ // #endif
+ return {
+ ...globalData
+ }
+}
+
+function sleep(time) {
+ return new Promise((resolve) => setTimeout(resolve, time))
+}
+const cloneDeep = (obj) => {
+ // 1.1 判断是否是对象
+ const isObject = (obj) => (typeof obj === 'object' || typeof obj === 'function') && obj !== 'null'
+
+ if (!isObject(obj)) {
+ throw new Error('参数不是对象')
+ }
+ // 1.3 如果参数为数组,则复制数组各元素,否则复制对象属性
+ const newObject = Array.isArray(obj) ? [...obj] : {
+ ...obj
+ }
+ // 1.4 迭代
+ Object.keys(newObject).forEach((key) => {
+ // 1.5 判断如果遍历到的属性值为对象,则继续递归cloneDeep
+ if (isObject(newObject[key])) {
+ newObject[key] = cloneDeep(newObject[key])
+ }
+ })
+ return newObject
+}
+
+const CopyText = (text) => {
+ let input = document.createElement('textarea');
+ input.value = text;
+ document.body.appendChild(input);
+ input.select();
+ let flag = document.execCommand('copy')
+ if (flag) {
+ message.success('成功复制到剪贴板')
+ } else {
+ message.success('复制失败')
+ }
+ document.body.removeChild(input)
+}
+
+// 柯里化 降低使用范围,提高适用性
+function Exp(regExp) {
+ return (str) => {
+ return regExp.test(str)
+ }
+}
+
+const checkingPhoneRegExp = Exp(/^1[3-9]{1}\d{9}/)
+// 手机号校验 checkingPhoneRegExp(phone)
+
+const checkingEmailRegExp = Exp(/^[a-z0-9_\.-]+@[a-z0-9_\.-]+[a-z0-9]{2,6}$/i)
+// 邮箱校验 checkingEmailRegExp(email)
+
+
+function throttle(fn, delay = 300) {
+ let valid = true
+ let savedArgs = null // 参数存储器
+ let savedContext = null // 上下文存储器
+
+ return function(...args) {
+ // 保存当前参数和上下文
+ savedArgs = args
+ savedContext = this
+
+ if (!valid) return false
+ valid = false
+ setTimeout(() => {
+ fn.apply(savedContext, savedArgs)
+ valid = true
+ savedArgs = null // 清空存储
+ savedContext = null
+ }, delay)
+ }
+}
+
+function debounce(fun, delay) {
+ return function(args) {
+ let that = this
+ let _args = args
+ clearTimeout(fun.id)
+ fun.id = setTimeout(function() {
+ fun.call(that, _args)
+ }, delay)
+ }
+}
+
+
+function toRad(degree) {
+ return degree * Math.PI / 180;
+}
+
+function haversine(lat1, lon1, lat2, lon2) {
+ const R = 6371; // 地球半径,单位为公里
+ const a1 = toRad(lat1);
+ const a2 = toRad(lat2);
+ const b1 = toRad(lat2 - lat1);
+ const b2 = toRad(lon2 - lon1);
+
+ const a = Math.sin(b1 / 2) * Math.sin(b1 / 2) +
+ Math.cos(a1) * Math.cos(a2) * Math.sin(b2 / 2) * Math.sin(b2 / 2);
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+ const distance = R * c; // 计算得到的距离,单位为公里
+
+ return distance;
+}
+
+export function getDistanceFromLatLonInKm(lat1, lon1, lat2, lon2) {
+ const R = 6371; // 地球平均半径,单位为公里
+ const dLat = deg2rad(lat2 - lat1);
+ const dLon = deg2rad(lon2 - lon1);
+ const a =
+ Math.sin(dLat / 2) * Math.sin(dLat / 2) +
+ Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
+ Math.sin(dLon / 2) * Math.sin(dLon / 2);
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+ const d = R * c;
+ return {
+ km: d,
+ m: d * 1000
+ };
+}
+
+// 将角度转换为弧度
+function deg2rad(deg) {
+ return deg * (Math.PI / 180);
+}
+
+function vacanciesTo(vacancies) {
+ if (vacancies === null) {
+ return '-人'
+ } else if (vacancies >= 0) {
+ return vacancies + "人"
+ } else {
+ return '不限人数'
+ }
+}
+
+function salaryGlobal(type = 'min') {
+ const salay = [2, 5, 10, 15, 20, 25, 30, 50, 80];
+ const salaymax = [2, 5, 10, 15, 20, 25, 30, 50, 80, 100];
+ const salarys = salay.map((item, index) => ({
+ label: item + 'k',
+ value: item * 1000,
+ children: CloneDeep(salaymax).splice(index).map((vItem) => ({
+ label: vItem + 'k',
+ value: vItem * 1000,
+ }))
+ }))
+
+ return salarys
+}
+
+class CustomSystem {
+ constructor() {
+ const systemInfo = uni.getSystemInfoSync();
+ this.systemInfo = systemInfo
+ }
+}
+const customSystem = new CustomSystem()
+
+function setCheckedNodes(nodes, ids) {
+ const isClear = ids.length === 0;
+
+ nodes.forEach((firstLayer) => {
+ // 每次处理都先重置
+ firstLayer.checkednumber = 0;
+
+ const traverse = (node) => {
+ if (isClear) {
+ node.checked = false;
+ } else {
+ node.checked = ids.includes(node.id);
+ }
+
+ if (node !== firstLayer && node.checked) {
+ firstLayer.checkednumber++;
+ }
+
+ if (node.children && node.children.length) {
+ node.children.forEach(child => traverse(child));
+ }
+ };
+
+ traverse(firstLayer);
+ });
+
+ return nodes;
+}
+const formatTotal = (total) => {
+ if (total < 10) return total.toString(); // 直接返回小于 10 的数
+
+ const magnitude = Math.pow(10, Math.floor(Math.log10(total))); // 计算数量级
+ const roundedTotal = Math.floor(total / magnitude) * magnitude; // 去掉零头
+
+ return `${roundedTotal}+`;
+};
+
+export function formatDate(isoString) {
+ const date = new Date(isoString);
+ const year = date.getFullYear();
+ const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从 0 开始,需要 +1
+ const day = String(date.getDate()).padStart(2, '0');
+ const hours = String(date.getHours()).padStart(2, '0');
+ const minutes = String(date.getMinutes()).padStart(2, '0');
+ const seconds = String(date.getSeconds()).padStart(2, '0');
+
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+}
+
+export function insertSortData(data, attribute = 'createTime') {
+ const sortedData = data.sort((a, b) => new Date(b[attribute]) - new Date(a[attribute])); // 按时间降序排序
+ const result = [];
+ let lastDate = '';
+ let lastTitle = ''
+
+
+ const now = new Date();
+ const todayStr = now.toISOString().split('T')[0]; // 获取今天的日期字符串
+ const yesterday = new Date(now.setDate(now.getDate() - 1)).toISOString().split('T')[0]; // 获取昨天的日期字符串
+ const twoDaysAgo = new Date(now.setDate(now.getDate() - 1)).toISOString().split('T')[0]; // 获取前天的日期字符串
+
+ sortedData.forEach(item => {
+ const itemAttribute = item[attribute].replace('T', ' ')
+ const itemDate = itemAttribute.split(' ')[0]; // 提取日期部分
+
+ let title = itemDate;
+ if (itemDate === todayStr) {
+ title = '今天';
+ } else if (itemDate === yesterday) {
+ title = '昨天';
+ } else if (itemDate === twoDaysAgo) {
+ title = '前天';
+ }
+
+ if (lastDate !== itemDate) {
+ result.push({
+ title,
+ isTitle: true
+ });
+ lastDate = itemDate;
+ lastTitle = title;
+ }
+
+ result.push({
+ ...item,
+ isTitle: false
+ });
+ });
+
+ return [result, lastTitle];
+}
+
+function getWeeksOfMonth(year, month) {
+ const firstDay = new Date(year, month - 1, 1); // 当月第一天
+ const lastDay = new Date(year, month, 0); // 当月最后一天
+ const weeks = [];
+ let week = [];
+
+ for (let d = new Date(firstDay); d <= lastDay; d.setDate(d.getDate() + 1)) {
+ // 补充第一周的上个月日期
+ if (week.length === 0 && d.getDay() !== 1) {
+ let prevMonday = new Date(d);
+ prevMonday.setDate(d.getDate() - (d.getDay() === 0 ? 6 : d.getDay() - 1));
+ while (prevMonday < d) {
+ week.push({
+ year: prevMonday.getFullYear(),
+ month: prevMonday.getMonth() + 1,
+ day: prevMonday.getDate(),
+ fullDate: getLocalYYYYMMDD(prevMonday), // 修正
+ weekday: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"][prevMonday.getDay()],
+ isCurrent: false // 上个月日期
+ });
+ prevMonday.setDate(prevMonday.getDate() + 1);
+ }
+ }
+
+ // 添加当前月份的日期
+ week.push({
+ year: d.getFullYear(),
+ month: d.getMonth() + 1,
+ day: d.getDate(),
+ fullDate: getLocalYYYYMMDD(d), // 修正
+ weekday: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"][d.getDay()],
+ isCurrent: true // 当前月的日期
+ });
+
+ // 如果到了月末但当前周未满7天,需要补足到周日
+ if (d.getTime() === lastDay.getTime() && week.length < 7) {
+ let nextDay = new Date(d);
+ nextDay.setDate(d.getDate() + 1);
+ while (week.length < 7) {
+ week.push({
+ year: nextDay.getFullYear(),
+ month: nextDay.getMonth() + 1,
+ day: nextDay.getDate(),
+ fullDate: getLocalYYYYMMDD(nextDay), // 修正
+ weekday: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"][nextDay.getDay()],
+ isCurrent: false // 下个月日期
+ });
+ nextDay.setDate(nextDay.getDate() + 1);
+ }
+ }
+
+ // 如果本周满了(7天)或者到了月末
+ if (week.length === 7 || d.getTime() === lastDay.getTime()) {
+ weeks.push([...week]); // 存入当前周
+ week = []; // 清空,准备下一周
+ }
+ }
+
+ return weeks;
+}
+
+// 新增工具函数:将日期格式化为本地 YYYY-MM-DD 字符串
+function getLocalYYYYMMDD(date) {
+ const y = date.getFullYear();
+ const m = String(date.getMonth() + 1).padStart(2, '0');
+ const d = String(date.getDate()).padStart(2, '0');
+ return `${y}-${m}-${d}`;
+}
+
+function isFutureDate(dateStr) {
+ const inputDate = new Date(dateStr);
+ const today = new Date();
+
+ // 只比较年月日,不考虑具体时间
+ today.setHours(0, 0, 0, 0);
+ inputDate.setHours(0, 0, 0, 0);
+
+ return inputDate > today;
+}
+
+function parseQueryParams(url = window.location.href) {
+ const queryString = url.split('?')[1]?.split('#')[0];
+ const params = {};
+ if (!queryString) return params;
+
+ queryString.split('&').forEach(param => {
+ const [key, value] = param.split('=');
+ if (key) {
+ params[decodeURIComponent(key)] = decodeURIComponent(value || '');
+ }
+ });
+
+ return params;
+}
+
+function formatFileSize(bytes) {
+ if (bytes < 1024) return bytes + ' B'
+ else if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB'
+ else if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(2) + ' MB'
+ else return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB'
+}
+
+
+function sendingMiniProgramMessage(data = {
+ text: 'hello'
+}, action = 'defalut') {
+ jWeixin.miniProgram.postMessage({
+ data,
+ action
+ });
+}
+
+function copyText(text) {
+ uni.setClipboardData({
+ data: text,
+ showToast: false,
+ success(res) {
+ msg('复制成功')
+ },
+ });
+}
+
+function appendScriptTagElement(src) {
+ if (!src) return null;
+ return new Promise((resolve, reject) => {
+ const script = document.createElement('script');
+ script.src = src;
+ script.onload = () => {
+ resolve()
+ };
+ script.onerror = () => {
+ reject()
+ };
+ document.body.appendChild(script);
+ })
+}
+
+function isInWechatMiniProgramWebview() {
+ const ua = navigator.userAgent.toLowerCase()
+ return ua.includes('miniprogram') || window.__wxjs_environment === 'miniprogram'
+}
+
+function isEmptyObject(obj) {
+ return obj && typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0;
+}
+
+function aes_Decrypt(word, key) {
+ var key = CryptoJS.enc.Utf8.parse(key) //转为128bit
+ var srcs = CryptoJS.enc.Hex.parse(word) //转为16进制
+ var str = CryptoJS.enc.Base64.stringify(srcs) //变为Base64编码的字符串
+ var decrypt = CryptoJS.AES.decrypt(str, key, {
+ mode: CryptoJS.mode.ECB,
+ spadding: CryptoJS.pad.Pkcs7
+ })
+ return decrypt.toString(CryptoJS.enc.Utf8)
+}
+export function sm2_Decrypt(word, key) {
+ return SM.decrypt(word, key);
+}
+
+export function sm2_Encrypt(word, key) {
+ return SM.encrypt(word, key);
+}
+
+export function sm4Decrypt(key, value, mode = "hex") {
+ try {
+ if (key.length !== 32) {
+ alert('密钥必须是32位16进制字符串(128位)');
+ return;
+ }
+ const decrypted = sm4.decrypt(value, key, {
+ mode: 'ecb',
+ cipherType: mode === 'hex' ? 'hex' : 'base64',
+ padding: 'pkcs#5'
+ });
+ return decrypted
+
+ } catch (e) {
+ console.log('解密失败', e)
+ }
+}
+
+export function sm4Encrypt(key, value, mode = "hex") {
+ try {
+
+ if (key.length !== 32) {
+ alert('密钥必须是32位16进制字符串(128位)');
+ return;
+ }
+
+ const encrypted = sm4.encrypt(value, key, {
+ mode: 'ecb',
+ cipherType: mode === 'hex' ? 'hex' : 'base64',
+ padding: 'pkcs#5'
+ });
+
+ return encrypted
+
+ } catch (e) {
+ console.log('加密失败')
+ }
+}
+
+export function reloadBrowser() {
+ window.location.reload()
+}
+
+// 一体机环境判断
+export function isY9MachineType() {
+
+ try {
+ const ua = navigator.userAgent;
+ const isY9Machine = /Y9-ZYYH/i.test(ua); // 匹配机器型号
+ return isY9Machine;
+ } catch (error) {
+ return false
+ }
+
+}
+
+// 一体机环境判断
+export function isAsdMachineType() {
+ // const ua = navigator.userAgent;
+ // const isY9Machine = /asd_hanweb/i.test(ua); // 匹配机器型号
+ // return isY9Machine;
+ try {
+ return !!lightAppJssdk.user
+ } catch (error) {
+ false
+ }
+
+}
+
+
+
+export const $api = {
+ msg,
+ prePage,
+ sleep,
+ createRequest,
+ streamRequest,
+ chatRequest,
+ insertSortData,
+ uploadFile,
+ formatFileSize,
+ sendingMiniProgramMessage,
+ copyText,
+ aes_Decrypt,
+ createRequestWithCache,
+ safeReLaunch
+}
+
+
+
+export default {
+ $api,
+ navTo,
+ navBack,
+ cloneDeep,
+ formatDate,
+ getdeviceInfo,
+ checkingPhoneRegExp,
+ checkingEmailRegExp,
+ throttle,
+ debounce,
+ haversine,
+ getDistanceFromLatLonInKm,
+ vacanciesTo,
+ salaryGlobal,
+ customSystem,
+ setCheckedNodes,
+ formatTotal,
+ getWeeksOfMonth,
+ isFutureDate,
+ parseQueryParams,
+ appendScriptTagElement,
+ insertSortData,
+ isInWechatMiniProgramWebview,
+ isEmptyObject,
+ sm4Decrypt,
+ aes_Decrypt,
+ sm2_Decrypt,
+ sm2_Encrypt,
+ safeReLaunch,
+ reloadBrowser,
+ isAsdMachineType,
+ isY9MachineType
}
\ No newline at end of file
diff --git a/pages/chat/components/fileIcon.vue b/components/FileIcon/fileIcon.vue
similarity index 100%
rename from pages/chat/components/fileIcon.vue
rename to components/FileIcon/fileIcon.vue
diff --git a/pages/chat/components/fileText.vue b/components/FileText/fileText.vue
similarity index 100%
rename from pages/chat/components/fileText.vue
rename to components/FileText/fileText.vue
diff --git a/config.js b/config.js
index dced9d7..4d64e59 100644
--- a/config.js
+++ b/config.js
@@ -1,6 +1,6 @@
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',
// 语音转文字
diff --git a/hook/useColumnCount.js b/hook/useColumnCount.js
index 48421e1..8acd19f 100644
--- a/hook/useColumnCount.js
+++ b/hook/useColumnCount.js
@@ -53,15 +53,25 @@ export function useColumnCount(onChange = () => {}) {
onMounted(() => {
columnCount.value = 2
calcColumn()
- // if (process.client) {
- window.addEventListener('resize', calcColumn)
- // }
+ try {
+ // if (process.client) {
+ window.addEventListener('resize', calcColumn)
+ // }
+ } catch (error) {
+
+ }
+
})
onUnmounted(() => {
- // if (process.client) {
- window.removeEventListener('resize', calcColumn)
- // }
+ try {
+ // if (process.client) {
+ window.removeEventListener('resize', calcColumn)
+ // }
+ } catch (error) {
+
+ }
+
})
// 列数变化时执行回调
diff --git a/main.js b/main.js
index 570d0bb..6a562ea 100644
--- a/main.js
+++ b/main.js
@@ -26,9 +26,11 @@ import renderCompanyCollectionRecord from '@/components/renderCompanyCollectionR
import renderJobViewRecord from '@/components/renderJobViewRecord/renderJobViewRecord.vue';
import MyIcons from '@/components/My-icons/my-icons.vue';
import GlobalPopup from '@/components/GlobalPopup/GlobalPopup.vue'
+import FileIcon from '@/components/FileIcon/fileIcon.vue'
+import FileText from '@/components/FileText/fileText.vue'
// import Tabbar from '@/components/tabbar/midell-box.vue'
// 自动导入 directives 目录下所有指令
-console.log(lightAppJssdk)
+
const directives = import.meta.glob('./directives/*.js', {
eager: true
});
@@ -58,6 +60,8 @@ export function createApp() {
app.component('renderJobViewRecord', renderJobViewRecord) //渲染岗位浏览记录
app.component('MyIcons', MyIcons)
app.component('global-popup', GlobalPopup)
+ app.component('FileIcon', FileIcon)
+ app.component('FileText', FileText)
// app.component('tabbar-custom', Tabbar)
for (const path in directives) {
diff --git a/manifest.json b/manifest.json
index 21d1280..5d9dfa7 100644
--- a/manifest.json
+++ b/manifest.json
@@ -50,7 +50,7 @@
"quickapp" : {},
/* 小程序特有相关 */
"mp-weixin" : {
- "appid" : "",
+ "appid" : "wxdbdcc6a10153c99b",
"setting" : {
"urlCheck" : false,
"es6" : true,
diff --git a/packageA/pages/myResume/components/uploadQrcode.vue b/packageA/pages/myResume/components/uploadQrcode.vue
new file mode 100644
index 0000000..57abf0b
--- /dev/null
+++ b/packageA/pages/myResume/components/uploadQrcode.vue
@@ -0,0 +1,564 @@
+
+
+
+
+
+
+
+
+
diff --git a/packageA/pages/myResume/myResume.vue b/packageA/pages/myResume/myResume.vue
index 3ebb004..5818063 100644
--- a/packageA/pages/myResume/myResume.vue
+++ b/packageA/pages/myResume/myResume.vue
@@ -127,6 +127,7 @@
+
@@ -137,11 +138,14 @@ import { onLoad, onShow } from '@dcloudio/uni-app';
import { storeToRefs } from 'pinia';
import useUserStore from '@/stores/useUserStore';
import useDictStore from '@/stores/useDictStore';
-const { userInfo, isMiniProgram } = storeToRefs(useUserStore());
+const { userInfo, isMiniProgram,isMachineEnv } = storeToRefs(useUserStore());
const { getUserResume } = useUserStore();
const { getDictData, oneDictData } = useDictStore();
+import { playTextDirectly } from '@/hook/useTTSPlayer-all-in-one';
import config from '@/config.js';
+import UploadQrcode from './components/uploadQrcode.vue';
+const qrcodeRef = ref(null);
const showNotice = ref(true);
onLoad(() => {
getUserResume();
@@ -152,6 +156,10 @@ function closeNotice() {
}
function chooseResume() {
+ if(isMachineEnv.value){
+ qrcodeRef.value?.open()
+ return
+ }
uni.chooseImage({
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
@@ -162,9 +170,11 @@ function chooseResume() {
res = JSON.parse(res);
getUserResume();
$api.msg('上传成功');
+ playTextDirectly('上传成功')
})
.catch((err) => {
$api.msg('上传失败');
+ playTextDirectly('上传失败')
});
},
fail: (error) => {},
@@ -209,6 +219,23 @@ function uploadResume(tempFilePath, loading) {
});
});
}
+const handleFileSend = (rows)=>{
+ const file = {
+ url: rows[0].fileUrl,
+ type: rows[0].fileSuffix,
+ name: rows[0].originalName,
+ }
+
+ $api.createRequest('/app/oss/uploadToObs', { userId: userInfo.value.userId,url:file.url }, 'POST').then((res) => {
+ getUserResume();
+ $api.msg('上传成功');
+ playTextDirectly('上传失败')
+ }).catch(()=>{
+ $api.msg('上传失败');
+ playTextDirectly('上传失败')
+ })
+}
+
diff --git a/pages/index/index.vue b/pages/index/index.vue
index a4957da..3e33854 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -18,8 +18,13 @@
v-for="(_, index) in 2"
:key="index"
>
-
+
diff --git a/pages/search/search.vue b/pages/search/search.vue
index ab58954..d28370f 100644
--- a/pages/search/search.vue
+++ b/pages/search/search.vue
@@ -1,5 +1,6 @@
+
-
+
+
+
+ 职位
+
+
+ 专业
+
+
+
+
+
+ {{ item }}
+
+
搜索
@@ -86,7 +111,7 @@