diff --git a/App.vue b/App.vue index 092d1a2..c94eace 100644 --- a/App.vue +++ b/App.vue @@ -58,7 +58,6 @@ export default { this.$u.vuex("vuex_msgList", ""); this.$u.vuex("vuex_user", ""); this.$u.vuex("vuex_token", ""); - this.$u.vuex("vuex_userInfo", ""); uni.clearStorage(); this.$u.route({ url: "/pages/login/login/login", @@ -75,99 +74,6 @@ export default { // console.log('onShow') // }, methods: { - getLocation() { - var that = this; - if (this.isWechat()) { - const isiOS = !!navigator.userAgent.match( - /\(i[^;]+;( U;)? CPU.+Mac OS X/ - ); //ios终端 - // 进行签名的时候 Android 不用使用之前的链接, ios 需要 - const signLink = isiOS - ? window.entryUrl - : window.location.href.split("#")[0]; - //获取当前url然后传递给后台获取授权和签名信息,后台需要解码才能使用 - // const url =encodeURIComponent(signLink); - const url = signLink; - const data = { - url: url, - }; - this.$u.api.GetInfoMation(data).then((res) => { - jweixin.config({ - debug: false, - appId: res.appId, - timestamp: res.timestamp, - nonceStr: res.noncestr, - signature: res.signature, - jsApiList: [ - //这里是需要用到的接口名称 - "getLocation", //获取位置 - "openLocation", //打开位置 - ], - }); - - // jweixin.config 执行失败时调用 - jweixin.error((err) => { - uni.hideLoading(); - console.log("授权失败,您可能无法使用部分功能", err); - }); - jweixin.ready(function () { - jweixin.getLocation({ - type: "gcj02", // 默认为wgs84的gps坐标,如果要返 回直接给openLocation用的火星坐标,可传入'gcj02' - success: (res) => { - uni.hideLoading(); - that.$u.vuex("vuex_userLocation", res); - - var data = { - userId: that.vuex_user.id, - longitude: res.longitude + "", - latitude: res.latitude + "", - }; - that.$u.api.upPosition(data); - }, - fail: function (res) { - uni.hideLoading(); - console.log(res, "err"); - }, - complete: function (res) { - uni.hideLoading(); - console.log(res, "is"); - }, - }); - }); - }); - } else { - uni.getLocation({ - type: "gcj02 ", - isHighAccuracy: true, - highAccuracyExpireTime: 3000, - success: (res) => { - uni.hideLoading(); - - this.$u.vuex("vuex_userLocation", res); - var data = { - userId: this.vuex_user.id, - longitude: res.longitude + "", - latitude: res.latitude + "", - }; - this.$u.api.upPosition(data); - }, - fail: (err) => { - uni.hideLoading(); - console.log("地理位置获取失败", err); - }, - }); - } - }, - isWechat() { - var ua = window.navigator.userAgent.toLowerCase(); - if (ua.match(/micromessenger/i) == "micromessenger") { - // console.log(‘是微信客户端’) - return true; - } else { - // console.log(‘不是微信客户端’) - return false; - } - }, // 构建 WebSocket 连接地址(与 oa-web-phone 保持一致的握手参数) buildWsUrl() { const protocol = diff --git a/store/index.js b/store/index.js index e45d5f0..8300454 100644 --- a/store/index.js +++ b/store/index.js @@ -1,125 +1,286 @@ -import Vue from 'vue' -import Vuex from 'vuex' +import Vue from "vue"; +import Vuex from "vuex"; -Vue.use(Vuex) +Vue.use(Vuex); let lifeData = {}; try { - // 尝试获取本地是否存在lifeData变量,第一次启动APP时是不存在的 - lifeData = uni.getStorageSync('lifeData'); -} catch (e) { - -} + // 尝试获取本地是否存在lifeData变量,第一次启动APP时是不存在的 + lifeData = uni.getStorageSync("lifeData"); +} catch (e) {} // 需要永久存储,且下次APP启动需要取出的,在state中的变量名 -// let saveStateKeys = ['vuex_user', 'vuex_token', 'vuex_msgList', 'vuex_userLocation','vuex_userInfo',]; -let saveStateKeys = ['vuex_user', 'vuex_token', 'vuex_userType']; +let saveStateKeys = ["vuex_user", "vuex_token", "vuex_userType"]; // 保存变量到本地存储中 const saveLifeData = function (key, value) { - // 判断变量名是否在需要存储的数组中 - if (saveStateKeys.indexOf(key) != -1) { - // 获取本地存储的lifeData对象,将变量添加到对象中 - let tmp = uni.getStorageSync('lifeData'); - // 第一次打开APP,不存在lifeData变量,故放一个{}空对象 - tmp = tmp ? tmp : {}; - tmp[key] = value; - // 执行这一步后,所有需要存储的变量,都挂载在本地的lifeData对象中 - uni.setStorageSync('lifeData', tmp); - } -} + // 判断变量名是否在需要存储的数组中 + if (saveStateKeys.indexOf(key) != -1) { + // 获取本地存储的lifeData对象,将变量添加到对象中 + let tmp = uni.getStorageSync("lifeData"); + // 第一次打开APP,不存在lifeData变量,故放一个{}空对象 + tmp = tmp ? tmp : {}; + tmp[key] = value; + // 执行这一步后,所有需要存储的变量,都挂载在本地的lifeData对象中 + uni.setStorageSync("lifeData", tmp); + } +}; const store = new Vuex.Store({ - state: { - vuex_teacherInfo: lifeData.vuex_teacherInfo ? lifeData.vuex_teacherInfo : '', - // 如果上面从本地获取的lifeData对象下有对应的属性,就赋值给state中对应的变量 - // 加上vuex_前缀,是防止变量名冲突,也让人一目了然 - vuex_userType: lifeData.vuex_userType ? lifeData.vuex_userType : 0, // 0:学生 1:教师 - vuex_user: lifeData.vuex_user ? lifeData.vuex_user : '', - vuex_token: lifeData.vuex_token ? lifeData.vuex_token : '', - vuex_userLocation: lifeData.vuex_userLocation ? lifeData.vuex_userLocation : '', - // 如果vuex_version无需保存到本地永久存储,无需lifeData.vuex_version方式 - vuex_version: '1.0.0', - vuex_msgList: lifeData.vuex_msgList ? lifeData.vuex_msgList : '', - // 自定义tabbar数据 - vuex_iPhone: lifeData.vuex_iPhone ? lifeData.vuex_iPhone : false, - // tabbar相关配置 - vuex_tabbar_config: { - activeColor: '#3CB5FB', - inactiveColor: '#666666' - }, - vuex_tabbar: [{ - pagePath: "pages/home/index/index", - iconPath: "/static/common/tabbar/index.png", - selectedIconPath: "/static/common/tabbar/selectindex.png", - text: "首页" - }, - { - pagePath: "pages/message/msgList/msgList", - iconPath: "/static/common/tabbar/message.png", - selectedIconPath: "/static/common/tabbar/selectmessage.png", - // count: 2, //提示数量 - isDot: lifeData.vuex_msgList ? true : false, //显示红色小点 - text: "消息" - }, - // { - // pagePath: "/pages/main/index/index", - // iconPath: "/static/common/tabbar/findFriends.png", - // selectedIconPath: "/static/common/tabbar/selectFindFridend.png", - // text: "找校友" - // }, - // { - // pagePath: "/pages/AlumniCircle/alumnus/alumnus", - // iconPath: "/static/common/tabbar/AlumniCircle.png", - // selectedIconPath: "/static/common/tabbar/selectAlumniCircle.png", - // text: "校友圈" - // }, - - // { - // pagePath: "/pages/my/my/my", - // iconPath: "/static/common/tabbar/my.png", - // selectedIconPath: "/static/common/tabbar/selectmy.png", - // text: "我的" - // } - ], - vuex_education: [], - vuex_schoolName: "", - vuex_userInfo: lifeData.vuex_userInfo ? lifeData.vuex_userInfo :'' + state: { + vuex_teacherInfo: lifeData.vuex_teacherInfo + ? lifeData.vuex_teacherInfo + : "", + // 如果上面从本地获取的lifeData对象下有对应的属性,就赋值给state中对应的变量 + // 加上vuex_前缀,是防止变量名冲突,也让人一目了然 + vuex_userType: lifeData.vuex_userType ? lifeData.vuex_userType : 0, // 0:学生 1:教师 + vuex_user: lifeData.vuex_user ? lifeData.vuex_user : "", + vuex_token: lifeData.vuex_token ? lifeData.vuex_token : "", + // 如果vuex_version无需保存到本地永久存储,无需lifeData.vuex_version方式 + vuex_version: "1.0.0", + // 当前聊天窗口消息列表(数组 + vuex_msgList: [], + // 最近联系人/会话列表 + vuex_userMsgList: [], + // 本地占位的聊天用户(未在服务端建立的会话,临时展示) + vuex_localMsgUserList: [], + // 当前聊天用户对象 + vuex_msgUser: null, + // 消息窗口滚动位置 + vuex_msgScrollTop: 0, + // 自定义tabbar数据 + vuex_iPhone: lifeData.vuex_iPhone ? lifeData.vuex_iPhone : false, + // tabbar相关配置 + vuex_tabbar_config: { + activeColor: "#3CB5FB", + inactiveColor: "#666666", }, - mutations: { - $uStore(state, payload) { - // 判断是否多层级调用,state中为对象存在的情况,诸如user.info.score = 1 - let nameArr = payload.name.split('.'); - let saveKey = ''; - let len = nameArr.length; - if (len >= 2) { - let obj = state[nameArr[0]]; - for (let i = 1; i < len - 1; i++) { - obj = obj[nameArr[i]]; - } - obj[nameArr[len - 1]] = payload.value; - saveKey = nameArr[0]; - } else { - // 单层级变量,在state就是一个普通变量的情况 - state[payload.name] = payload.value; - saveKey = payload.name; - } - // 保存变量到本地,见顶部函数定义 - saveLifeData(saveKey, state[saveKey]) - }, - // 统一登出清理:清除 token 与用户数据,并同步到本地存储 - // 注意:仅清理与登录态相关的关键字段,避免影响其他持久化数据 - logout(state) { - // 清除登录令牌 - state.vuex_token = ''; - state.vuex_teacherInfo = ''; - state.vuex_user = ''; - // 同步更新本地持久化 - saveLifeData('vuex_token', state.vuex_token); - saveLifeData('vuex_teacherInfo', state.vuex_teacherInfo); - saveLifeData('vuex_user', state.vuex_user); - } - } -}) + vuex_tabbar: [ + { + pagePath: "pages/home/index/index", + iconPath: "/static/common/tabbar/index.png", + selectedIconPath: "/static/common/tabbar/selectindex.png", + text: "首页", + }, + { + pagePath: "pages/message/msgList/msgList", + iconPath: "/static/common/tabbar/message.png", + selectedIconPath: "/static/common/tabbar/selectmessage.png", + // count: 2, //提示数量 + // 初始化红点:基于未读计数 + isDot: lifeData.vuex_msgList ? true : false, // 显示红色小点 + text: "消息", + }, + // { + // pagePath: "/pages/main/index/index", + // iconPath: "/static/common/tabbar/findFriends.png", + // selectedIconPath: "/static/common/tabbar/selectFindFridend.png", + // text: "找校友" + // }, + // { + // pagePath: "/pages/AlumniCircle/alumnus/alumnus", + // iconPath: "/static/common/tabbar/AlumniCircle.png", + // selectedIconPath: "/static/common/tabbar/selectAlumniCircle.png", + // text: "校友圈" + // }, -export default store + // { + // pagePath: "/pages/my/my/my", + // iconPath: "/static/common/tabbar/my.png", + // selectedIconPath: "/static/common/tabbar/selectmy.png", + // text: "我的" + // } + ], + vuex_education: [], + vuex_schoolName: "", + }, + mutations: { + $uStore(state, payload) { + // 判断是否多层级调用,state中为对象存在的情况,诸如user.info.score = 1 + let nameArr = payload.name.split("."); + let saveKey = ""; + let len = nameArr.length; + if (len >= 2) { + let obj = state[nameArr[0]]; + for (let i = 1; i < len - 1; i++) { + obj = obj[nameArr[i]]; + } + obj[nameArr[len - 1]] = payload.value; + saveKey = nameArr[0]; + } else { + // 单层级变量,在state就是一个普通变量的情况 + state[payload.name] = payload.value; + saveKey = payload.name; + } + // 保存变量到本地,见顶部函数定义 + saveLifeData(saveKey, state[saveKey]); + }, + + // ===== 消息中心:列表、当前聊天、消息推送等 ===== + // 设置会话列表(服务端返回) + setUserMsgList(state, list) { + state.vuex_userMsgList = Array.isArray(list) ? list.slice() : []; + if (state.vuex_msgUser && state.vuex_msgUser.friendId) { + state.vuex_userMsgList = state.vuex_userMsgList.map((item) => { + if (item && item.friendId === state.vuex_msgUser.friendId) { + return { ...item, unReadCount: 0 }; + } + return item; + }); + } + }, + // 插入一个本地占位的聊天用户 + addLocalMsgUser(state, user) { + const existsLocal = (state.vuex_localMsgUserList || []).some( + (v) => v && v.friendId === user.friendId + ); + const existsServer = (state.vuex_userMsgList || []).some( + (v) => v && v.friendId === user.friendId + ); + if (existsLocal || existsServer) return; + state.vuex_localMsgUserList.unshift({ + avatar: user.avatar, + chatType: user.chatType || 0, + friendName: user.friendName, + userId: "", + friendId: user.friendId, + sendDate: "", + message: "", + userCount: user.userCount || 2, + groupChatType: user.groupChatType || 1, + messageType: user.messageType || 5, + unReadCount: 0, + isTop: !!user.isTop, + // isNoDisturbance: !!user.isNoDisturbance, + // isNotMember: !!user.isNotMember, + }); + }, + // 设置当前聊天用户 + setMsgUser(state, user) { + state.vuex_msgUser = user || null; + if (state.vuex_msgUser && state.vuex_msgUser.friendId) { + state.vuex_userMsgList = (state.vuex_userMsgList || []).map((item) => { + if (item && item.friendId === state.vuex_msgUser.friendId) { + return { ...item, unReadCount: 0 }; + } + return item; + }); + } + }, + // 推送一条新消息(去重) + pushMsg(state, msg) { + if (!msg || !msg.id) return; + const exists = (state.vuex_msgList || []).some( + (item) => item && item.id === msg.id + ); + if (!exists) { + state.vuex_msgList.push(msg); + } + }, + // 插入历史消息到头部 + unshiftMsg(state, msg) { + if (!msg) return; + state.vuex_msgList.unshift(msg); + }, + // 更新置顶状态(本地) + updateTopState(state, { friendId, isTop }) { + state.vuex_userMsgList = (state.vuex_userMsgList || []).map((item) => { + if (item && item.friendId === friendId) { + return { ...item, isTop: !!isTop }; + } + return item; + }); + }, + // 更新消息窗口滚动位置 + setMsgScrollTop(state, top) { + state.vuex_msgScrollTop = Number(top) || 0; + }, + // 清空消息相关状态(登出/切换账号) + clearMessageState(state) { + state.vuex_msgList = []; + state.vuex_userMsgList = []; + state.vuex_localMsgUserList = []; + state.vuex_msgUser = null; + state.vuex_msgScrollTop = 0; + }, + // 统一登出清理:清除 token 与用户数据,并同步到本地存储 + // 注意:仅清理与登录态相关的关键字段,避免影响其他持久化数据 + logout(state) { + // 清除登录令牌 + state.vuex_token = ""; + state.vuex_teacherInfo = ""; + state.vuex_user = ""; + // 清理消息相关状态 + state.vuex_msgList = []; + state.vuex_userMsgList = []; + state.vuex_localMsgUserList = []; + state.vuex_msgUser = null; + state.vuex_msgScrollTop = 0; + // 同步更新本地持久化 + saveLifeData("vuex_token", state.vuex_token); + saveLifeData("vuex_teacherInfo", state.vuex_teacherInfo); + saveLifeData("vuex_user", state.vuex_user); + }, + }, + actions: { + // 获取聊天列表(最近联系人) + async getUserlist({ commit, state }) { + this.$u.api.GetDialogueListApi().then((res) => { + const baseUrl = + (Vue.prototype.$u && + Vue.prototype.$u.http && + Vue.prototype.$u.http.config && + Vue.prototype.$u.http.config.baseUrl) || + ""; + const list = (res && res.data ? res.data : []).map((item) => { + const unReadCount = + state.vuex_msgUser && state.vuex_msgUser.friendId === item.friendId + ? 0 + : item.unReadCount || 0; + return { + ...item, + avatar: baseUrl ? baseUrl + item.avatar : item.avatar, + unReadCount, + }; + }); + commit("setUserMsgList", list); + }); + }, + // 设置当前聊天用户并入队本地占位 + setMsgUser({ commit, dispatch }, user) { + commit("setMsgUser", user); + commit("addLocalMsgUser", user); + // 刷新列表,清零未读 + dispatch("getUserlist"); + }, + // 获取聊天记录(私聊) + async fetchChatRecord( + { commit, state }, + { userId, friendId, chatType = 0, PageIndex = 1, PageSize = 20 } + ) { + const params = { userId, friendId, PageIndex, PageSize }; + + this.$u.api.GetChatHistoryDataApi(params).then((res) => { + const list = res && res.data ? res.data : []; + // 将最新消息插入到消息列表尾部(或头部) + list.forEach((msg) => commit("pushMsg", msg)); + }); + }, + // 设置消息置顶(服务端 + 本地) + async setTopMsgUser({ commit, dispatch }, user) { + if (!user || !user.friendId) return; + if (user.isTop) { + return; + } else { + this.$u.api + .OverheadOneDialogueApi({ dialogueManagementId: user.friendId }) + .then((res) => { + commit("updateTopState", { friendId: user.friendId, isTop: true }); + dispatch("getUserlist"); + }); + } + }, + }, +}); + +export default store;