| | |
| | | import { getToken } from '@/utils/auth' |
| | | import { getUnreadCount } from '@/api/message' |
| | | import storage from '@/utils/storage' |
| | | import { redirectToLoginByEnvironment } from '@/utils/wechat' |
| | | |
| | | export default { |
| | | data() { |
| | |
| | | } |
| | | }, |
| | | onLaunch: function(options) { |
| | | console.log('App onLaunch, options:', options); |
| | | this.lastToken = getToken() |
| | | this.initApp(options) |
| | | |
| | |
| | | if (token) { |
| | | this.lastToken = token |
| | | this.updateUnreadMessageBadge() |
| | | this.startMessagePolling() |
| | | // this.startMessagePolling() |
| | | } |
| | | }) |
| | | |
| | |
| | | this.stopMessagePolling() |
| | | this.lastToken = null |
| | | // 清除消息徽标 |
| | | uni.removeTabBarBadge({ index: 3 }) |
| | | try { |
| | | uni.removeTabBarBadge({ index: 3 }) |
| | | } catch (e) { |
| | | console.error('清除消息徽标失败:', e) |
| | | } |
| | | }) |
| | | }, |
| | | onShow: function() { |
| | |
| | | methods: { |
| | | // 初始化应用 |
| | | initApp(options) { |
| | | // 初始化应用配置 |
| | | this.initConfig() |
| | | // 检查用户登录状态并自动跳转到合适的登录页面 |
| | | this.checkLoginAndRedirect(options) |
| | | try { |
| | | // 初始化应用配置 |
| | | this.initConfig() |
| | | // 检查用户登录状态并自动跳转到合适的登录页面 |
| | | this.checkLoginAndRedirect(options) |
| | | } catch (e) { |
| | | console.error('初始化应用失败:', e) |
| | | } |
| | | |
| | | // 注意:不在应用启动时自动启动轮询 |
| | | // 只有在用户主动登录成功后才启动(通过 user-login 事件触发) |
| | |
| | | }, |
| | | // 检查登录状态并自动跳转到合适的登录页面 |
| | | checkLoginAndRedirect(options) { |
| | | if (!getToken()) { |
| | | // 检查运行环境并跳转到对应的登录页面 |
| | | // #ifdef MP-WEIXIN |
| | | // 在微信小程序环境中 |
| | | try { |
| | | if (!getToken()) { |
| | | console.log('用户未登录,准备跳转到登录页面') |
| | | // 使用工具类根据环境自动跳转到合适的登录页面 |
| | | redirectToLoginByEnvironment(options, this.$tab); |
| | | } else { |
| | | console.log('用户已登录,无需跳转') |
| | | } |
| | | } catch (e) { |
| | | console.error('检查登录状态并跳转失败:', e) |
| | | // fallback到普通登录页面 |
| | | try { |
| | | // 获取系统信息 |
| | | const systemInfo = uni.getSystemInfoSync() |
| | | console.log('系统信息:', systemInfo) |
| | | |
| | | // 检查environment字段是否为wxwork |
| | | if (systemInfo.environment === 'wxwork') { |
| | | console.log('检测到企业微信环境,跳转到企业微信免登页面') |
| | | // 构造带参数的URL |
| | | let url = '/pages/qylogin' |
| | | if (options && options.query) { |
| | | const queryParams = Object.keys(options.query).map(key => `${key}=${encodeURIComponent(options.query[key])}`).join('&') |
| | | if (queryParams) { |
| | | url += '?' + queryParams |
| | | } |
| | | } |
| | | this.$tab.reLaunch(url) |
| | | return |
| | | } else { |
| | | console.log('检测到普通微信环境,跳转到微信登录页面') |
| | | // 构造带参数的URL |
| | | let url = '/pages/login' |
| | | if (options && options.query) { |
| | | const queryParams = Object.keys(options.query).map(key => `${key}=${encodeURIComponent(options.query[key])}`).join('&') |
| | | if (queryParams) { |
| | | url += '?' + queryParams |
| | | } |
| | | } |
| | | this.$tab.reLaunch(url) |
| | | return |
| | | } |
| | | } catch (e) { |
| | | console.error('获取系统信息失败:', e) |
| | | // 默认跳转到普通登录页面 |
| | | this.$tab.reLaunch('/pages/login') |
| | | this.$tab.reLaunch('/pages/login'); |
| | | } catch (fallbackError) { |
| | | console.error('fallback跳转也失败了:', fallbackError); |
| | | } |
| | | // #endif |
| | | |
| | | // #ifndef MP-WEIXIN |
| | | // 非微信小程序环境,跳转到普通登录页面 |
| | | console.log('非微信小程序环境,跳转到普通登录页面') |
| | | let url = '/pages/login' |
| | | if (options && options.query) { |
| | | const queryParams = Object.keys(options.query).map(key => `${key}=${encodeURIComponent(options.query[key])}`).join('&') |
| | | if (queryParams) { |
| | | url += '?' + queryParams |
| | | } |
| | | } |
| | | this.$tab.reLaunch(url) |
| | | // #endif |
| | | } |
| | | }, |
| | | |
| | | // 判断当前是否在登录页面 |
| | | isLoginPage() { |
| | | const pages = getCurrentPages() |
| | | if (pages.length === 0) { |
| | | try { |
| | | const pages = getCurrentPages() |
| | | if (pages.length === 0) { |
| | | return false |
| | | } |
| | | const currentPage = pages[pages.length - 1] |
| | | const route = currentPage.route || '' |
| | | // 判断是否为登录相关页面 |
| | | return route.includes('login') || route.includes('register') |
| | | } catch (e) { |
| | | console.error('判断是否为登录页面失败:', e) |
| | | return false |
| | | } |
| | | const currentPage = pages[pages.length - 1] |
| | | const route = currentPage.route || '' |
| | | // 判断是否为登录相关页面 |
| | | return route.includes('login') || route.includes('register') |
| | | }, |
| | | |
| | | // 更新未读消息徽标 |
| | |
| | | |
| | | if (count > 0) { |
| | | // 设置徽标 |
| | | uni.setTabBarBadge({ |
| | | index: 3, // 消息页面在tabBar中的索引位置(0开始) |
| | | text: count > 99 ? '99+' : count.toString() |
| | | }) |
| | | try { |
| | | uni.setTabBarBadge({ |
| | | index: 3, // 消息页面在tabBar中的索引位置(0开始) |
| | | text: count > 99 ? '99+' : count.toString() |
| | | }) |
| | | } catch (e) { |
| | | console.error('设置消息徽标失败:', e) |
| | | } |
| | | } else { |
| | | // 移除徽标 |
| | | uni.removeTabBarBadge({ |
| | | index: 3 |
| | | }) |
| | | try { |
| | | uni.removeTabBarBadge({ |
| | | index: 3 |
| | | }) |
| | | } catch (e) { |
| | | console.error('移除消息徽标失败:', e) |
| | | } |
| | | } |
| | | }).catch(error => { |
| | | console.error('获取未读消息数量失败:', error) |
| | |
| | | |
| | | // 启动消息轮询 |
| | | startMessagePolling() { |
| | | // 每30秒轮询一次 |
| | | this.messagePollingTimer = setInterval(() => { |
| | | if (getToken()) { |
| | | this.updateUnreadMessageBadge() |
| | | } else { |
| | | // 如果用户已登出,停止轮询 |
| | | this.stopMessagePolling() |
| | | } |
| | | }, 30000) // 30秒 |
| | | try { |
| | | // 每30秒轮询一次 |
| | | this.messagePollingTimer = setInterval(() => { |
| | | if (getToken()) { |
| | | this.updateUnreadMessageBadge() |
| | | } else { |
| | | // 如果用户已登出,停止轮询 |
| | | this.stopMessagePolling() |
| | | } |
| | | }, 30000) // 30秒 |
| | | } catch (e) { |
| | | console.error('启动消息轮询失败:', e) |
| | | } |
| | | }, |
| | | |
| | | // 停止消息轮询 |
| | | stopMessagePolling() { |
| | | if (this.messagePollingTimer) { |
| | | clearInterval(this.messagePollingTimer) |
| | | this.messagePollingTimer = null |
| | | try { |
| | | if (this.messagePollingTimer) { |
| | | clearInterval(this.messagePollingTimer) |
| | | this.messagePollingTimer = null |
| | | } |
| | | } catch (e) { |
| | | console.error('停止消息轮询失败:', e) |
| | | } |
| | | }, |
| | | |
| | |
| | | this.hasSubscribed = true;//subscribeManager.checkLocalSubscribeStatus(); |
| | | |
| | | // 自动订阅(如果未订阅则显示确认弹窗) |
| | | this.autoSubscribeOnLaunch(); |
| | | // this.autoSubscribeOnLaunch(); |
| | | |
| | | // 加载用户绑定车辆信息 |
| | | this.loadUserVehicle(); |
| | |
| | | |
| | | <script> |
| | | import { getCodeImg, loginByOpenId, loginByWechatPhone } from '@/api/login' |
| | | import { isWxWorkEnvironment,redirectToQyLogin } from '@/utils/wechat' |
| | | |
| | | export default { |
| | | data() { |
| | |
| | | onLoad(options) { |
| | | // 保存页面参数 |
| | | this.pageOptions = options || {} |
| | | isWxWorkEnvironment().then(res=>{ |
| | | if(res){ |
| | | // console.log("企业微信环境 login.vue....") |
| | | redirectToQyLogin(options,this.$tab); |
| | | } |
| | | }); |
| | | |
| | | }, |
| | | created() { |
| | | this.getCode() |
| | |
| | | this.$store.dispatch('GetInfo').then(res => { |
| | | // 触发登录成功事件,启动消息轮询 |
| | | uni.$emit('user-login') |
| | | // 检查是否有redirect参数指定跳转页面 |
| | | if (this.pageOptions.redirect) { |
| | | // 解码redirect参数 |
| | | const redirectUrl = decodeURIComponent(this.pageOptions.redirect) |
| | | this.$tab.reLaunch(redirectUrl) |
| | | } else { |
| | | // 默认跳转到首页 |
| | | this.$tab.reLaunch('/pages/index') |
| | | } |
| | | // 处理自动跳转逻辑 |
| | | this.redirectAfterLogin() |
| | | }) |
| | | }, |
| | | |
| | |
| | | this.isWechat = false |
| | | console.log('当前环境:非微信小程序') |
| | | // #endif |
| | | |
| | | |
| | | }, |
| | | |
| | | // 尝试自动登录(检查本地是否有保存的OpenID) |
| | |
| | | const { setToken } = require('@/utils/auth') |
| | | setToken(token) |
| | | |
| | | // 检查是否有redirect参数指定跳转页面 |
| | | if (this.pageOptions.redirect) { |
| | | // 解码redirect参数 |
| | | const redirectUrl = decodeURIComponent(this.pageOptions.redirect) |
| | | this.$tab.reLaunch(redirectUrl) |
| | | } else { |
| | | // 默认跳转到首页 |
| | | this.$tab.reLaunch('/pages/index') |
| | | } |
| | | // 获取用户信息并处理自动跳转逻辑 |
| | | this.$store.dispatch('GetInfo').then(() => { |
| | | this.redirectAfterLogin() |
| | | }); |
| | | } else { |
| | | this.$modal.msgError(response.msg || '登录失败') |
| | | } |
| | |
| | | const { setToken } = require('@/utils/auth') |
| | | setToken(token) |
| | | |
| | | // 检查是否有redirect参数指定跳转页面 |
| | | if (this.pageOptions.redirect) { |
| | | // 解码redirect参数 |
| | | const redirectUrl = decodeURIComponent(this.pageOptions.redirect) |
| | | this.$tab.reLaunch(redirectUrl) |
| | | } else { |
| | | // 默认跳转到首页 |
| | | this.$tab.reLaunch('/pages/index') |
| | | } |
| | | // 获取用户信息并处理自动跳转逻辑 |
| | | this.$store.dispatch('GetInfo').then(() => { |
| | | this.redirectAfterLogin() |
| | | }); |
| | | } else { |
| | | // OpenID未绑定或验证失败,需要获取手机号绑定 |
| | | console.log('该OpenID尚未绑定或验证失败,需要获取手机号') |
| | |
| | | console.error('登录失败:', error) |
| | | this.$modal.msgError('登录失败,请重试') |
| | | }) |
| | | }, |
| | | |
| | | /** |
| | | * 获取URL参数 |
| | | */ |
| | | getUrlParam(name) { |
| | | // #ifdef H5 |
| | | const reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); |
| | | const r = window.location.search.substr(1).match(reg); |
| | | if (r != null) return decodeURIComponent(r[2]); |
| | | // #endif |
| | | |
| | | // #ifdef MP-WEIXIN |
| | | // 在小程序中,参数通过onLoad的options传递 |
| | | if (this.pageOptions && this.pageOptions[name]) { |
| | | return decodeURIComponent(this.pageOptions[name]); |
| | | } |
| | | // #endif |
| | | |
| | | return null; |
| | | }, |
| | | |
| | | /** |
| | | * 登录成功后的跳转处理 |
| | | */ |
| | | redirectAfterLogin() { |
| | | try { |
| | | // 检查是否有redirect参数指定跳转页面 |
| | | let redirectUrl = this.getUrlParam("redirect"); |
| | | |
| | | // 如果没有redirect参数,检查是否有保存的目标页面 |
| | | if (!redirectUrl) { |
| | | const { getTargetUrl } = require('@/utils/auth') |
| | | redirectUrl = getTargetUrl() |
| | | } |
| | | |
| | | if (redirectUrl) { |
| | | // 解码redirect参数 |
| | | redirectUrl = decodeURIComponent(redirectUrl); |
| | | console.log("自动跳转到指定页面:", redirectUrl); |
| | | this.$tab.reLaunch(redirectUrl); |
| | | } else { |
| | | // 默认跳转到首页 |
| | | console.log("跳转到首页"); |
| | | this.$tab.reLaunch('/pages/index'); |
| | | } |
| | | } catch (e) { |
| | | console.error("跳转失败,使用默认跳转:", e); |
| | | // 出现异常时,默认跳转到首页 |
| | | this.$tab.reLaunch('/pages/index'); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | <script> |
| | | import { qyWechatAutoLogin } from "@/api/login"; |
| | | import { buildUrlWithParams } from "@/utils/wechat"; |
| | | |
| | | export default { |
| | | data() { |
| | |
| | | }, |
| | | |
| | | onLoad(options) { |
| | | // 保存页面参数 |
| | | this.pageOptions = options || {}; |
| | | // 页面加载时执行免登流程 |
| | | this.qyWechatAutoLogin(); |
| | | // 添加容错处理 |
| | | try { |
| | | // 保存页面参数 |
| | | this.pageOptions = options || {}; |
| | | // 页面加载时执行免登流程 |
| | | this.qyWechatAutoLogin(); |
| | | } catch (e) { |
| | | console.error('页面加载出错:', e); |
| | | this.loading = false; |
| | | this.error = true; |
| | | this.errorMessage = "页面初始化失败,请重试"; |
| | | } |
| | | }, |
| | | |
| | | methods: { |
| | | async getLoginCode() { |
| | | //这里要调用wx.qy.login获取code,是否有集成到uni-app中呢 |
| | | return new Promise((resolve, reject) => { |
| | | wx.qy.login({ |
| | | success: (res) => { |
| | | if (res.code) { |
| | | console.log("企业微信小程序 ---> code:", res.code); |
| | | resolve(res.code); // 返回 code 给后端 |
| | | } else { |
| | | reject(new Error("获取 code 失败:" + res.errMsg)); |
| | | } |
| | | }, |
| | | fail: (err) => { |
| | | console.error("wx.qy.login 调用失败:", err); |
| | | // 常见失败原因:非企业微信客户端打开、小程序未关联企业微信等 |
| | | reject(new Error("企业微信登录接口调用失败:" + err.errMsg)); |
| | | }, |
| | | }); |
| | | }); |
| | | }, |
| | | /** |
| | | * 企业微信免登流程 |
| | | */ |
| | |
| | | // 在微信小程序环境中,通过企业微信免登 |
| | | console.log("企业微信小程序环境免登"); |
| | | |
| | | // 获取URL参数中的code |
| | | // 直接通过企业微信API获取code,不使用URL中的code |
| | | const code = await this.getLoginCode(); |
| | | |
| | | if (!code) { |
| | | // 如果没有code,尝试通过企业微信API获取 |
| | | this.handleWxWorkLogin(); |
| | | return; |
| | | throw new Error("无法获取企业微信授权code"); |
| | | } |
| | | |
| | | // 调用后端接口进行免登 |
| | |
| | | const token = response.data.token; |
| | | |
| | | this.$store.commit('SET_TOKEN', token) |
| | | // 必须调用setToken保存到本地存储 |
| | | // 必须调用setToken保存到本地存储 |
| | | const { setToken } = require('@/utils/auth') |
| | | setToken(token) |
| | | // 获取用户信息 |
| | |
| | | } |
| | | |
| | | // 获取URL参数中的code |
| | | const codeH5 = this.getUrlParam("code"); |
| | | |
| | | let codeH5 = this.getUrlParam("code"); |
| | | |
| | | // 如果URL中没有code,则跳转到企业微信授权页面 |
| | | if (!codeH5) { |
| | | // 如果没有code,则跳转到企业微信授权页面 |
| | | this.redirectToWxWorkAuth(); |
| | | return; |
| | | } |
| | |
| | | }, |
| | | |
| | | /** |
| | | * 处理企业微信登录 |
| | | * 获取企业微信登录code |
| | | */ |
| | | handleWxWorkLogin() { |
| | | // #ifdef MP-WEIXIN |
| | | // 在企业微信小程序中,可以直接调用企业微信登录API |
| | | uni.login({ |
| | | provider: "weixin", |
| | | success: (loginRes) => { |
| | | console.log("企业微信登录成功", loginRes); |
| | | // 调用后端接口进行免登 |
| | | qyWechatAutoLogin(loginRes.code) |
| | | .then((response) => { |
| | | if (response.code === 200) { |
| | | // 免登成功,保存token |
| | | const token = response.data.token; |
| | | this.$store.commit("SET_TOKEN", token); |
| | | uni.setStorageSync("token", token); |
| | | |
| | | // 获取用户信息 |
| | | this.$store.dispatch("GetInfo").then(() => { |
| | | // 跳转到首页或其他指定页面 |
| | | this.redirectAfterLogin(); |
| | | }); |
| | | } else { |
| | | throw new Error(response.msg || "免登失败"); |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | console.error("免登失败:", error); |
| | | this.loading = false; |
| | | this.error = true; |
| | | this.errorMessage = error.message || "免登失败,请稍后重试"; |
| | | }); |
| | | }, |
| | | fail: (err) => { |
| | | console.error("企业微信登录失败:", err); |
| | | this.loading = false; |
| | | this.error = true; |
| | | this.errorMessage = "企业微信登录失败,请稍后重试"; |
| | | }, |
| | | getLoginCode() { |
| | | return new Promise((resolve, reject) => { |
| | | // #ifdef MP-WEIXIN |
| | | // 使用企业微信小程序API获取code |
| | | wx.qy.login({ |
| | | success: (res) => { |
| | | if (res.code) { |
| | | console.log("企业微信小程序 ---> code:", res.code); |
| | | resolve(res.code); |
| | | } else { |
| | | reject(new Error("获取code失败:" + res.errMsg)); |
| | | } |
| | | }, |
| | | fail: (err) => { |
| | | console.error("wx.qy.login调用失败:", err); |
| | | reject(new Error("企业微信登录接口调用失败:" + err.errMsg)); |
| | | }, |
| | | }); |
| | | // #endif |
| | | |
| | | // #ifndef MP-WEIXIN |
| | | resolve(null); |
| | | // #endif |
| | | }); |
| | | // #endif |
| | | }, |
| | | |
| | | /** |
| | | * 检查是否在企业微信环境 |
| | | */ |
| | | isWxWorkEnvironment() { |
| | | // #ifdef H5 |
| | | const userAgent = navigator.userAgent.toLowerCase(); |
| | | return userAgent.includes("wxwork"); |
| | | // #endif |
| | | |
| | | // #ifndef H5 |
| | | return false; |
| | | // #endif |
| | | }, |
| | | |
| | | /** |
| | |
| | | // #endif |
| | | |
| | | // #ifdef MP-WEIXIN |
| | | // 在小程序中可以通过其他方式获取参数 |
| | | // 这里简化处理,实际项目中可以根据需要调整 |
| | | // 在小程序中,参数通过onLoad的options传递 |
| | | if (this.pageOptions && this.pageOptions[name]) { |
| | | return decodeURIComponent(this.pageOptions[name]); |
| | | } |
| | | // #endif |
| | | |
| | | return null; |
| | | }, |
| | | |
| | | /** |
| | | * 跳转到企业微信授权页面 |
| | | * 跳转到企业微信授权页面(H5环境) |
| | | */ |
| | | redirectToWxWorkAuth() { |
| | | // #ifdef H5 |
| | | // 从全局配置中获取企业微信配置 |
| | | const config = getApp().globalData.config; |
| | | const corpId = config.qyWechatCorpId || "your_corp_id"; // 企业ID |
| | |
| | | const authUrl = `https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=${corpId}&agentid=${agentId}&redirect_uri=${redirectUri}&state=${state}`; |
| | | |
| | | window.location.href = authUrl; |
| | | // #endif |
| | | }, |
| | | |
| | | /** |
| | | * 登录成功后的跳转处理 |
| | | */ |
| | | redirectAfterLogin() { |
| | | // 检查是否有redirect参数指定跳转页面 |
| | | if (this.pageOptions.redirect) { |
| | | // 解码redirect参数 |
| | | const redirectUrl = decodeURIComponent(this.pageOptions.redirect); |
| | | this.$tab.reLaunch(redirectUrl); |
| | | } else { |
| | | // 默认跳转到首页 |
| | | try { |
| | | // 检查是否有redirect参数指定跳转页面 |
| | | let redirectUrl = this.getUrlParam("redirect"); |
| | | |
| | | // 如果没有redirect参数,检查是否有保存的目标页面 |
| | | if (!redirectUrl) { |
| | | const { getTargetUrl } = require('@/utils/auth') |
| | | redirectUrl = getTargetUrl() |
| | | } |
| | | |
| | | if (redirectUrl) { |
| | | // 解码redirect参数 |
| | | redirectUrl = decodeURIComponent(redirectUrl); |
| | | console.log("自动跳转到指定页面:", redirectUrl); |
| | | this.$tab.reLaunch(redirectUrl); |
| | | } else { |
| | | // 默认跳转到首页 |
| | | console.log("跳转到首页"); |
| | | this.$tab.reLaunch("/pages/index"); |
| | | } |
| | | } catch (e) { |
| | | console.error("跳转失败,使用默认跳转:", e); |
| | | // 出现异常时,默认跳转到首页 |
| | | this.$tab.reLaunch("/pages/index"); |
| | | } |
| | | }, |
| | |
| | | return whiteList.indexOf(path) !== -1 |
| | | } |
| | | |
| | | // 保存目标页面URL,用于登录后跳转 |
| | | function saveTargetUrl(url) { |
| | | try { |
| | | uni.setStorageSync('targetUrl', url) |
| | | } catch (e) { |
| | | console.error('保存目标URL失败:', e) |
| | | } |
| | | } |
| | | |
| | | // 页面跳转验证拦截器 |
| | | let list = ["navigateTo", "redirectTo", "reLaunch", "switchTab"] |
| | | list.forEach(item => { |
| | | uni.addInterceptor(item, { |
| | | invoke(to) { |
| | | if (getToken()) { |
| | | // 已登录 |
| | | if (to.url === loginPage) { |
| | | // 如果已经登录还要访问登录页,直接跳转到首页 |
| | | uni.reLaunch({ url: "/" }) |
| | | return false |
| | | } |
| | | return true |
| | | } else { |
| | | // 未登录 |
| | | if (checkWhite(to.url)) { |
| | | // 白名单页面可以直接访问 |
| | | return true |
| | | } |
| | | |
| | | // 保存当前要访问的页面作为登录后跳转的目标 |
| | | saveTargetUrl(to.url) |
| | | |
| | | // 跳转到登录页面 |
| | | uni.reLaunch({ url: loginPage }) |
| | | return false |
| | | } |
| | |
| | | export function removeToken() { |
| | | return uni.removeStorageSync(TokenKey) |
| | | } |
| | | |
| | | // 获取并清除目标页面URL |
| | | export function getTargetUrl() { |
| | | try { |
| | | const url = uni.getStorageSync('targetUrl') |
| | | if (url) { |
| | | uni.removeStorageSync('targetUrl') |
| | | } |
| | | return url |
| | | } catch (e) { |
| | | console.error('获取目标URL失败:', e) |
| | | return null |
| | | } |
| | | } |
| New file |
| | |
| | | /** |
| | | * 微信环境检测和跳转工具类 |
| | | */ |
| | | |
| | | /** |
| | | * 检查是否为企业微信环境 |
| | | * @returns {Promise<boolean>} 是否为企业微信环境 |
| | | */ |
| | | export function isWxWorkEnvironment() { |
| | | return new Promise((resolve) => { |
| | | // #ifdef MP-WEIXIN |
| | | try { |
| | | // 获取系统信息 |
| | | const systemInfo = uni.getSystemInfoSync(); |
| | | // 检查environment字段是否为wxwork |
| | | const isWxWork = systemInfo.environment === 'wxwork'; |
| | | console.log('环境检测结果:', isWxWork, systemInfo); |
| | | resolve(isWxWork); |
| | | } catch (e) { |
| | | console.error('获取系统信息失败:', e); |
| | | // fallback检测 |
| | | resolve(false); |
| | | } |
| | | // #endif |
| | | |
| | | // #ifndef MP-WEIXIN |
| | | resolve(false); |
| | | // #endif |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 构造带参数的URL |
| | | * @param {string} baseUrl 基础URL |
| | | * @param {Object} queryParameters 查询参数对象 |
| | | * @returns {string} 构造后的URL |
| | | */ |
| | | export function buildUrlWithParams(baseUrl, queryParameters) { |
| | | if (!queryParameters) return baseUrl; |
| | | |
| | | const queryParams = Object.keys(queryParameters) |
| | | .map(key => `${key}=${encodeURIComponent(queryParameters[key])}`) |
| | | .join('&'); |
| | | |
| | | if (queryParams) { |
| | | return baseUrl + '?' + queryParams; |
| | | } |
| | | |
| | | return baseUrl; |
| | | } |
| | | |
| | | /** |
| | | * 根据环境自动跳转到合适的登录页面 |
| | | * @param {Object} options 启动参数 |
| | | * @param {Object} tab tab导航对象 |
| | | */ |
| | | export async function redirectToLoginByEnvironment(options, tab) { |
| | | // #ifdef MP-WEIXIN |
| | | // 在微信小程序环境中 |
| | | try { |
| | | const isWxWork = await isWxWorkEnvironment(); |
| | | |
| | | if (isWxWork) { |
| | | console.log('检测到企业微信环境,跳转到企业微信免登页面'); |
| | | // 构造带参数的URL |
| | | redirectToQyLogin(options, tab); |
| | | return; |
| | | } else { |
| | | console.log('检测到普通微信环境,跳转到微信登录页面'); |
| | | redirectToLogin(options, tab); |
| | | return; |
| | | } |
| | | } catch (e) { |
| | | console.error('环境检测失败:', e); |
| | | redirectToLogin(options, tab); |
| | | } |
| | | // #endif |
| | | |
| | | // #ifndef MP-WEIXIN |
| | | // 非微信小程序环境,跳转到普通登录页面 |
| | | console.log('非微信小程序环境,跳转到普通登录页面'); |
| | | redirectToLogin(options, tab); |
| | | // #endif |
| | | } |
| | | |
| | | |
| | | export function redirectToQyLogin(options, tab) { |
| | | try { |
| | | let url = '/pages/qylogin'; |
| | | if (options && options.query) { |
| | | url = buildUrlWithParams(url, options.query); |
| | | } |
| | | console.log('跳转到企业微信登录页面:', url); |
| | | tab.reLaunch(url); |
| | | } catch (e) { |
| | | console.error('跳转到企业微信登录页面失败:', e); |
| | | // fallback到普通登录页面 |
| | | redirectToLogin(options, tab); |
| | | } |
| | | } |
| | | |
| | | export function redirectToLogin(options, tab) { |
| | | try { |
| | | let url = '/pages/login'; |
| | | if (options && options.query) { |
| | | url = buildUrlWithParams(url, options.query); |
| | | } |
| | | console.log('跳转到普通登录页面:', url); |
| | | tab.reLaunch(url); |
| | | } catch (e) { |
| | | console.error('跳转到普通登录页面失败:', e); |
| | | // 如果跳转失败,至少确保不会卡在当前页面 |
| | | try { |
| | | tab.reLaunch('/pages/login'); |
| | | } catch (fallbackError) { |
| | | console.error('fallback跳转也失败了:', fallbackError); |
| | | } |
| | | } |
| | | } |
| | | |
| | | export default { |
| | | isWxWorkEnvironment, |
| | | buildUrlWithParams, |
| | | redirectToLogin, |
| | | redirectToQyLogin, |
| | | redirectToLoginByEnvironment |
| | | }; |
| | |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | sdf.setLenient(false); // 严格解析日期 |
| | | Date date = sdf.parse(statDate.trim()); |
| | | logger.info("---> 手动计算车辆里程汇总,车辆ID: {}, 日期: {}", vehicleId, date); |
| | | // logger.info("---> 手动计算车辆里程汇总,车辆ID: {}, 日期: {}", vehicleId, date); |
| | | VehicleMileageStats stats = vehicleMileageStatsService.calculateAndSaveMileageStats(vehicleId, date); |
| | | // 修复String到Date转换问题,添加更好的错误处理 |
| | | if (stats != null) { |
| | |
| | | departure = task.getDepartureAddress(); |
| | | } |
| | | DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm"); |
| | | content.append(",出发时间:").append(df.format(dispatchTime)); |
| | | content.append(",出发时间:").append(df.format(dispatchTime)); |
| | | |
| | | // 添加目的地信息 |
| | | String destination = null; |
| | |
| | | } |
| | | |
| | | if (departure != null || destination != null) { |
| | | content = new StringBuilder(); |
| | | if (departure != null) { |
| | | content.append("出发地:").append(departure); |
| | | } |
| | |
| | | boolean sendNotifyMessage(Long userId, String title, String content, String notifyUrl); |
| | | |
| | | /** |
| | | * 发送企业微信消息,带小程序路径链接 |
| | | * @param userId |
| | | * @param title |
| | | * @param content |
| | | * @param appId |
| | | * @param businessUrl 小程序访问路径 |
| | | * @return |
| | | */ |
| | | boolean sendNotifyMessage(Long userId, String title, String content, String appId,String businessUrl); |
| | | |
| | | /** |
| | | * 发送企业微信文本消息 |
| | | * |
| | | * @param qyUserId 企业微信用户ID |
| | |
| | | */ |
| | | boolean sendTextMessage(String qyUserId, String title, String content, String notifyUrl); |
| | | |
| | | boolean sendTextMessage(String qyUserId, String title, String content, String appId,String businessUrl); |
| | | |
| | | /** |
| | | * 获取用户的企业微信ID |
| | | * |
| | |
| | | package com.ruoyi.system.service.impl; |
| | | |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.ruoyi.common.config.WechatConfig; |
| | | import com.ruoyi.common.utils.DateUtils; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.system.domain.*; |
| | |
| | | @Autowired |
| | | private IQyWechatService qyWechatService; |
| | | |
| | | |
| | | @Autowired |
| | | private WechatConfig wechatConfig; |
| | | |
| | | @Autowired |
| | | private ISysEmergencyTaskService sysEmergencyTaskService; |
| | |
| | | if(emergency==null){ |
| | | return false; |
| | | } |
| | | Long dispatchOrderId = emergency.getLegacyDispatchOrdId(); |
| | | String oldsiteUrl= sysConfigService.selectConfigByKey("oldsite.url"); |
| | | if(oldsiteUrl==null){ |
| | | oldsiteUrl="https://sys.966120.com.cn/m_DispatchOrder.gds?DispatchOrdID="; |
| | | } |
| | | String url=oldsiteUrl+dispatchOrderId; |
| | | // Long dispatchOrderId = emergency.getLegacyDispatchOrdId(); |
| | | // String oldsiteUrl= sysConfigService.selectConfigByKey("oldsite.url"); |
| | | // if(oldsiteUrl==null){ |
| | | // oldsiteUrl="https://sys.966120.com.cn/m_DispatchOrder.gds?DispatchOrdID="; |
| | | // } |
| | | String appId=wechatConfig.getAppId(); |
| | | String pathPage="/pagesTask/detail?id="+taskId; |
| | | // 发送企业微信消息 |
| | | boolean success = qyWechatService.sendNotifyMessage( |
| | | notifyTask.getUserId(), |
| | | notifyTask.getTitle(), |
| | | notifyTask.getContent(),url |
| | | notifyTask.getContent(),appId,pathPage |
| | | ); |
| | | |
| | | if (success) { |
| | |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public boolean sendNotifyMessage(Long userId, String title, String content, String appId, String businessUrl) { |
| | | try { |
| | | // 检查服务是否启用 |
| | | if (!isEnabled()) { |
| | | log.info("企业微信服务未启用,跳过消息发送"); |
| | | return false; |
| | | } |
| | | |
| | | // 获取用户的企业微信ID |
| | | String qyUserId = getQyUserIdByUserId(userId); |
| | | if (StringUtils.isEmpty(qyUserId)) { |
| | | log.warn("用户{}未绑定企业微信ID,无法发送消息", userId); |
| | | return false; |
| | | } |
| | | |
| | | // 发送文本消息 |
| | | return sendTextMessage(qyUserId, title, content, appId, businessUrl); |
| | | } catch (Exception e) { |
| | | log.error("企业微信消息发送异常,userId={}", userId, e); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 发送企业微信文本消息 |
| | | */ |
| | |
| | | article.setTitle(title); |
| | | article.setDescription(content); |
| | | article.setUrl(notifyUrl); |
| | | |
| | | // 设置默认图片URL,您可以根据需要修改 |
| | | |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public boolean sendTextMessage(String qyUserId, String title, String content, String appId, String businessUrl) { |
| | | try { |
| | | // 检查服务是否启用 |
| | | if (!isEnabled()) { |
| | | log.info("企业微信服务未启用,跳过消息发送"); |
| | | return false; |
| | | } |
| | | |
| | | // 获取企业微信配置 |
| | | String corpId = configService.selectConfigByKey("qy_wechat.corp_id"); |
| | | String corpSecret = configService.selectConfigByKey("qy_wechat.miniprogram_secret"); |
| | | |
| | | if (StringUtils.isEmpty(corpId) || StringUtils.isEmpty(corpSecret)) { |
| | | log.error("企业微信配置不完整,缺少corpId或corpSecret"); |
| | | return false; |
| | | } |
| | | |
| | | // 获取AccessToken |
| | | String accessToken = qyWechatAccessTokenService.getQyMiniAccessToken(corpId, corpSecret); |
| | | if (StringUtils.isEmpty(accessToken)) { |
| | | log.error("获取企业微信AccessToken失败"); |
| | | return false; |
| | | } |
| | | |
| | | // 构造请求URL |
| | | String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + accessToken; |
| | | |
| | | // 构造文章对象 |
| | | QyWechatArticle article = new QyWechatArticle(); |
| | | article.setTitle(title); |
| | | article.setDescription(content); |
| | | article.setAppid(appId); |
| | | article.setPagepath(businessUrl); |
| | | |
| | | // 设置默认图片URL,您可以根据需要修改 |
| | | |
| | | |
| | | // 构造请求参数 |
| | | Map<String, Object> params = new HashMap<>(); |
| | | params.put("touser", qyUserId); |
| | | params.put("msgtype", "news"); |
| | | params.put("agentid", Integer.parseInt(configService.selectConfigByKey("qywechat.miniprogram.agentid"))); |
| | | |
| | | // 构造文章列表 |
| | | List<QyWechatArticle> articles = new ArrayList<>(); |
| | | articles.add(article); |
| | | params.put("news", Collections.singletonMap("articles", articles)); |
| | | |
| | | // 发送HTTP POST请求 |
| | | String response = sendHttpPostRequest(url, params); |
| | | |
| | | if (StringUtils.isEmpty(response)) { |
| | | log.error("发送企业微信消息失败,响应为空"); |
| | | return false; |
| | | } |
| | | |
| | | // 解析响应结果 |
| | | QyWechatResponse result = parseResponse(response); |
| | | |
| | | if (result != null && result.getErrcode() == 0) { |
| | | log.info("企业微信消息发送成功,用户ID: {}", qyUserId); |
| | | return true; |
| | | } else { |
| | | log.error("企业微信消息发送失败,错误码: {}, 错误信息: {}", |
| | | result != null ? result.getErrcode() : "unknown", |
| | | result != null ? result.getErrmsg() : response); |
| | | return false; |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("企业微信文本消息发送异常,qyUserId={}", qyUserId, e); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取用户的企业微信ID |
| | | */ |
| | |
| | | } |
| | | } |
| | | } |
| | | if(updateVO.getAssignees()!=null && !updateVO.getAssignees().isEmpty()){ |
| | | TaskCreateVO.AssigneeInfo assigneeInfo= updateVO.getAssignees().get(0); |
| | | task.setAssigneeId(assigneeInfo.getUserId()); |
| | | task.setAssigneeName(assigneeInfo.getUserName()); |
| | | } |
| | | // 用于跟踪是否需要重新同步(车辆、人员、地址、成交价变更) |
| | | boolean needResync = false; |
| | | int result = sysTaskMapper.updateSysTask(task); |
| | |
| | | if(updateVO.getActualEndTime() != null) { |
| | | task.setActualEndTime(updateVO.getActualEndTime()); |
| | | } |
| | | task.setAssigneeId(updateVO.getAssigneeId()); |
| | | // task.setAssigneeId(updateVO.getAssigneeId()); |
| | | task.setUpdateBy(userName); |
| | | task.setUpdateTime(DateUtils.getNowDate()); |
| | | task.setRemark(updateVO.getRemark()); |
| | |
| | | task.setDepartureLatitude(updateVO.getDepartureLatitude()); |
| | | task.setDestinationLongitude(updateVO.getDestinationLongitude()); |
| | | task.setDestinationLatitude(updateVO.getDestinationLatitude()); |
| | | |
| | | if(updateVO.getAssignees()!=null && !updateVO.getAssignees().isEmpty()){ |
| | | TaskCreateVO.AssigneeInfo assigneeInfo= updateVO.getAssignees().get(0); |
| | | task.setAssigneeId(assigneeInfo.getUserId()); |
| | | task.setAssigneeName(assigneeInfo.getUserName()); |
| | | } |
| | | // 如果更新了部门ID |
| | | if (updateVO.getDeptId() != null) { |
| | | task.setDeptId(updateVO.getDeptId()); |
| | |
| | | WHERE vehicle_id = #{vehicleId} |
| | | AND segment_start_time <= #{endDate} |
| | | AND segment_end_time >= #{startDate} |
| | | AND segment_start_time IS NOT NULL |
| | | AND segment_end_time IS NOT NULL |
| | | AND segment_distance >0 |
| | | ORDER BY segment_start_time |
| | | </select> |
| | | |