import http from "./http"; import Vue from "vue"; import CryptoJS from "./crypto-js"; import qs from 'query-string' import dayjs from "./monent"; /** * 用户登录信息和方法 */ export const user = { state: () => ({ token: "", expiredTime: "" }), mutations: { setToken(state, token) { state.token = token }, setExpired(state, time) { state.expiredTime = time }, setUser(state, user) { for (const key in user) { Vue.set(state, key, user[key]) } }, initWaterMarker(state) { const waterMarked = document.querySelector('#waterMarker') if (!waterMarked && state?.name) { const waterMarker = document.createElement('div') waterMarker.id = 'waterMarker' waterMarker.style.position = 'absolute' waterMarker.style.display = 'flex' waterMarker.style.flexWrap = 'wrap' waterMarker.style.overflow = 'hidden' waterMarker.style.justifyContent = 'space-between' waterMarker.style.alignContent = 'flex-start' waterMarker.style.zIndex = '2' waterMarker.style.top = '0' waterMarker.style.color = 'rgba(153,153,153,.2)' waterMarker.style.width = '100%' waterMarker.style.height = '100%' waterMarker.style.pointerEvents = 'none' for (let i = 0; i < 200; i++) { const markerItem = document.createElement('div') markerItem.style.fontSize = '14px' markerItem.style.padding = '30px' markerItem.style.height = '80px' markerItem.style.transform = 'rotate(-20deg)' markerItem.style.flexShrink = '0' markerItem.innerText = state?.name + state?.phone?.slice(-4) || "未授权" waterMarker.appendChild(markerItem) } document.querySelector('uni-page-body')?.appendChild(waterMarker) } // canvas 方案 // const HiDPICanvas = (w, h, ratio) => { // const PIXEL_RATIO = () => { // const c = document.createElement("canvas"), // ctx = c.getContext("2d"), // dpr = window.devicePixelRatio || 1, // bsr = ctx['webkitBackingStorePixelRatio'] || // ctx['mozBackingStorePixelRatio'] || // ctx['msBackingStorePixelRatio'] || // ctx['oBackingStorePixelRatio'] || // ctx['backingStorePixelRatio'] || 1; // // return dpr / bsr; // } // if (!ratio) { // ratio = PIXEL_RATIO(); // } // const can = document.createElement("canvas"); // can.width = w * ratio; // can.height = h * ratio; // can.style.width = w + "px"; // can.style.height = h + "px"; // can.getContext("2d").setTransform(ratio, 0, 0, ratio, 0, 0); // return can // } // if (!waterMarked && state.user?.name) { // const canvas = HiDPICanvas(100, 40) // canvas.style.display = 'none'; // let ctx = canvas.getContext("2d") // ctx.rotate(-20 * Math.PI / 180); // ctx.fillStyle = 'rgba(153,153,153,.3)'; // ctx.textAlign = 'left'; // ctx.textBaseline = 'middle'; // ctx.font = "lighter 7px 'Microsoft YaHei UI',sans-serif" // ctx.fillText(state.user?.name + state.user?.phone?.slice(-4) || "未授权", 0, 30); // const waterMarker = document.createElement('div') // if (waterMarker) { // waterMarker.id = 'waterMarker' // waterMarker.style.position = 'absolute' // waterMarker.style.zIndex = '2' // waterMarker.style.top = '0' // waterMarker.style.width = '100%' // waterMarker.style.height = '100%' // waterMarker.style.pointerEvents = 'none' // waterMarker.style.backgroundImage = "url(" + canvas.toDataURL("image/png") + ")" // document.querySelector('uni-page-body').appendChild(waterMarker) // } // } } }, actions: { getToken({commit, dispatch}, params) { const encryptByDES = password => { let isIos = uni.getSystemInfoSync().system.toUpperCase == 'ios' let key = "thanks,villcloud" let iv = CryptoJS.enc.Latin1.parse(key) let encrypted = CryptoJS.AES.encrypt(password, iv, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.ZeroPadding }) if (isIos) { return encodeURIComponent(encrypted.toString()); } else { return encrypted.toString(); } } let {module, code} = params, action = "/auth/oauth/token" if (!!code) { action = "/auth/wechatcp/token" } return http.post(action, params, { withoutToken: true, module, params: { ...params, grant_type: 'password', password: encryptByDES(params.password) }, headers: { Authorization: "Basic d2VjaGF0OndlY2hhdA==" } }).then(res => { if (res?.access_token) { const token = [res?.token_type, res?.access_token].join(" ").trim() commit("setToken", token) commit("setExpired", dayjs().add(res.expires_in - 600,'s').unix()) return token } else return Promise.reject(res.msg) }) }, getWechatToken({commit, dispatch}, params) { const encryptByDES = password => { let isIos = uni.getSystemInfoSync().system.toUpperCase == 'ios' let key = "thanks,villcloud" let iv = CryptoJS.enc.Latin1.parse(key) let encrypted = CryptoJS.AES.encrypt(password, iv, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.ZeroPadding }) if (isIos) { return encodeURIComponent(encrypted.toString()); } else { return encrypted.toString(); } } let {module} = params, action = "/auth/wechat-mp/token" return http.post(action, params, { withoutToken: true, throttle: 500, module, params: { ...params, grant_type: 'password', password: encryptByDES(params.password) }, headers: { Authorization: "Basic d3htcDp3eG1w" } }).then(res => { if (res?.access_token) { const token = [res?.token_type, res?.access_token].join(" ").trim() commit("setToken", token) return token } else return Promise.reject(res.msg) }) }, getAccount({dispatch, commit}, config) { //获取企业微信后台账号信息 return http.post("/admin/user/detail-phone", null, config).then(res => { if (res?.data) { commit('setUser', res.data) return Promise.all([dispatch('getGridInfo', config)]) } }) }, getGridInfo({commit}, config) { //获取登录着网格员信息 return http.post("/app/appgirdmemberinfo/checkLogOnUser", null, config).then(res => { if (res?.data) { let { girdId, girdMemberId, girdName, checkType: girdCheckType, appGirdInfo: gridInfo, isSign } = res.data, gridExtra = {isSign} return commit("setUser", {girdId, girdMemberId, girdName, girdCheckType, gridInfo, gridExtra}) } }).catch(() => 0) } } } /** * 企微jssdk功能 */ let timer = {} /** * 微信oauth2跳转链接 * https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&agentid=AGENTID#wechat_redirect * @param params */ const oauth2Weixin = params => { const redirect = qs.parseUrl(location.href) delete redirect.query.code delete redirect.query.state return qs.stringifyUrl({ url: "https://open.weixin.qq.com/connect/oauth2/authorize", query: { response_type: 'code', redirect_uri: qs.stringifyUrl(redirect), ...params }, fragmentIdentifier: "wechat_redirect" }) } export const wxwork = { state: () => ({ agentSignURL: "", apiList: [], config: {} }), mutations: { setConfig(state, config) { state.config = config }, setAgentSignURL(state, url) { state.agentSignURL = url }, setApiList(state, list) { state.apiList = list }, }, actions: { agentSign({state, commit}, params = {}) { //授权jssdk在url上使用,并获取corpId let url = window.location.href if (state.agentSignURL == url && state.config.corpId) { return Promise.resolve() } else { commit("setAgentSignURL", url) commit("setApiList", []) let action = "/app/wxcp/portal/agentSign" if (!!params?.action) { action = params.action delete params.action } else if (!!params?.suiteId) { action = "/app/wxcptp/portal/agentSign" } return http.post(action, null, { withoutToken: true, params: {...params, url} }).then(res => { if (res?.data) { let config = { ...params, debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 beta: true,// 必须这么写,否则wx.invoke调用形式的jsapi会有问题 corpId: res.data.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致 agentId: res.data.agentid, // 必填,企业微信的应用id (e.g. 1000247) timestamp: Number(res.data.timestamp), // 必填,生成签名的时间戳 nonceStr: res.data.nonceStr, // 必填,生成签名的随机串 signature: res.data.signature,// 必填,签名,见 附录-JS-SDK使用权限签名算法 ...res.data } commit("setConfig", config) return config } }).catch(err => { console.error(err) }) } }, getCode({state, dispatch}, params) { const excute = (tryAgentSign = false) => { if (!params?.appid) { let {corpid: corpId, suiteId, agentid} = state.config, scope = "snsapi_privateinfo" if (/AppForm/.test(location.pathname)) { scope = "snsapi_base" } else if (suiteId) { corpId = suiteId scope = "snsapi_privateinfo" } params = {appid: corpId, agentid, scope} return new Promise((resolve, reject) => { if (corpId && scope) { const oauthURL = oauth2Weixin(params) location.replace(oauthURL) } else if (!tryAgentSign && corpId) { dispatch("agentSign", {corpId, suiteId}).then(() => excute(true)).then(() => resolve()) } else reject("URL缺少必要参数(corpId)") }) } else new Promise(() => { const oauthURL = oauth2Weixin(params) location.replace(oauthURL) }) } return excute() }, injectJWeixin({state, commit, rootState}, apis) { const inject = (jsApiList) => new Promise((resolve, reject) => { jsApiList = jsApiList || [] if (timer.injectJWeixin) {//节流设置,500ms内的多次请求合并到一处 clearTimeout(timer.injectJWeixin) jsApiList = [...new Set([...state.apiList, ...jsApiList])] commit("setApiList", jsApiList) } timer.injectJWeixin = setTimeout(() => { const sdk = wx?.agentConfig ? wx : jWeixin console.log("agentConfig配置:") console.log({...state.config, jsApiList}) sdk?.agentConfig({ ...state.config, jsApiList, success: res => resolve(res), fail: err => { console.error(err) reject(err) } }) }, 500) }) return inject([apis].flat().filter(Boolean)) }, injectSDK({dispatch, state}, apis) { const {corpId, suiteId} = state.config return dispatch('agentSign', {corpId, suiteId}).then(() => dispatch("injectJWeixin", [apis].flat())) }, previewFile({dispatch}, op) { if (window.navigator.userAgent.indexOf("Windows NT") > -1) { uni.showToast({ title: "企业微信暂不支持PC端的预览文件!", icon: 'none' }) } else { dispatch("injectSDK", "previewFile").then(() => { setTimeout(() => { let sdk = typeof wx?.invoke == 'function' ? wx : jWeixin sdk?.invoke('previewFile', {...op}, res => { console.log(res) }) }, 500) }) } }, closeAgent({dispatch}) { dispatch("injectSDK", "closeWindow").then(() => { setTimeout(() => { let sdk = typeof wx?.closeWindow == 'function' ? wx : jWeixin sdk?.closeWindow() }, 500) }) }, selectEnterpriseContact({dispatch}, params) { return new Promise((resolve, reject) => { dispatch("injectSDK", "selectEnterpriseContact").then(() => { setTimeout(() => { let sdk = typeof wx?.invoke == 'function' ? wx : jWeixin sdk?.invoke("selectEnterpriseContact", { fromDepartmentId: -1, mode: "multi", type: ["user"], ...params }, res => { if (res.err_msg == "selectEnterpriseContact:ok") { if (typeof res.result == 'string') { res.result = JSON.parse(res.result) } resolve(res.result) } else { reject(res) } }) }, 500) }) }) }, selectPrivilegedContact({dispatch}, params) { return new Promise((resolve, reject) => { dispatch("injectSDK", "selectPrivilegedContact").then(() => { setTimeout(() => { let sdk = typeof wx?.invoke == 'function' ? wx : jWeixin sdk?.invoke("selectPrivilegedContact", { fromDepartmentId: -1, mode: "multi", ...params }, res => { if (res.err_msg == "selectPrivilegedContact:ok") { if (typeof res.result == 'string') { res.result = JSON.parse(res.result) } resolve(res.result) } else { reject(res) } }) }, 300) }).catch(() => { reject('error') }) }) }, initOpenData({dispatch, commit, state}, params = {}) { const loadSdk = (count = 0) => { if (!!window?.WWOpenData) { const canvas = params?.canvas if (canvas) delete params.canvas if (timer.initOpenData) { clearTimeout(timer.initOpenData) } const init = () => canvas ? dispatch('initCanvas') : dispatch('bindElements') timer.initOpenData = setTimeout(() => { window?.WWOpenData?.checkSession({ success: () => init(), fail: () => { dispatch("injectSDK", "initWwOpenData").then(() => init()) } }) }, 500) } else if (count > 10) { console.log("无法获取WWOpenData") } else { setTimeout(() => { loadSdk(++count) }, 200) } } dispatch("injectSDK", "initWwOpenData").then(() => loadSdk()) }, bindElements() { const nodes = document.querySelectorAll('.AiOpenData') window.WWOpenData?.bindAll(nodes) }, initCanvas() { window.WWOpenData?.initCanvas() }, transCanvas(store, items) { return new Promise((resolve, reject) => { window.WWOpenData?.prefetch({items}, (err, data) => { err ? reject(err) : resolve(data) }) }) }, shareToExternalChat({dispatch}, params) { return new Promise(resolve => { dispatch("injectSDK", "shareToExternalChat").then(() => window?.wx?.invoke("shareToExternalChat", {...params}, resolve) || console.error("jssdk未成功加载!")) }) } } }