51 changed files with 4741 additions and 4730 deletions
@ -1,429 +1,430 @@ |
|||||
<script> |
<script> |
||||
import App from './App' |
import App from './App' |
||||
import http from './common/request'; |
import http from './common/request'; |
||||
import * as msgType from './common/messageType'; |
import * as msgType from './common/messageType'; |
||||
import * as enums from './common/enums'; |
import * as enums from './common/enums'; |
||||
import * as wsApi from './common/wssocket'; |
import * as wsApi from './common/wssocket'; |
||||
import UNI_APP from '@/.env.js' |
import UNI_APP from '@/.env.js' |
||||
|
|
||||
export default { |
export default { |
||||
data() { |
data() { |
||||
return { |
return { |
||||
isExit: false, // 是否已退出 |
isExit: false, // 是否已退出 |
||||
audioTip: null, |
audioTip: null, |
||||
reconnecting: false // 正在重连标志 |
reconnecting: false // 正在重连标志 |
||||
} |
} |
||||
|
}, |
||||
|
methods: { |
||||
|
init() { |
||||
|
this.isExit = false; |
||||
|
// 加载数据 |
||||
|
this.loadStore().then(() => { |
||||
|
// 初始化websocket |
||||
|
this.initWebSocket(); |
||||
|
}).catch((e) => { |
||||
|
console.log(e); |
||||
|
this.exit(); |
||||
|
}) |
||||
}, |
}, |
||||
methods: { |
initWebSocket() { |
||||
init() { |
let loginInfo = uni.getStorageSync("loginInfo") |
||||
this.isExit = false; |
wsApi.init(); |
||||
// 加载数据 |
wsApi.connect(UNI_APP.WS_URL, loginInfo.accessToken); |
||||
this.loadStore().then(() => { |
wsApi.onConnect(() => { |
||||
// 初始化websocket |
// 重连成功提示 |
||||
this.initWebSocket(); |
if (this.reconnecting) { |
||||
}).catch((e) => { |
this.reconnecting = false; |
||||
console.log(e); |
uni.showToast({ |
||||
this.exit(); |
title: "已重新连接", |
||||
}) |
icon: 'none' |
||||
}, |
|
||||
initWebSocket() { |
|
||||
let loginInfo = uni.getStorageSync("loginInfo") |
|
||||
wsApi.init(); |
|
||||
wsApi.connect(UNI_APP.WS_URL, loginInfo.accessToken); |
|
||||
wsApi.onConnect(() => { |
|
||||
// 重连成功提示 |
|
||||
if (this.reconnecting) { |
|
||||
this.reconnecting = false; |
|
||||
uni.showToast({ |
|
||||
title: "已重新连接", |
|
||||
icon: 'none' |
|
||||
}) |
|
||||
} |
|
||||
// 加载离线消息 |
|
||||
this.pullPrivateOfflineMessage(this.chatStore.privateMsgMaxId); |
|
||||
this.pullGroupOfflineMessage(this.chatStore.groupMsgMaxId); |
|
||||
}); |
|
||||
wsApi.onMessage((cmd, msgInfo) => { |
|
||||
if (cmd == 2) { |
|
||||
// 异地登录,强制下线 |
|
||||
uni.showModal({ |
|
||||
content: '您已在其他地方登陆,将被强制下线', |
|
||||
showCancel: false, |
|
||||
}) |
|
||||
this.exit(); |
|
||||
} else if (cmd == 3) { |
|
||||
// 私聊消息 |
|
||||
this.handlePrivateMessage(msgInfo); |
|
||||
} else if (cmd == 4) { |
|
||||
// 群聊消息 |
|
||||
this.handleGroupMessage(msgInfo); |
|
||||
} else if (cmd == 5) { |
|
||||
// 系统消息 |
|
||||
this.handleSystemMessage(msgInfo); |
|
||||
} |
|
||||
}); |
|
||||
wsApi.onClose((res) => { |
|
||||
console.log("ws断开", res); |
|
||||
// 重新连接 |
|
||||
this.reconnectWs(); |
|
||||
|
|
||||
}) |
|
||||
}, |
|
||||
loadStore() { |
|
||||
return this.userStore.loadUser().then(() => { |
|
||||
const promises = []; |
|
||||
promises.push(this.friendStore.loadFriend()); |
|
||||
promises.push(this.groupStore.loadGroup()); |
|
||||
promises.push(this.chatStore.loadChat()); |
|
||||
promises.push(this.configStore.loadConfig()); |
|
||||
return Promise.all(promises); |
|
||||
}) |
|
||||
}, |
|
||||
unloadStore(){ |
|
||||
this.friendStore.clear(); |
|
||||
this.groupStore.clear(); |
|
||||
this.chatStore.clear(); |
|
||||
this.configStore.clear(); |
|
||||
this.userStore.clear(); |
|
||||
}, |
|
||||
pullPrivateOfflineMessage(minId) { |
|
||||
this.chatStore.setLoadingPrivateMsg(true) |
|
||||
http({ |
|
||||
url: "/message/private/pullOfflineMessage?minId=" + minId, |
|
||||
method: 'GET' |
|
||||
}).catch(() => { |
|
||||
this.chatStore.setLoadingPrivateMsg(false) |
|
||||
}) |
|
||||
}, |
|
||||
pullGroupOfflineMessage(minId) { |
|
||||
this.chatStore.setLoadingGroupMsg(true) |
|
||||
http({ |
|
||||
url: "/message/group/pullOfflineMessage?minId=" + minId, |
|
||||
method: 'GET' |
|
||||
}).catch(() => { |
|
||||
this.chatStore.setLoadingGroupMsg(false) |
|
||||
}) |
|
||||
}, |
|
||||
handlePrivateMessage(msg) { |
|
||||
// 消息加载标志 |
|
||||
if (msg.type == enums.MESSAGE_TYPE.LOADING) { |
|
||||
this.chatStore.setLoadingPrivateMsg(JSON.parse(msg.content)) |
|
||||
return; |
|
||||
} |
|
||||
// 消息已读处理,清空已读数量 |
|
||||
if (msg.type == enums.MESSAGE_TYPE.READED) { |
|
||||
this.chatStore.resetUnreadCount({ |
|
||||
type: 'PRIVATE', |
|
||||
targetId: msg.recvId |
|
||||
}) |
|
||||
return; |
|
||||
} |
|
||||
// 消息回执处理,改消息状态为已读 |
|
||||
if (msg.type == enums.MESSAGE_TYPE.RECEIPT) { |
|
||||
this.chatStore.readedMessage({ |
|
||||
friendId: msg.sendId |
|
||||
}) |
}) |
||||
return; |
|
||||
} |
|
||||
// 标记这条消息是不是自己发的 |
|
||||
msg.selfSend = msg.sendId == this.userStore.userInfo.id; |
|
||||
// 好友id |
|
||||
let friendId = msg.selfSend ? msg.recvId : msg.sendId; |
|
||||
this.loadFriendInfo(friendId, (friend) => { |
|
||||
this.insertPrivateMessage(friend, msg); |
|
||||
}) |
|
||||
}, |
|
||||
insertPrivateMessage(friend, msg) { |
|
||||
// 单人视频信令 |
|
||||
if (msgType.isRtcPrivate(msg.type)) { |
|
||||
// #ifdef MP-WEIXIN |
|
||||
// 小程序不支持音视频 |
|
||||
return; |
|
||||
// #endif |
|
||||
// 被呼叫,弹出视频页面 |
|
||||
let delayTime = 100; |
|
||||
if (msg.type == enums.MESSAGE_TYPE.RTC_CALL_VOICE || |
|
||||
msg.type == enums.MESSAGE_TYPE.RTC_CALL_VIDEO) { |
|
||||
let mode = msg.type == enums.MESSAGE_TYPE.RTC_CALL_VIDEO ? "video" : "voice"; |
|
||||
let pages = getCurrentPages(); |
|
||||
let curPage = pages[pages.length - 1].route; |
|
||||
if (curPage != "pages/chat/chat-private-video") { |
|
||||
const friendInfo = encodeURIComponent(JSON.stringify(friend)); |
|
||||
uni.navigateTo({ |
|
||||
url: `/pages/chat/chat-private-video?mode=${mode}&friend=${friendInfo}&isHost=false` |
|
||||
}) |
|
||||
delayTime = 500; |
|
||||
} |
|
||||
} |
|
||||
setTimeout(() => { |
|
||||
uni.$emit('WS_RTC_PRIVATE', msg); |
|
||||
}, delayTime) |
|
||||
return; |
|
||||
} |
} |
||||
let chatInfo = { |
// 加载离线消息 |
||||
type: 'PRIVATE', |
this.pullPrivateOfflineMessage(this.chatStore.privateMsgMaxId); |
||||
targetId: friend.id, |
this.pullGroupOfflineMessage(this.chatStore.groupMsgMaxId); |
||||
showName: friend.nickName, |
}); |
||||
headImage: friend.headImage |
wsApi.onMessage((cmd, msgInfo) => { |
||||
}; |
if (cmd == 2) { |
||||
// 打开会话 |
// 异地登录,强制下线 |
||||
this.chatStore.openChat(chatInfo); |
|
||||
// 插入消息 |
|
||||
this.chatStore.insertMessage(msg); |
|
||||
// 播放提示音 |
|
||||
this.playAudioTip(); |
|
||||
|
|
||||
}, |
|
||||
handleGroupMessage(msg) { |
|
||||
// 消息加载标志 |
|
||||
if (msg.type == enums.MESSAGE_TYPE.LOADING) { |
|
||||
this.chatStore.setLoadingGroupMsg(JSON.parse(msg.content)) |
|
||||
return; |
|
||||
} |
|
||||
// 消息已读处理 |
|
||||
if (msg.type == enums.MESSAGE_TYPE.READED) { |
|
||||
// 我已读对方的消息,清空已读数量 |
|
||||
let chatInfo = { |
|
||||
type: 'GROUP', |
|
||||
targetId: msg.groupId |
|
||||
} |
|
||||
this.chatStore.resetUnreadCount(chatInfo) |
|
||||
return; |
|
||||
} |
|
||||
// 消息回执处理 |
|
||||
if (msg.type == enums.MESSAGE_TYPE.RECEIPT) { |
|
||||
// 更新消息已读人数 |
|
||||
let msgInfo = { |
|
||||
id: msg.id, |
|
||||
groupId: msg.groupId, |
|
||||
readedCount: msg.readedCount, |
|
||||
receiptOk: msg.receiptOk |
|
||||
}; |
|
||||
this.chatStore.updateMessage(msgInfo) |
|
||||
return; |
|
||||
} |
|
||||
// 标记这条消息是不是自己发的 |
|
||||
msg.selfSend = msg.sendId == this.userStore.userInfo.id; |
|
||||
this.loadGroupInfo(msg.groupId, (group) => { |
|
||||
// 插入群聊消息 |
|
||||
this.insertGroupMessage(group, msg); |
|
||||
}) |
|
||||
}, |
|
||||
handleSystemMessage(msg) { |
|
||||
if (msg.type == enums.MESSAGE_TYPE.USER_BANNED) { |
|
||||
// 用户被封禁 |
|
||||
wsApi.close(3099); |
|
||||
uni.showModal({ |
uni.showModal({ |
||||
content: '您的账号已被管理员封禁,原因:' + msg.content, |
content: '您已在其他地方登陆,将被强制下线', |
||||
showCancel: false, |
showCancel: false, |
||||
}) |
}) |
||||
this.exit(); |
this.exit(); |
||||
|
} else if (cmd == 3) { |
||||
|
// 私聊消息 |
||||
|
this.handlePrivateMessage(msgInfo); |
||||
|
} else if (cmd == 4) { |
||||
|
// 群聊消息 |
||||
|
this.handleGroupMessage(msgInfo); |
||||
|
} else if (cmd == 5) { |
||||
|
// 系统消息 |
||||
|
this.handleSystemMessage(msgInfo); |
||||
} |
} |
||||
}, |
}); |
||||
insertGroupMessage(group, msg) { |
wsApi.onClose((res) => { |
||||
// 群视频信令 |
console.log("ws断开", res); |
||||
if (msgType.isRtcGroup(msg.type)) { |
// 重新连接 |
||||
// #ifdef MP-WEIXIN |
this.reconnectWs(); |
||||
// 小程序不支持音视频 |
|
||||
return; |
}) |
||||
// #endif |
}, |
||||
// 被呼叫,弹出视频页面 |
loadStore() { |
||||
let delayTime = 100; |
return this.userStore.loadUser().then(() => { |
||||
if (msg.type == enums.MESSAGE_TYPE.RTC_GROUP_SETUP) { |
const promises = []; |
||||
let pages = getCurrentPages(); |
promises.push(this.friendStore.loadFriend()); |
||||
let curPage = pages[pages.length - 1].route; |
promises.push(this.groupStore.loadGroup()); |
||||
if (curPage != "pages/chat/chat-group-video") { |
promises.push(this.chatStore.loadChat()); |
||||
const userInfos = encodeURIComponent(msg.content); |
promises.push(this.configStore.loadConfig()); |
||||
const inviterId = msg.sendId; |
return Promise.all(promises); |
||||
const groupId = msg.groupId |
}) |
||||
uni.navigateTo({ |
}, |
||||
url: `/pages/chat/chat-group-video?groupId=${groupId}&isHost=false |
unloadStore() { |
||||
&inviterId=${inviterId}&userInfos=${userInfos}` |
this.friendStore.clear(); |
||||
}) |
this.groupStore.clear(); |
||||
delayTime = 500; |
this.chatStore.clear(); |
||||
} |
this.configStore.clear(); |
||||
|
this.userStore.clear(); |
||||
|
}, |
||||
|
pullPrivateOfflineMessage(minId) { |
||||
|
this.chatStore.setLoadingPrivateMsg(true) |
||||
|
http({ |
||||
|
url: "/message/private/pullOfflineMessage?minId=" + minId, |
||||
|
method: 'GET' |
||||
|
}).catch(() => { |
||||
|
this.chatStore.setLoadingPrivateMsg(false) |
||||
|
}) |
||||
|
}, |
||||
|
pullGroupOfflineMessage(minId) { |
||||
|
this.chatStore.setLoadingGroupMsg(true) |
||||
|
http({ |
||||
|
url: "/message/group/pullOfflineMessage?minId=" + minId, |
||||
|
method: 'GET' |
||||
|
}).catch(() => { |
||||
|
this.chatStore.setLoadingGroupMsg(false) |
||||
|
}) |
||||
|
}, |
||||
|
handlePrivateMessage(msg) { |
||||
|
// 消息加载标志 |
||||
|
if (msg.type == enums.MESSAGE_TYPE.LOADING) { |
||||
|
this.chatStore.setLoadingPrivateMsg(JSON.parse(msg.content)) |
||||
|
return; |
||||
|
} |
||||
|
// 消息已读处理,清空已读数量 |
||||
|
if (msg.type == enums.MESSAGE_TYPE.READED) { |
||||
|
this.chatStore.resetUnreadCount({ |
||||
|
type: 'PRIVATE', |
||||
|
targetId: msg.recvId |
||||
|
}) |
||||
|
return; |
||||
|
} |
||||
|
// 消息回执处理,改消息状态为已读 |
||||
|
if (msg.type == enums.MESSAGE_TYPE.RECEIPT) { |
||||
|
this.chatStore.readedMessage({ |
||||
|
friendId: msg.sendId |
||||
|
}) |
||||
|
return; |
||||
|
} |
||||
|
// 标记这条消息是不是自己发的 |
||||
|
msg.selfSend = msg.sendId == this.userStore.userInfo.id; |
||||
|
// 好友id |
||||
|
let friendId = msg.selfSend ? msg.recvId : msg.sendId; |
||||
|
this.loadFriendInfo(friendId, (friend) => { |
||||
|
this.insertPrivateMessage(friend, msg); |
||||
|
}) |
||||
|
}, |
||||
|
insertPrivateMessage(friend, msg) { |
||||
|
// 单人视频信令 |
||||
|
if (msgType.isRtcPrivate(msg.type)) { |
||||
|
// #ifdef MP-WEIXIN |
||||
|
// 小程序不支持音视频 |
||||
|
return; |
||||
|
// #endif |
||||
|
// 被呼叫,弹出视频页面 |
||||
|
let delayTime = 100; |
||||
|
if (msg.type == enums.MESSAGE_TYPE.RTC_CALL_VOICE || |
||||
|
msg.type == enums.MESSAGE_TYPE.RTC_CALL_VIDEO) { |
||||
|
let mode = msg.type == enums.MESSAGE_TYPE.RTC_CALL_VIDEO ? "video" : "voice"; |
||||
|
let pages = getCurrentPages(); |
||||
|
let curPage = pages[pages.length - 1].route; |
||||
|
if (curPage != "pages/chat/chat-private-video") { |
||||
|
const friendInfo = encodeURIComponent(JSON.stringify(friend)); |
||||
|
uni.navigateTo({ |
||||
|
url: `/pages/chat/chat-private-video?mode=${mode}&friend=${friendInfo}&isHost=false` |
||||
|
}) |
||||
|
delayTime = 500; |
||||
} |
} |
||||
// 消息转发到chat-group-video页面进行处理 |
|
||||
setTimeout(() => { |
|
||||
uni.$emit('WS_RTC_GROUP', msg); |
|
||||
}, delayTime) |
|
||||
return; |
|
||||
} |
} |
||||
|
setTimeout(() => { |
||||
|
uni.$emit('WS_RTC_PRIVATE', msg); |
||||
|
}, delayTime) |
||||
|
return; |
||||
|
} |
||||
|
let chatInfo = { |
||||
|
type: 'PRIVATE', |
||||
|
targetId: friend.id, |
||||
|
showName: friend.nickName, |
||||
|
headImage: friend.headImage |
||||
|
}; |
||||
|
// 打开会话 |
||||
|
this.chatStore.openChat(chatInfo); |
||||
|
// 插入消息 |
||||
|
this.chatStore.insertMessage(msg); |
||||
|
// 播放提示音 |
||||
|
this.playAudioTip(); |
||||
|
|
||||
|
}, |
||||
|
handleGroupMessage(msg) { |
||||
|
// 消息加载标志 |
||||
|
if (msg.type == enums.MESSAGE_TYPE.LOADING) { |
||||
|
this.chatStore.setLoadingGroupMsg(JSON.parse(msg.content)) |
||||
|
return; |
||||
|
} |
||||
|
// 消息已读处理 |
||||
|
if (msg.type == enums.MESSAGE_TYPE.READED) { |
||||
|
// 我已读对方的消息,清空已读数量 |
||||
let chatInfo = { |
let chatInfo = { |
||||
type: 'GROUP', |
type: 'GROUP', |
||||
targetId: group.id, |
targetId: msg.groupId |
||||
showName: group.showGroupName, |
|
||||
headImage: group.headImageThumb |
|
||||
}; |
|
||||
// 打开会话 |
|
||||
this.chatStore.openChat(chatInfo); |
|
||||
// 插入消息 |
|
||||
this.chatStore.insertMessage(msg); |
|
||||
// 播放提示音 |
|
||||
this.playAudioTip(); |
|
||||
}, |
|
||||
loadFriendInfo(id, callback) { |
|
||||
let friend = this.friendStore.findFriend(id); |
|
||||
if (friend) { |
|
||||
callback(friend); |
|
||||
} else { |
|
||||
http({ |
|
||||
url: `/friend/find/${id}`, |
|
||||
method: 'GET' |
|
||||
}).then((friend) => { |
|
||||
this.friendStore.addFriend(friend); |
|
||||
callback(friend) |
|
||||
}) |
|
||||
} |
|
||||
}, |
|
||||
loadGroupInfo(id, callback) { |
|
||||
let group = this.groupStore.findGroup(id); |
|
||||
if (group) { |
|
||||
callback(group); |
|
||||
} else { |
|
||||
http({ |
|
||||
url: `/group/find/${id}`, |
|
||||
method: 'GET' |
|
||||
}).then((group) => { |
|
||||
this.groupStore.addGroup(group); |
|
||||
callback(group) |
|
||||
}) |
|
||||
} |
} |
||||
}, |
this.chatStore.resetUnreadCount(chatInfo) |
||||
exit() { |
return; |
||||
console.log("exit"); |
} |
||||
this.isExit = true; |
// 消息回执处理 |
||||
|
if (msg.type == enums.MESSAGE_TYPE.RECEIPT) { |
||||
|
// 更新消息已读人数 |
||||
|
let msgInfo = { |
||||
|
id: msg.id, |
||||
|
groupId: msg.groupId, |
||||
|
readedCount: msg.readedCount, |
||||
|
receiptOk: msg.receiptOk |
||||
|
}; |
||||
|
this.chatStore.updateMessage(msgInfo) |
||||
|
return; |
||||
|
} |
||||
|
// 标记这条消息是不是自己发的 |
||||
|
msg.selfSend = msg.sendId == this.userStore.userInfo.id; |
||||
|
this.loadGroupInfo(msg.groupId, (group) => { |
||||
|
// 插入群聊消息 |
||||
|
this.insertGroupMessage(group, msg); |
||||
|
}) |
||||
|
}, |
||||
|
handleSystemMessage(msg) { |
||||
|
if (msg.type == enums.MESSAGE_TYPE.USER_BANNED) { |
||||
|
// 用户被封禁 |
||||
wsApi.close(3099); |
wsApi.close(3099); |
||||
uni.removeStorageSync("loginInfo"); |
uni.showModal({ |
||||
uni.reLaunch({ |
content: '您的账号已被管理员封禁,原因:' + msg.content, |
||||
url: "/pages/login/login" |
showCancel: false, |
||||
}) |
}) |
||||
this.unloadStore(); |
this.exit(); |
||||
}, |
} |
||||
playAudioTip() { |
}, |
||||
// 音频播放无法成功 |
insertGroupMessage(group, msg) { |
||||
// this.audioTip = uni.createInnerAudioContext(); |
// 群视频信令 |
||||
// this.audioTip.src = "/static/audio/tip.wav"; |
if (msgType.isRtcGroup(msg.type)) { |
||||
// this.audioTip.play(); |
// #ifdef MP-WEIXIN |
||||
}, |
// 小程序不支持音视频 |
||||
refreshToken(loginInfo) { |
return; |
||||
return new Promise((resolve, reject) => { |
// #endif |
||||
if (!loginInfo || !loginInfo.refreshToken) { |
// 被呼叫,弹出视频页面 |
||||
reject(); |
let delayTime = 100; |
||||
return; |
if (msg.type == enums.MESSAGE_TYPE.RTC_GROUP_SETUP) { |
||||
|
let pages = getCurrentPages(); |
||||
|
let curPage = pages[pages.length - 1].route; |
||||
|
if (curPage != "pages/chat/chat-group-video") { |
||||
|
const userInfos = encodeURIComponent(msg.content); |
||||
|
const inviterId = msg.sendId; |
||||
|
const groupId = msg.groupId |
||||
|
uni.navigateTo({ |
||||
|
url: `/pages/chat/chat-group-video?groupId=${groupId}&isHost=false |
||||
|
&inviterId=${inviterId}&userInfos=${userInfos}` |
||||
|
}) |
||||
|
delayTime = 500; |
||||
} |
} |
||||
http({ |
|
||||
url: '/refreshToken', |
|
||||
method: 'PUT', |
|
||||
header: { |
|
||||
refreshToken: loginInfo.refreshToken |
|
||||
} |
|
||||
}).then((newLoginInfo) => { |
|
||||
uni.setStorageSync("loginInfo", newLoginInfo) |
|
||||
resolve() |
|
||||
}).catch((e) => { |
|
||||
reject(e) |
|
||||
}) |
|
||||
}) |
|
||||
}, |
|
||||
reconnectWs() { |
|
||||
// 已退出则不再重连 |
|
||||
if (this.isExit) { |
|
||||
return; |
|
||||
} |
} |
||||
// 记录标志 |
// 消息转发到chat-group-video页面进行处理 |
||||
this.reconnecting = true; |
setTimeout(() => { |
||||
// 重新加载一次个人信息,目的是为了保证网络已经正常且token有效 |
uni.$emit('WS_RTC_GROUP', msg); |
||||
this.reloadUserInfo().then((userInfo) => { |
}, delayTime) |
||||
uni.showToast({ |
return; |
||||
title: '连接已断开,尝试重新连接...', |
} |
||||
icon: 'none', |
|
||||
}) |
let chatInfo = { |
||||
this.userStore.setUserInfo(userInfo); |
type: 'GROUP', |
||||
// 重新连接 |
targetId: group.id, |
||||
let loginInfo = uni.getStorageSync("loginInfo") |
showName: group.showGroupName, |
||||
wsApi.reconnect(UNI_APP.WS_URL, loginInfo.accessToken); |
headImage: group.headImageThumb |
||||
}).catch(() => { |
}; |
||||
// 5s后重试 |
// 打开会话 |
||||
setTimeout(() => { |
this.chatStore.openChat(chatInfo); |
||||
this.reconnectWs(); |
// 插入消息 |
||||
}, 5000) |
this.chatStore.insertMessage(msg); |
||||
|
// 播放提示音 |
||||
|
this.playAudioTip(); |
||||
|
}, |
||||
|
loadFriendInfo(id, callback) { |
||||
|
let friend = this.friendStore.findFriend(id); |
||||
|
if (friend) { |
||||
|
callback(friend); |
||||
|
} else { |
||||
|
http({ |
||||
|
url: `/friend/find/${id}`, |
||||
|
method: 'GET' |
||||
|
}).then((friend) => { |
||||
|
this.friendStore.addFriend(friend); |
||||
|
callback(friend) |
||||
}) |
}) |
||||
}, |
} |
||||
reloadUserInfo() { |
}, |
||||
return http({ |
loadGroupInfo(id, callback) { |
||||
url: '/user/self', |
let group = this.groupStore.findGroup(id); |
||||
|
if (group) { |
||||
|
callback(group); |
||||
|
} else { |
||||
|
http({ |
||||
|
url: `/group/find/${id}`, |
||||
method: 'GET' |
method: 'GET' |
||||
|
}).then((group) => { |
||||
|
this.groupStore.addGroup(group); |
||||
|
callback(group) |
||||
}) |
}) |
||||
} |
} |
||||
}, |
}, |
||||
onLaunch() { |
exit() { |
||||
this.$mountStore(); |
console.log("exit"); |
||||
// 登录状态校验 |
this.isExit = true; |
||||
let loginInfo = uni.getStorageSync("loginInfo") |
wsApi.close(3099); |
||||
this.refreshToken(loginInfo).then(() => { |
uni.removeStorageSync("loginInfo"); |
||||
// 初始化 |
uni.reLaunch({ |
||||
this.init(); |
url: "/pages/login/login" |
||||
// 跳转到聊天页面 |
}) |
||||
uni.switchTab({ |
this.unloadStore(); |
||||
url: "/pages/chat/chat" |
}, |
||||
|
playAudioTip() { |
||||
|
// 音频播放无法成功 |
||||
|
// this.audioTip = uni.createInnerAudioContext(); |
||||
|
// this.audioTip.src = "/static/audio/tip.wav"; |
||||
|
// this.audioTip.play(); |
||||
|
}, |
||||
|
refreshToken(loginInfo) { |
||||
|
return new Promise((resolve, reject) => { |
||||
|
if (!loginInfo || !loginInfo.refreshToken) { |
||||
|
reject(); |
||||
|
return; |
||||
|
} |
||||
|
http({ |
||||
|
url: '/refreshToken', |
||||
|
method: 'PUT', |
||||
|
header: { |
||||
|
refreshToken: loginInfo.refreshToken |
||||
|
} |
||||
|
}).then((newLoginInfo) => { |
||||
|
uni.setStorageSync("loginInfo", newLoginInfo) |
||||
|
resolve() |
||||
|
}).catch((e) => { |
||||
|
reject(e) |
||||
}) |
}) |
||||
}).catch(() => { |
}) |
||||
// 跳转到登录页 |
}, |
||||
// #ifdef H5 |
reconnectWs() { |
||||
uni.navigateTo({ |
// 已退出则不再重连 |
||||
url: "/pages/login/login" |
if (this.isExit) { |
||||
|
return; |
||||
|
} |
||||
|
// 记录标志 |
||||
|
this.reconnecting = true; |
||||
|
// 重新加载一次个人信息,目的是为了保证网络已经正常且token有效 |
||||
|
this.reloadUserInfo().then((userInfo) => { |
||||
|
uni.showToast({ |
||||
|
title: '连接已断开,尝试重新连接...', |
||||
|
icon: 'none', |
||||
}) |
}) |
||||
// #endif |
this.userStore.setUserInfo(userInfo); |
||||
|
// 重新连接 |
||||
|
let loginInfo = uni.getStorageSync("loginInfo") |
||||
|
wsApi.reconnect(UNI_APP.WS_URL, loginInfo.accessToken); |
||||
|
}).catch(() => { |
||||
|
// 5s后重试 |
||||
|
setTimeout(() => { |
||||
|
this.reconnectWs(); |
||||
|
}, 5000) |
||||
|
}) |
||||
|
}, |
||||
|
reloadUserInfo() { |
||||
|
return http({ |
||||
|
url: '/user/self', |
||||
|
method: 'GET' |
||||
}) |
}) |
||||
} |
} |
||||
|
}, |
||||
|
onLaunch() { |
||||
|
this.$mountStore(); |
||||
|
// 登录状态校验 |
||||
|
let loginInfo = uni.getStorageSync("loginInfo") |
||||
|
this.refreshToken(loginInfo).then(() => { |
||||
|
// 初始化 |
||||
|
this.init(); |
||||
|
// 跳转到聊天页面 |
||||
|
uni.switchTab({ |
||||
|
url: "/pages/chat/chat" |
||||
|
}) |
||||
|
}).catch(() => { |
||||
|
// 跳转到登录页 |
||||
|
// #ifdef H5 |
||||
|
uni.navigateTo({ |
||||
|
url: "/pages/login/login" |
||||
|
}) |
||||
|
// #endif |
||||
|
}) |
||||
} |
} |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<style lang="scss"> |
<style lang="scss"> |
||||
@import "@/uni_modules/uview-plus/index.scss"; |
@import "@/uni_modules/uview-plus/index.scss"; |
||||
@import "@/im.scss"; |
@import "@/im.scss"; |
||||
@import url('./static/icon/iconfont.css'); |
@import url('./static/icon/iconfont.css'); |
||||
|
|
||||
// #ifdef H5 |
// #ifdef H5 |
||||
uni-page-head { |
uni-page-head { |
||||
display: none; // h5浏览器本身就有标题 |
display: none; // h5浏览器本身就有标题 |
||||
} |
} |
||||
// #endif |
|
||||
|
|
||||
.tab-page { |
// #endif |
||||
position: relative; |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
// #ifdef H5 |
|
||||
height: calc(100vh - 50px - $im-nav-bar-height); // h5平台100vh是包含了底部高度,需要减去 |
|
||||
top: $im-nav-bar-height; |
|
||||
// #endif |
|
||||
|
|
||||
// #ifndef H5 |
.tab-page { |
||||
height: calc(100vh - var(--status-bar-height) - $im-nav-bar-height); // app平台还要减去顶部手机状态栏高度 |
position: relative; |
||||
top: calc($im-nav-bar-height + var(--status-bar-height)); |
display: flex; |
||||
// #endif |
flex-direction: column; |
||||
color: $im-text-color; |
// #ifdef H5 |
||||
background-color: $im-bg; |
height: calc(100vh - 50px - $im-nav-bar-height); // h5平台100vh是包含了底部高度,需要减去 |
||||
font-size: $im-font-size; |
top: $im-nav-bar-height; |
||||
font-family: $font-family; |
// #endif |
||||
} |
|
||||
|
|
||||
.page { |
// #ifndef H5 |
||||
position: relative; |
height: calc(100vh - var(--status-bar-height) - $im-nav-bar-height); // app平台还要减去顶部手机状态栏高度 |
||||
// #ifdef H5 |
top: calc($im-nav-bar-height + var(--status-bar-height)); |
||||
height: calc(100vh - $im-nav-bar-height); // app平台还要减去顶部手机状态栏高度 |
// #endif |
||||
top: $im-nav-bar-height; |
color: $im-text-color; |
||||
// #endif |
background-color: $im-bg; |
||||
// #ifndef H5 |
font-size: $im-font-size; |
||||
height: calc(100vh - var(--status-bar-height) - $im-nav-bar-height); // app平台还要减去顶部手机状态栏高度 |
font-family: $font-family; |
||||
top: calc($im-nav-bar-height + var(--status-bar-height)); |
} |
||||
// #endif |
|
||||
color: $im-text-color; |
.page { |
||||
background-color: $im-bg; |
position: relative; |
||||
font-size: $im-font-size; |
// #ifdef H5 |
||||
font-family: $font-family; |
height: calc(100vh - $im-nav-bar-height); // app平台还要减去顶部手机状态栏高度 |
||||
} |
top: $im-nav-bar-height; |
||||
|
// #endif |
||||
|
// #ifndef H5 |
||||
|
height: calc(100vh - var(--status-bar-height) - $im-nav-bar-height); // app平台还要减去顶部手机状态栏高度 |
||||
|
top: calc($im-nav-bar-height + var(--status-bar-height)); |
||||
|
// #endif |
||||
|
color: $im-text-color; |
||||
|
background-color: $im-bg; |
||||
|
font-size: $im-font-size; |
||||
|
font-family: $font-family; |
||||
|
} |
||||
</style> |
</style> |
||||
@ -1,39 +1,40 @@ |
|||||
<template> |
<template> |
||||
<view class="arrow-bar"> |
<view class="arrow-bar"> |
||||
<text class="title">{{title}}</text> |
<text class="title">{{ title }}</text> |
||||
<uni-icons class="arrow" type="right" size="16"></uni-icons> |
<uni-icons class="arrow" type="right" size="16"></uni-icons> |
||||
</view> |
</view> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
export default { |
export default { |
||||
name: "arrow-bar", |
name: "arrow-bar", |
||||
props: { |
props: { |
||||
title: { |
title: { |
||||
type: String, |
type: String, |
||||
required: true |
required: true |
||||
} |
} |
||||
}, |
}, |
||||
} |
} |
||||
</script> |
</script> |
||||
|
|
||||
<style lang="scss" scoped> |
<style lang="scss" scoped> |
||||
.arrow-bar { |
.arrow-bar { |
||||
width: 100%; |
width: 100%; |
||||
height: 90rpx; |
height: 90rpx; |
||||
font-size: 30rpx; |
font-size: 30rpx; |
||||
color: black; |
color: black; |
||||
margin-top: 5rpx; |
margin-top: 5rpx; |
||||
background-color: white; |
background-color: white; |
||||
line-height: 90rpx; |
line-height: 90rpx; |
||||
display: flex; |
display: flex; |
||||
.title { |
|
||||
flex: 1; |
.title { |
||||
margin-left: 40rpx; |
flex: 1; |
||||
} |
margin-left: 40rpx; |
||||
|
} |
||||
.arrow { |
|
||||
margin-right: 40rpx; |
.arrow { |
||||
} |
margin-right: 40rpx; |
||||
} |
} |
||||
|
} |
||||
</style> |
</style> |
||||
@ -1,66 +1,68 @@ |
|||||
<template> |
<template> |
||||
<view class="btn-bar" :style="style"> |
<view class="btn-bar" :style="style"> |
||||
<text v-if="icon" class="icon iconfont" :class="icon"></text> |
<text v-if="icon" class="icon iconfont" :class="icon"></text> |
||||
<text class="title">{{title}}</text> |
<text class="title">{{ title }}</text> |
||||
</view> |
</view> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
export default { |
export default { |
||||
name: "btn-bar", |
name: "btn-bar", |
||||
props: { |
props: { |
||||
title: { |
title: { |
||||
type: String, |
type: String, |
||||
required: true |
required: true |
||||
}, |
}, |
||||
icon: { |
icon: { |
||||
type: String, |
type: String, |
||||
required: false |
required: false |
||||
}, |
}, |
||||
type: { |
type: { |
||||
type: String, |
type: String, |
||||
default: "normal" |
default: "normal" |
||||
}, |
|
||||
color: { |
|
||||
type: String, |
|
||||
default: "#000" |
|
||||
} |
|
||||
}, |
}, |
||||
computed: { |
color: { |
||||
style() { |
type: String, |
||||
let color = "#000"; |
default: "#000" |
||||
switch (this.type) { |
} |
||||
case 'danger': |
}, |
||||
color = "#f14747"; |
computed: { |
||||
break; |
style() { |
||||
case 'primary': |
let color = "#000"; |
||||
color = "#35567f"; |
switch (this.type) { |
||||
break; |
case 'danger': |
||||
} |
color = "#f14747"; |
||||
return `color: ${color};` |
break; |
||||
|
case 'primary': |
||||
|
color = "#35567f"; |
||||
|
break; |
||||
} |
} |
||||
|
return `color: ${color};` |
||||
} |
} |
||||
} |
} |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<style lang="scss" scoped> |
<style lang="scss" scoped> |
||||
.btn-bar { |
.btn-bar { |
||||
width: 100%; |
width: 100%; |
||||
height: 100rpx; |
height: 100rpx; |
||||
margin-top: 5rpx; |
margin-top: 5rpx; |
||||
background-color: white; |
background-color: white; |
||||
line-height: 100rpx; |
line-height: 100rpx; |
||||
text-align: center; |
text-align: center; |
||||
display: flex; |
display: flex; |
||||
justify-content: center; |
justify-content: center; |
||||
.icon { |
|
||||
font-size: 40rpx; |
.icon { |
||||
font-weight: 600; |
font-size: 40rpx; |
||||
margin-right: 10rpx; |
font-weight: 600; |
||||
} |
margin-right: 10rpx; |
||||
.title { |
} |
||||
font-size: 32rpx; |
|
||||
font-weight: 600; |
.title { |
||||
} |
font-size: 32rpx; |
||||
|
font-weight: 600; |
||||
} |
} |
||||
|
} |
||||
</style> |
</style> |
||||
@ -1,61 +1,61 @@ |
|||||
<template> |
<template> |
||||
<view class="switch-bar"> |
<view class="switch-bar"> |
||||
<text class="title">{{title}}</text> |
<text class="title">{{ title }}</text> |
||||
<switch class="switch" :checked="checked" color="#18bc37" @change="onChange"></switch> |
<switch class="switch" :checked="checked" color="#18bc37" @change="onChange"></switch> |
||||
</view> |
</view> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
export default { |
export default { |
||||
name: "switch-bar", |
name: "switch-bar", |
||||
props: { |
props: { |
||||
title: { |
title: { |
||||
type: String, |
type: String, |
||||
required: true |
required: true |
||||
}, |
|
||||
checked: { |
|
||||
type: Boolean, |
|
||||
default: false |
|
||||
} |
|
||||
}, |
}, |
||||
data() { |
checked: { |
||||
return { |
type: Boolean, |
||||
value: this.checked |
default: false |
||||
} |
} |
||||
}, |
}, |
||||
methods: { |
data() { |
||||
onChange(e) { |
return { |
||||
this.value = true; |
value: this.checked |
||||
setTimeout(()=>{ |
|
||||
this.value = false; |
|
||||
},100) |
|
||||
//this.value = false; |
|
||||
|
|
||||
this.$emit('change', e); |
|
||||
} |
|
||||
} |
} |
||||
|
}, |
||||
|
methods: { |
||||
|
onChange(e) { |
||||
|
this.value = true; |
||||
|
setTimeout(() => { |
||||
|
this.value = false; |
||||
|
}, 100) |
||||
|
//this.value = false; |
||||
|
|
||||
|
this.$emit('change', e); |
||||
|
} |
||||
} |
} |
||||
|
|
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<style lang="scss" scoped> |
<style lang="scss" scoped> |
||||
.switch-bar { |
.switch-bar { |
||||
width: 100%; |
width: 100%; |
||||
height: 100rpx; |
height: 100rpx; |
||||
font-size: 34rpx; |
font-size: 34rpx; |
||||
color: black; |
color: black; |
||||
margin-top: 5rpx; |
margin-top: 5rpx; |
||||
background-color: white; |
background-color: white; |
||||
line-height: 100rpx; |
line-height: 100rpx; |
||||
display: flex; |
display: flex; |
||||
|
|
||||
.title { |
.title { |
||||
flex: 1; |
flex: 1; |
||||
margin-left: 40rpx; |
margin-left: 40rpx; |
||||
} |
} |
||||
|
|
||||
.switch { |
.switch { |
||||
margin-right: 40rpx; |
margin-right: 40rpx; |
||||
} |
|
||||
} |
} |
||||
|
} |
||||
</style> |
</style> |
||||
@ -1,59 +1,58 @@ |
|||||
<template> |
<template> |
||||
<view class="group-item" @click="showGroupInfo()"> |
<view class="group-item" @click="showGroupInfo()"> |
||||
<head-image :name="group.showGroupName" |
<head-image :name="group.showGroupName" :url="group.headImage" size="small"></head-image> |
||||
:url="group.headImage" size="small"></head-image> |
|
||||
<view class="group-name"> |
<view class="group-name"> |
||||
<view>{{ group.showGroupName}}</view> |
<view>{{ group.showGroupName }}</view> |
||||
</view> |
</view> |
||||
</view> |
</view> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
export default { |
export default { |
||||
name: "group-item", |
name: "group-item", |
||||
data() { |
data() { |
||||
return {} |
return {} |
||||
|
}, |
||||
|
methods: { |
||||
|
showGroupInfo() { |
||||
|
uni.navigateTo({ |
||||
|
url: "/pages/group/group-info?id=" + this.group.id |
||||
|
}) |
||||
}, |
}, |
||||
methods:{ |
}, |
||||
showGroupInfo(){ |
props: { |
||||
uni.navigateTo({ |
group: { |
||||
url:"/pages/group/group-info?id="+this.group.id |
type: Object |
||||
}) |
|
||||
}, |
|
||||
}, |
|
||||
props: { |
|
||||
group: { |
|
||||
type: Object |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<style scope lang="scss"> |
<style scope lang="scss"> |
||||
.group-item { |
.group-item { |
||||
height: 90rpx; |
height: 90rpx; |
||||
display: flex; |
display: flex; |
||||
margin-bottom: 2rpx; |
margin-bottom: 2rpx; |
||||
position: relative; |
position: relative; |
||||
padding: 18rpx 20rpx; |
padding: 18rpx 20rpx; |
||||
align-items: center; |
align-items: center; |
||||
background-color: white; |
background-color: white; |
||||
white-space: nowrap; |
white-space: nowrap; |
||||
|
|
||||
&:hover { |
&:hover { |
||||
background-color: $im-bg-active; |
background-color: $im-bg-active; |
||||
} |
} |
||||
|
|
||||
&.active { |
&.active { |
||||
background-color: $im-bg-active; |
background-color: $im-bg-active; |
||||
} |
} |
||||
|
|
||||
.group-name { |
.group-name { |
||||
font-size: $im-font-size; |
font-size: $im-font-size; |
||||
padding-left: 20rpx; |
padding-left: 20rpx; |
||||
text-align: left; |
text-align: left; |
||||
white-space: nowrap; |
white-space: nowrap; |
||||
overflow: hidden; |
overflow: hidden; |
||||
} |
|
||||
} |
} |
||||
|
} |
||||
</style> |
</style> |
||||
|
|||||
File diff suppressed because it is too large
@ -1,146 +1,150 @@ |
|||||
<template> |
<template> |
||||
<nav-bar add search @add="onAddNewFriends" @search="showSearch = !showSearch">好友</nav-bar> |
|
||||
<view class="tab-page friend"> |
<view class="tab-page friend"> |
||||
|
<nav-bar add search @add="onAddNewFriends" @search="showSearch = !showSearch">好友</nav-bar> |
||||
<view class="nav-bar" v-if="showSearch"> |
<view class="nav-bar" v-if="showSearch"> |
||||
<view class="nav-search"> |
<view class="nav-search"> |
||||
<uni-search-bar v-model="searchText" radius="100" cancelButton="none" placeholder="点击搜索好友"></uni-search-bar> |
<uni-search-bar v-model="searchText" radius="100" cancelButton="none" |
||||
|
placeholder="点击搜索好友"></uni-search-bar> |
||||
</view> |
</view> |
||||
</view> |
</view> |
||||
<view class="friend-tip" v-if="friends.length==0"> |
<view class="friend-tip" v-if="friends.length == 0"> |
||||
温馨提示:您现在还没有任何好友,快点击右上方'+'按钮添加好友吧~ |
温馨提示:您现在还没有任何好友,快点击右上方'+'按钮添加好友吧~ |
||||
</view> |
</view> |
||||
<view class="friend-items" v-else> |
<view class="friend-items" v-else> |
||||
<up-index-list :index-list="friendIdx" > |
<up-index-list :index-list="friendIdx"> |
||||
<template v-for="(friends,i) in friendGroups"> |
<template v-for="(friends, i) in friendGroups"> |
||||
<up-index-item> |
<up-index-item> |
||||
<up-index-anchor :text="friendIdx[i]=='*'?'在线':friendIdx[i]"></up-index-anchor> |
<up-index-anchor :text="friendIdx[i] == '*' ? '在线' : friendIdx[i]"></up-index-anchor> |
||||
<view v-for="(friend,idx) in friends" :key="idx"> |
<view v-for="(friend, idx) in friends" :key="idx"> |
||||
<friend-item :friend="friend"></friend-item> |
<friend-item :friend="friend"></friend-item> |
||||
</view> |
</view> |
||||
</up-index-item> |
</up-index-item> |
||||
</template> |
</template> |
||||
</up-index-list> |
</up-index-list> |
||||
</view> |
</view> |
||||
|
|
||||
</view> |
</view> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
import { pinyin } from 'pinyin-pro'; |
import { pinyin } from 'pinyin-pro'; |
||||
|
|
||||
export default { |
export default { |
||||
data() { |
data() { |
||||
return { |
return { |
||||
showSearch: false, |
showSearch: false, |
||||
searchText: '' |
searchText: '' |
||||
} |
} |
||||
|
}, |
||||
|
methods: { |
||||
|
onAddNewFriends() { |
||||
|
uni.navigateTo({ |
||||
|
url: "/pages/friend/friend-add" |
||||
|
}) |
||||
|
}, |
||||
|
firstLetter(strText) { |
||||
|
// 使用pinyin-pro库将中文转换为拼音 |
||||
|
let pinyinOptions = { |
||||
|
toneType: 'none', // 无声调 |
||||
|
type: 'normal' // 普通拼音 |
||||
|
}; |
||||
|
let pyText = pinyin(strText, pinyinOptions); |
||||
|
return pyText[0]; |
||||
|
}, |
||||
|
isEnglish(character) { |
||||
|
return /^[A-Za-z]+$/.test(character); |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
friends() { |
||||
|
return this.friendStore.friends; |
||||
|
}, |
||||
|
friendGroupMap() { |
||||
|
// 按首字母分组 |
||||
|
let groupMap = new Map(); |
||||
|
this.friends.forEach((f) => { |
||||
|
if (this.searchText && !f.nickName.includes(this.searchText)) { |
||||
|
return; |
||||
|
} |
||||
|
let letter = this.firstLetter(f.nickName).toUpperCase(); |
||||
|
// 非英文一律为#组 |
||||
|
if (!this.isEnglish(letter)) { |
||||
|
letter = "#" |
||||
|
} |
||||
|
if (f.online) { |
||||
|
letter = '*' |
||||
|
} |
||||
|
if (groupMap.has(letter)) { |
||||
|
groupMap.get(letter).push(f); |
||||
|
} else { |
||||
|
groupMap.set(letter, [f]); |
||||
|
} |
||||
|
}) |
||||
|
// 排序 |
||||
|
let arrayObj = Array.from(groupMap); |
||||
|
arrayObj.sort((a, b) => { |
||||
|
// #组在最后面 |
||||
|
if (a[0] == '#' || b[0] == '#') { |
||||
|
return b[0].localeCompare(a[0]) |
||||
|
} |
||||
|
return a[0].localeCompare(b[0]) |
||||
|
}) |
||||
|
groupMap = new Map(arrayObj.map(i => [i[0], i[1]])); |
||||
|
return groupMap; |
||||
}, |
}, |
||||
methods: { |
friendIdx() { |
||||
onAddNewFriends() { |
return Array.from(this.friendGroupMap.keys()); |
||||
uni.navigateTo({ |
|
||||
url: "/pages/friend/friend-add" |
|
||||
}) |
|
||||
}, |
|
||||
firstLetter(strText) { |
|
||||
// 使用pinyin-pro库将中文转换为拼音 |
|
||||
let pinyinOptions = { |
|
||||
toneType: 'none', // 无声调 |
|
||||
type: 'normal' // 普通拼音 |
|
||||
}; |
|
||||
let pyText = pinyin(strText, pinyinOptions); |
|
||||
return pyText[0]; |
|
||||
}, |
|
||||
isEnglish(character) { |
|
||||
return /^[A-Za-z]+$/.test(character); |
|
||||
} |
|
||||
}, |
}, |
||||
computed: { |
friendGroups() { |
||||
friends() { |
return Array.from(this.friendGroupMap.values()); |
||||
return this.friendStore.friends; |
|
||||
}, |
|
||||
friendGroupMap(){ |
|
||||
// 按首字母分组 |
|
||||
let groupMap = new Map(); |
|
||||
this.friends.forEach((f) => { |
|
||||
if(this.searchText && !f.nickName.includes(this.searchText)){ |
|
||||
return; |
|
||||
} |
|
||||
let letter = this.firstLetter(f.nickName).toUpperCase(); |
|
||||
// 非英文一律为#组 |
|
||||
if (!this.isEnglish(letter)) { |
|
||||
letter = "#" |
|
||||
} |
|
||||
if (f.online) { |
|
||||
letter = '*' |
|
||||
} |
|
||||
if (groupMap.has(letter)) { |
|
||||
groupMap.get(letter).push(f); |
|
||||
} else { |
|
||||
groupMap.set(letter, [f]); |
|
||||
} |
|
||||
}) |
|
||||
// 排序 |
|
||||
let arrayObj = Array.from(groupMap); |
|
||||
arrayObj.sort((a, b) => { |
|
||||
// #组在最后面 |
|
||||
if (a[0] == '#' || b[0] == '#') { |
|
||||
return b[0].localeCompare(a[0]) |
|
||||
} |
|
||||
return a[0].localeCompare(b[0]) |
|
||||
}) |
|
||||
groupMap = new Map(arrayObj.map(i => [i[0], i[1]])); |
|
||||
return groupMap; |
|
||||
}, |
|
||||
friendIdx(){ |
|
||||
return Array.from(this.friendGroupMap.keys()); |
|
||||
}, |
|
||||
friendGroups(){ |
|
||||
return Array.from(this.friendGroupMap.values()); |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<style lang="scss" scoped> |
<style lang="scss" scoped> |
||||
.friend { |
.friend { |
||||
position: relative; |
position: relative; |
||||
display: flex; |
display: flex; |
||||
flex-direction: column; |
flex-direction: column; |
||||
|
|
||||
:deep(.u-index-anchor){ |
:deep(.u-index-anchor) { |
||||
height: 60rpx !important; |
height: 60rpx !important; |
||||
background-color: unset !important; |
background-color: unset !important; |
||||
border-bottom: none !important; |
border-bottom: none !important; |
||||
} |
} |
||||
:deep(.u-index-anchor__text){ |
|
||||
color: $im-text-color !important; |
|
||||
} |
|
||||
:deep(.u-index-list__letter__item){ |
|
||||
width: 48rpx !important; |
|
||||
height: 48rpx !important; |
|
||||
} |
|
||||
:deep(.u-index-list__letter__item__index){ |
|
||||
font-size: $im-font-size-small !important; |
|
||||
} |
|
||||
|
|
||||
.friend-tip { |
:deep(.u-index-anchor__text) { |
||||
position: absolute; |
color: $im-text-color !important; |
||||
top: 400rpx; |
} |
||||
padding: 50rpx; |
|
||||
text-align: center; |
:deep(.u-index-list__letter__item) { |
||||
line-height: 50rpx; |
width: 48rpx !important; |
||||
color: $im-text-color-lighter; |
height: 48rpx !important; |
||||
} |
} |
||||
|
|
||||
|
:deep(.u-index-list__letter__item__index) { |
||||
|
font-size: $im-font-size-small !important; |
||||
|
} |
||||
|
|
||||
|
.friend-tip { |
||||
|
position: absolute; |
||||
|
top: 400rpx; |
||||
|
padding: 50rpx; |
||||
|
text-align: center; |
||||
|
line-height: 50rpx; |
||||
|
color: $im-text-color-lighter; |
||||
|
} |
||||
|
|
||||
|
.friend-items { |
||||
|
flex: 1; |
||||
|
padding: 0; |
||||
|
overflow: hidden; |
||||
|
position: relative; |
||||
|
|
||||
.friend-items { |
.scroll-bar { |
||||
flex: 1; |
height: 100%; |
||||
padding: 0; |
|
||||
overflow: hidden; |
|
||||
position: relative; |
|
||||
|
|
||||
.scroll-bar { |
|
||||
height: 100%; |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
} |
||||
</style> |
</style> |
||||
@ -1,156 +1,157 @@ |
|||||
<template> |
<template> |
||||
<nav-bar back>修改群资料</nav-bar> |
<view v-if="userStore.userInfo.type == 1" class="page group-edit"> |
||||
<view v-if="userStore.userInfo.type == 1" class="page group-edit"> |
<nav-bar back>修改群资料</nav-bar> |
||||
<uni-card :is-shadow="false" is-full :border="false"> |
<uni-card :is-shadow="false" is-full :border="false"> |
||||
<uni-forms ref="form" :modelValue="group" :rules="rules" validate-trigger="bind" label-position="top" |
<uni-forms ref="form" :modelValue="group" :rules="rules" validate-trigger="bind" label-position="top" |
||||
label-width="100%"> |
label-width="100%"> |
||||
<uni-forms-item name="headImage" class="avatar"> |
<uni-forms-item name="headImage" class="avatar"> |
||||
<image-upload v-if="isOwner" :onSuccess="onUnloadImageSuccess"> |
<image-upload v-if="isOwner" :onSuccess="onUnloadImageSuccess"> |
||||
<image :src="group.headImageThumb" class="group-image"></image> |
<image :src="group.headImageThumb" class="group-image"></image> |
||||
</image-upload> |
</image-upload> |
||||
<head-image v-if="!isOwner" :name="group.showGroupName" |
<head-image v-if="!isOwner" :name="group.showGroupName" :url="group.headImageThumb" |
||||
:url="group.headImageThumb" :size="200"></head-image> |
:size="200"></head-image> |
||||
</uni-forms-item> |
</uni-forms-item> |
||||
<uni-forms-item label="群聊名称" name="name" :required="true"> |
<uni-forms-item label="群聊名称" name="name" :required="true"> |
||||
<uni-easyinput type="text" v-model="group.name" :disabled="!isOwner" placeholder="请输入群聊名称" /> |
<uni-easyinput type="text" v-model="group.name" :disabled="!isOwner" placeholder="请输入群聊名称" /> |
||||
</uni-forms-item> |
</uni-forms-item> |
||||
<uni-forms-item label="群聊备注" name="remarkGroupName"> |
<uni-forms-item label="群聊备注" name="remarkGroupName"> |
||||
<uni-easyinput v-model="group.remarkGroupName" type="text" :placeholder="group.name" /> |
<uni-easyinput v-model="group.remarkGroupName" type="text" :placeholder="group.name" /> |
||||
</uni-forms-item> |
</uni-forms-item> |
||||
<uni-forms-item label="我在本群的昵称" name="remarkNickName"> |
<uni-forms-item label="我在本群的昵称" name="remarkNickName"> |
||||
<uni-easyinput v-model="group.remarkNickName" type="text" :placeholder="userStore.userInfo.nickName" /> |
<uni-easyinput v-model="group.remarkNickName" type="text" |
||||
</uni-forms-item> |
:placeholder="userStore.userInfo.nickName" /> |
||||
<uni-forms-item label="群公告" name="notice"> |
</uni-forms-item> |
||||
<uni-easyinput type="textarea" v-model="group.notice" :disabled="!isOwner" placeholder="请输入群公告" /> |
<uni-forms-item label="群公告" name="notice"> |
||||
</uni-forms-item> |
<uni-easyinput type="textarea" v-model="group.notice" :disabled="!isOwner" placeholder="请输入群公告" /> |
||||
</uni-forms> |
</uni-forms-item> |
||||
</uni-card> |
</uni-forms> |
||||
<button class="bottom-btn" type="primary" @click="submit()">提交</button> |
</uni-card> |
||||
</view> |
<button class="bottom-btn" type="primary" @click="submit()">提交</button> |
||||
|
</view> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
export default { |
export default { |
||||
data() { |
data() { |
||||
return { |
return { |
||||
group: {}, |
group: {}, |
||||
rules: { |
rules: { |
||||
name: { |
name: { |
||||
rules: [{ |
rules: [{ |
||||
required: true, |
required: true, |
||||
errorMessage: '请输入群聊名称', |
errorMessage: '请输入群聊名称', |
||||
}] |
}] |
||||
} |
|
||||
|
|
||||
} |
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
submit() { |
||||
|
if (this.group.id) { |
||||
|
this.modifyGroup(); |
||||
|
} else { |
||||
|
this.createNewGroup(); |
||||
} |
} |
||||
}, |
}, |
||||
|
onUnloadImageSuccess(file, res) { |
||||
|
this.group.headImage = res.data.originUrl; |
||||
|
this.group.headImageThumb = res.data.thumbUrl; |
||||
|
}, |
||||
|
modifyGroup() { |
||||
|
this.$http({ |
||||
|
url: "/group/modify", |
||||
|
method: "PUT", |
||||
|
data: this.group |
||||
|
}).then((group) => { |
||||
|
this.groupStore.updateGroup(group); |
||||
|
uni.showToast({ |
||||
|
title: "修改群聊信息成功", |
||||
|
icon: 'none' |
||||
|
}); |
||||
|
setTimeout(() => { |
||||
|
let pages = getCurrentPages(); |
||||
|
let prevPage = pages[pages.length - 2]; |
||||
|
prevPage.$vm.loadGroupInfo(); |
||||
|
uni.navigateBack(); |
||||
|
}, 1000); |
||||
|
|
||||
methods: { |
}) |
||||
submit() { |
}, |
||||
if (this.group.id) { |
createNewGroup() { |
||||
this.modifyGroup(); |
this.$http({ |
||||
} else { |
url: "/group/create", |
||||
this.createNewGroup(); |
method: 'POST', |
||||
} |
data: this.group |
||||
}, |
}).then((group) => { |
||||
onUnloadImageSuccess(file, res) { |
this.groupStore.addGroup(group); |
||||
this.group.headImage = res.data.originUrl; |
uni.showToast({ |
||||
this.group.headImageThumb = res.data.thumbUrl; |
title: `群聊创建成功,快邀请小伙伴进群吧`, |
||||
}, |
icon: 'none', |
||||
modifyGroup() { |
duration: 1500 |
||||
this.$http({ |
}); |
||||
url: "/group/modify", |
setTimeout(() => { |
||||
method: "PUT", |
uni.navigateTo({ |
||||
data: this.group |
url: "/pages/group/group-info?id=" + group.id |
||||
}).then((group) => { |
|
||||
this.groupStore.updateGroup(group); |
|
||||
uni.showToast({ |
|
||||
title: "修改群聊信息成功", |
|
||||
icon: 'none' |
|
||||
}); |
|
||||
setTimeout(() => { |
|
||||
let pages = getCurrentPages(); |
|
||||
let prevPage = pages[pages.length - 2]; |
|
||||
prevPage.$vm.loadGroupInfo(); |
|
||||
uni.navigateBack(); |
|
||||
}, 1000); |
|
||||
|
|
||||
}) |
|
||||
}, |
|
||||
createNewGroup() { |
|
||||
this.$http({ |
|
||||
url: "/group/create", |
|
||||
method: 'POST', |
|
||||
data: this.group |
|
||||
}).then((group) => { |
|
||||
this.groupStore.addGroup(group); |
|
||||
uni.showToast({ |
|
||||
title: `群聊创建成功,快邀请小伙伴进群吧`, |
|
||||
icon: 'none', |
|
||||
duration: 1500 |
|
||||
}); |
}); |
||||
setTimeout(() => { |
}, 1500) |
||||
uni.navigateTo({ |
|
||||
url: "/pages/group/group-info?id=" + group.id |
|
||||
}); |
|
||||
}, 1500) |
|
||||
|
|
||||
}) |
|
||||
}, |
|
||||
loadGroupInfo(id) { |
|
||||
this.$http({ |
|
||||
url: `/group/find/${id}`, |
|
||||
method: 'GET' |
|
||||
}).then((group) => { |
|
||||
this.group = group; |
|
||||
// 更新聊天页面的群聊信息 |
|
||||
this.chatStore.updateChatFromGroup(group); |
|
||||
// 更新聊天列表的群聊信息 |
|
||||
this.groupStore.updateGroup(group); |
|
||||
|
|
||||
}); |
}) |
||||
}, |
|
||||
initNewGroup() { |
|
||||
let userInfo = this.userStore.userInfo; |
|
||||
this.group = { |
|
||||
name: `${userInfo.userName}创建的群聊`, |
|
||||
headImage: userInfo.headImage, |
|
||||
headImageThumb: userInfo.headImageThumb, |
|
||||
ownerId: this.userStore.userInfo.id |
|
||||
} |
|
||||
} |
|
||||
}, |
}, |
||||
computed: { |
loadGroupInfo(id) { |
||||
isOwner() { |
this.$http({ |
||||
return this.userStore.userInfo.id == this.group.ownerId |
url: `/group/find/${id}`, |
||||
} |
method: 'GET' |
||||
|
}).then((group) => { |
||||
|
this.group = group; |
||||
|
// 更新聊天页面的群聊信息 |
||||
|
this.chatStore.updateChatFromGroup(group); |
||||
|
// 更新聊天列表的群聊信息 |
||||
|
this.groupStore.updateGroup(group); |
||||
|
|
||||
|
}); |
||||
}, |
}, |
||||
onLoad(options) { |
initNewGroup() { |
||||
if (options.id) { |
let userInfo = this.userStore.userInfo; |
||||
// 修改群聊 |
this.group = { |
||||
this.loadGroupInfo(options.id); |
name: `${userInfo.userName}创建的群聊`, |
||||
} else { |
headImage: userInfo.headImage, |
||||
// 创建群聊 |
headImageThumb: userInfo.headImageThumb, |
||||
this.initNewGroup(); |
ownerId: this.userStore.userInfo.id |
||||
} |
} |
||||
|
|
||||
} |
} |
||||
|
}, |
||||
|
computed: { |
||||
|
isOwner() { |
||||
|
return this.userStore.userInfo.id == this.group.ownerId |
||||
|
} |
||||
|
}, |
||||
|
onLoad(options) { |
||||
|
if (options.id) { |
||||
|
// 修改群聊 |
||||
|
this.loadGroupInfo(options.id); |
||||
|
} else { |
||||
|
// 创建群聊 |
||||
|
this.initNewGroup(); |
||||
|
} |
||||
|
|
||||
} |
} |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<style lang="scss" scoped> |
<style lang="scss" scoped> |
||||
.group-edit { |
.group-edit { |
||||
//padding: 20rpx; |
//padding: 20rpx; |
||||
|
|
||||
.group-image { |
.group-image { |
||||
width: 200rpx; |
width: 200rpx; |
||||
height: 200rpx; |
height: 200rpx; |
||||
border: 1px solid #ccc; |
border: 1px solid #ccc; |
||||
border-radius: 5%; |
border-radius: 5%; |
||||
} |
|
||||
} |
} |
||||
.avatar { |
} |
||||
margin-top: -30px; |
|
||||
} |
.avatar { |
||||
|
margin-top: -30px; |
||||
|
} |
||||
</style> |
</style> |
||||
|
|||||
@ -1,166 +1,165 @@ |
|||||
<template> |
<template> |
||||
<view class="page group-invite"> |
<view class="page group-invite"> |
||||
<view class="nav-bar"> |
<view class="nav-bar"> |
||||
<view class="nav-search"> |
<view class="nav-search"> |
||||
<uni-search-bar v-model="searchText" radius="100" cancelButton="none" placeholder="输入好友昵称搜索"></uni-search-bar> |
<uni-search-bar v-model="searchText" radius="100" cancelButton="none" |
||||
</view> |
placeholder="输入好友昵称搜索"></uni-search-bar> |
||||
</view> |
</view> |
||||
|
</view> |
||||
<view class="friend-items"> |
<view class="friend-items"> |
||||
<scroll-view class="scroll-bar" scroll-with-animation="true" scroll-y="true"> |
<scroll-view class="scroll-bar" scroll-with-animation="true" scroll-y="true"> |
||||
<view v-for="friend in friendItems" v-show="!searchText || friend.nickName.includes(searchText)" |
<view v-for="friend in friendItems" v-show="!searchText || friend.nickName.includes(searchText)" |
||||
:key="friend.id"> |
:key="friend.id"> |
||||
<view class="friend-item" @click="onSwitchChecked(friend)" :class="{checked: friend.checked, disabled: friend.disabled}"> |
<view class="friend-item" @click="onSwitchChecked(friend)" |
||||
<head-image :name="friend.nickName" |
:class="{ checked: friend.checked, disabled: friend.disabled }"> |
||||
:online="friend.online" :url="friend.headImage"></head-image> |
<head-image :name="friend.nickName" :online="friend.online" |
||||
|
:url="friend.headImage"></head-image> |
||||
<view class="friend-name">{{ friend.nickName}}</view> |
<view class="friend-name">{{ friend.nickName }}</view> |
||||
<!-- <view class="friend-checked">--> |
|
||||
<!-- <radio :checked="friend.checked" :disabled="friend.disabled" @click.stop="onSwitchChecked(friend)"/>--> |
|
||||
<!-- </view>--> |
|
||||
</view> |
</view> |
||||
</view> |
</view> |
||||
</scroll-view> |
</scroll-view> |
||||
</view> |
</view> |
||||
<button class="bottom-btn" type="primary" :disabled="inviteSize==0" @click="onInviteFriends()">邀请({{inviteSize}}) </button> |
<button class="bottom-btn" type="primary" :disabled="inviteSize == 0" |
||||
|
@click="onInviteFriends()">邀请({{ inviteSize }}) </button> |
||||
</view> |
</view> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
export default { |
export default { |
||||
data() { |
data() { |
||||
return { |
return { |
||||
groupId: null, |
groupId: null, |
||||
searchText: "", |
searchText: "", |
||||
groupMembers: [], |
groupMembers: [], |
||||
friendItems: [] |
friendItems: [] |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
onInviteFriends() { |
||||
|
let inviteVo = { |
||||
|
groupId: this.groupId, |
||||
|
friendIds: [] |
||||
} |
} |
||||
}, |
this.friendItems.forEach((f) => { |
||||
methods: { |
if (f.checked && !f.disabled) { |
||||
onInviteFriends() { |
inviteVo.friendIds.push(f.id); |
||||
let inviteVo = { |
|
||||
groupId: this.groupId, |
|
||||
friendIds: [] |
|
||||
} |
|
||||
this.friendItems.forEach((f) => { |
|
||||
if (f.checked && !f.disabled) { |
|
||||
inviteVo.friendIds.push(f.id); |
|
||||
} |
|
||||
}) |
|
||||
if (inviteVo.friendIds.length > 0) { |
|
||||
this.$http({ |
|
||||
url: "/group/invite", |
|
||||
method: 'POST', |
|
||||
data: inviteVo |
|
||||
}).then(() => { |
|
||||
uni.showToast({ |
|
||||
title: "邀请成功", |
|
||||
icon: 'none' |
|
||||
}) |
|
||||
setTimeout(() => { |
|
||||
// 回退并刷新 |
|
||||
let pages = getCurrentPages(); |
|
||||
let prevPage = pages[pages.length - 2]; |
|
||||
prevPage.$vm.loadGroupMembers(); |
|
||||
uni.navigateBack(); |
|
||||
}, 1000); |
|
||||
|
|
||||
}) |
|
||||
} |
} |
||||
}, |
}) |
||||
onShowUserInfo(userId) { |
if (inviteVo.friendIds.length > 0) { |
||||
uni.navigateTo({ |
|
||||
url: "/pages/common/user-info?id=" + userId |
|
||||
}) |
|
||||
}, |
|
||||
onSwitchChecked(friend) { |
|
||||
if (!friend.disabled) { |
|
||||
friend.checked = !friend.checked; |
|
||||
} |
|
||||
}, |
|
||||
initFriendItems() { |
|
||||
this.friendItems = []; |
|
||||
let friends = this.friendStore.friends; |
|
||||
friends.forEach((f => { |
|
||||
let item = { |
|
||||
id: f.id, |
|
||||
headImage: f.headImage, |
|
||||
nickName: f.nickName, |
|
||||
online: f.online |
|
||||
} |
|
||||
item.disabled = this.isGroupMember(f.id); |
|
||||
item.checked = item.disabled; |
|
||||
this.friendItems.push(item); |
|
||||
})) |
|
||||
}, |
|
||||
loadGroupMembers(id) { |
|
||||
this.$http({ |
this.$http({ |
||||
url: `/group/members/${id}`, |
url: "/group/invite", |
||||
method: "GET" |
method: 'POST', |
||||
}).then((members) => { |
data: inviteVo |
||||
this.groupMembers = members.filter(m => !m.quit); |
}).then(() => { |
||||
this.initFriendItems(); |
uni.showToast({ |
||||
}) |
title: "邀请成功", |
||||
}, |
icon: 'none' |
||||
|
}) |
||||
|
setTimeout(() => { |
||||
|
// 回退并刷新 |
||||
|
let pages = getCurrentPages(); |
||||
|
let prevPage = pages[pages.length - 2]; |
||||
|
prevPage.$vm.loadGroupMembers(); |
||||
|
uni.navigateBack(); |
||||
|
}, 1000); |
||||
|
|
||||
isGroupMember(id) { |
}) |
||||
return this.groupMembers.some(m => m.userId == id); |
|
||||
} |
} |
||||
}, |
}, |
||||
computed: { |
onShowUserInfo(userId) { |
||||
inviteSize() { |
uni.navigateTo({ |
||||
return this.friendItems.filter(f => !f.disabled && f.checked).length; |
url: "/pages/common/user-info?id=" + userId |
||||
|
}) |
||||
|
}, |
||||
|
onSwitchChecked(friend) { |
||||
|
if (!friend.disabled) { |
||||
|
friend.checked = !friend.checked; |
||||
} |
} |
||||
}, |
}, |
||||
onLoad(options) { |
initFriendItems() { |
||||
this.groupId = options.id; |
this.friendItems = []; |
||||
this.loadGroupMembers(options.id); |
let friends = this.friendStore.friends; |
||||
|
friends.forEach((f => { |
||||
|
let item = { |
||||
|
id: f.id, |
||||
|
headImage: f.headImage, |
||||
|
nickName: f.nickName, |
||||
|
online: f.online |
||||
|
} |
||||
|
item.disabled = this.isGroupMember(f.id); |
||||
|
item.checked = item.disabled; |
||||
|
this.friendItems.push(item); |
||||
|
})) |
||||
|
}, |
||||
|
loadGroupMembers(id) { |
||||
|
this.$http({ |
||||
|
url: `/group/members/${id}`, |
||||
|
method: "GET" |
||||
|
}).then((members) => { |
||||
|
this.groupMembers = members.filter(m => !m.quit); |
||||
|
this.initFriendItems(); |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
isGroupMember(id) { |
||||
|
return this.groupMembers.some(m => m.userId == id); |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
inviteSize() { |
||||
|
return this.friendItems.filter(f => !f.disabled && f.checked).length; |
||||
} |
} |
||||
|
}, |
||||
|
onLoad(options) { |
||||
|
this.groupId = options.id; |
||||
|
this.loadGroupMembers(options.id); |
||||
} |
} |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<style lang="scss" scoped> |
<style lang="scss" scoped> |
||||
.group-invite { |
.group-invite { |
||||
|
position: relative; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
|
||||
|
.friend-items { |
||||
position: relative; |
position: relative; |
||||
display: flex; |
flex: 1; |
||||
flex-direction: column; |
overflow: hidden; |
||||
|
|
||||
.friend-items { |
.friend-item { |
||||
|
height: 120rpx; |
||||
|
display: flex; |
||||
|
margin-bottom: 1rpx; |
||||
position: relative; |
position: relative; |
||||
flex: 1; |
padding: 0 30rpx; |
||||
overflow: hidden; |
align-items: center; |
||||
|
background-color: white; |
||||
.friend-item { |
white-space: nowrap; |
||||
height: 120rpx; |
|
||||
display: flex; |
|
||||
margin-bottom: 1rpx; |
|
||||
position: relative; |
|
||||
padding: 0 30rpx ; |
|
||||
align-items: center; |
|
||||
background-color: white; |
|
||||
white-space: nowrap; |
|
||||
|
|
||||
&.disabled { |
&.disabled { |
||||
background-color: $im-bg-active !important; |
background-color: $im-bg-active !important; |
||||
} |
} |
||||
|
|
||||
&.checked { |
|
||||
background-color: $im-color-primary-light-9; |
|
||||
} |
|
||||
|
|
||||
.friend-name { |
&.checked { |
||||
flex:1; |
background-color: $im-color-primary-light-9; |
||||
padding-left: 20rpx; |
|
||||
font-size: 30rpx; |
|
||||
font-weight: 600; |
|
||||
line-height: 60rpx; |
|
||||
white-space: nowrap; |
|
||||
overflow: hidden; |
|
||||
} |
|
||||
} |
} |
||||
|
|
||||
.scroll-bar { |
.friend-name { |
||||
height: 100%; |
flex: 1; |
||||
|
padding-left: 20rpx; |
||||
|
font-size: 30rpx; |
||||
|
font-weight: 600; |
||||
|
line-height: 60rpx; |
||||
|
white-space: nowrap; |
||||
|
overflow: hidden; |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
|
.scroll-bar { |
||||
|
height: 100%; |
||||
|
} |
||||
} |
} |
||||
|
} |
||||
</style> |
</style> |
||||
@ -1,81 +1,81 @@ |
|||||
<template> |
<template> |
||||
<view class="page mine-edit"> |
<view class="page mine-edit"> |
||||
<nav-bar back>修改我的信息</nav-bar> |
<nav-bar back>修改我的信息</nav-bar> |
||||
<uni-card :is-shadow="false" is-full :border="false"> |
<uni-card :is-shadow="false" is-full :border="false"> |
||||
<uni-forms ref="form" :modelValue="userInfo" label-position="top" |
<uni-forms ref="form" :modelValue="userInfo" label-position="top" label-width="100%"> |
||||
label-width="100%"> |
<uni-forms-item name="headImage" class="avatar"> |
||||
<uni-forms-item name="headImage" class="avatar"> |
<image-upload :onSuccess="onUnloadImageSuccess"> |
||||
<image-upload :onSuccess="onUnloadImageSuccess"> |
<image :src="userInfo.headImageThumb" class="head-image"></image> |
||||
<image :src="userInfo.headImageThumb" class="head-image"></image> |
</image-upload> |
||||
</image-upload> |
</uni-forms-item> |
||||
</uni-forms-item> |
<uni-forms-item label="用户名" name="userName"> |
||||
<uni-forms-item label="用户名" name="userName"> |
<uni-easyinput type="text" v-model="userInfo.userName" :disabled="true" /> |
||||
<uni-easyinput type="text" v-model="userInfo.userName" :disabled="true" /> |
</uni-forms-item> |
||||
</uni-forms-item> |
<uni-forms-item label="昵称" name="nickName"> |
||||
<uni-forms-item label="昵称" name="nickName"> |
<uni-easyinput v-model="userInfo.nickName" type="text" :placeholder="userInfo.userName" /> |
||||
<uni-easyinput v-model="userInfo.nickName" type="text" :placeholder="userInfo.userName" /> |
</uni-forms-item> |
||||
</uni-forms-item> |
<uni-forms-item label="性别" name="sex"> |
||||
<uni-forms-item label="性别" name="sex"> |
<uni-data-checkbox v-model="userInfo.sex" |
||||
<uni-data-checkbox v-model="userInfo.sex" :localdata="[{text: '男', value: 0}, {text: '女', value: 1}]"></uni-data-checkbox> |
:localdata="[{ text: '男', value: 0 }, { text: '女', value: 1 }]"></uni-data-checkbox> |
||||
</uni-forms-item> |
</uni-forms-item> |
||||
<uni-forms-item label="签名" name="signature"> |
<uni-forms-item label="签名" name="signature"> |
||||
<uni-easyinput type="textarea" v-model="userInfo.signature" placeholder="编辑个性标签,展示我的独特态度" /> |
<uni-easyinput type="textarea" v-model="userInfo.signature" placeholder="编辑个性标签,展示我的独特态度" /> |
||||
</uni-forms-item> |
</uni-forms-item> |
||||
</uni-forms> |
</uni-forms> |
||||
</uni-card> |
</uni-card> |
||||
<button type="primary" class="bottom-btn" @click="onSubmit()">提交</button> |
<button type="primary" class="bottom-btn" @click="onSubmit()">提交</button> |
||||
</view> |
</view> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
export default { |
export default { |
||||
data() { |
data() { |
||||
return { |
return { |
||||
userInfo: {} |
userInfo: {} |
||||
} |
} |
||||
|
}, |
||||
|
methods: { |
||||
|
onSexchange(e) { |
||||
|
this.userInfo.sex = e.detail.value; |
||||
}, |
}, |
||||
methods:{ |
onUnloadImageSuccess(file, res) { |
||||
onSexchange(e){ |
this.userInfo.headImage = res.data.originUrl; |
||||
this.userInfo.sex=e.detail.value; |
this.userInfo.headImageThumb = res.data.thumbUrl; |
||||
}, |
|
||||
onUnloadImageSuccess(file, res) { |
|
||||
this.userInfo.headImage = res.data.originUrl; |
|
||||
this.userInfo.headImageThumb = res.data.thumbUrl; |
|
||||
}, |
|
||||
onSubmit(){ |
|
||||
this.$http({ |
|
||||
url: "/user/update", |
|
||||
method: "PUT", |
|
||||
data: this.userInfo |
|
||||
}).then(()=>{ |
|
||||
this.userStore.setUserInfo(this.userInfo); |
|
||||
uni.showToast({ |
|
||||
title:"修改成功", |
|
||||
icon: 'none' |
|
||||
}); |
|
||||
setTimeout(()=>{ |
|
||||
uni.navigateBack(); |
|
||||
},1000); |
|
||||
}) |
|
||||
} |
|
||||
}, |
}, |
||||
onLoad() { |
onSubmit() { |
||||
// 深拷贝一份数据 |
this.$http({ |
||||
let mine = this.userStore.userInfo; |
url: "/user/update", |
||||
this.userInfo = JSON.parse(JSON.stringify(mine)); |
method: "PUT", |
||||
|
data: this.userInfo |
||||
|
}).then(() => { |
||||
|
this.userStore.setUserInfo(this.userInfo); |
||||
|
uni.showToast({ |
||||
|
title: "修改成功", |
||||
|
icon: 'none' |
||||
|
}); |
||||
|
setTimeout(() => { |
||||
|
uni.navigateBack(); |
||||
|
}, 1000); |
||||
|
}) |
||||
} |
} |
||||
|
}, |
||||
|
onLoad() { |
||||
|
// 深拷贝一份数据 |
||||
|
let mine = this.userStore.userInfo; |
||||
|
this.userInfo = JSON.parse(JSON.stringify(mine)); |
||||
} |
} |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<style scoped lang="scss"> |
<style scoped lang="scss"> |
||||
.mine-edit { |
.mine-edit { |
||||
.head-image { |
.head-image { |
||||
width: 200rpx; |
width: 200rpx; |
||||
height: 200rpx; |
height: 200rpx; |
||||
} |
|
||||
} |
} |
||||
|
} |
||||
|
|
||||
.avatar { |
.avatar { |
||||
margin-top: -30px; |
margin-top: -30px; |
||||
} |
} |
||||
</style> |
</style> |
||||
|
|||||
@ -1,102 +1,101 @@ |
|||||
<template> |
<template> |
||||
<view class="page mine-password"> |
<view class="page mine-password"> |
||||
<nav-bar back>修改密码</nav-bar> |
<nav-bar back>修改密码</nav-bar> |
||||
<uni-card :is-shadow="false" is-full :border="false"> |
<uni-card :is-shadow="false" is-full :border="false"> |
||||
<uni-forms ref="form" :modelValue="formData" label-position="top" label-width="100%" > |
<uni-forms ref="form" :modelValue="formData" label-position="top" label-width="100%"> |
||||
<uni-forms-item label="原密码" name="oldPassword"> |
<uni-forms-item label="原密码" name="oldPassword"> |
||||
<uni-easyinput type="password" v-model="formData.oldPassword" /> |
<uni-easyinput type="password" v-model="formData.oldPassword" /> |
||||
</uni-forms-item> |
</uni-forms-item> |
||||
<uni-forms-item label="新密码" name="newPassword"> |
<uni-forms-item label="新密码" name="newPassword"> |
||||
<uni-easyinput type="password" v-model="formData.newPassword" /> |
<uni-easyinput type="password" v-model="formData.newPassword" /> |
||||
</uni-forms-item> |
</uni-forms-item> |
||||
<uni-forms-item label="确认密码" name="confirmPassword"> |
<uni-forms-item label="确认密码" name="confirmPassword"> |
||||
<uni-easyinput type="password" v-model="formData.confirmPassword" /> |
<uni-easyinput type="password" v-model="formData.confirmPassword" /> |
||||
</uni-forms-item> |
</uni-forms-item> |
||||
</uni-forms> |
</uni-forms> |
||||
</uni-card> |
</uni-card> |
||||
<button class="bottom-btn" type="primary" @click="onSubmit()">提交</button> |
<button class="bottom-btn" type="primary" @click="onSubmit()">提交</button> |
||||
</view> |
</view> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
export default { |
export default { |
||||
data() { |
data() { |
||||
return { |
return { |
||||
formData: { |
formData: { |
||||
oldPassword: "", |
oldPassword: "", |
||||
newPassword: "", |
newPassword: "", |
||||
confirmPassword: "" |
confirmPassword: "" |
||||
|
}, |
||||
|
rules: { |
||||
|
oldPassword: { |
||||
|
rules: [{ |
||||
|
required: true, |
||||
|
errorMessage: '请输入原密码', |
||||
|
}] |
||||
}, |
}, |
||||
rules: { |
newPassword: { |
||||
oldPassword: { |
rules: [{ |
||||
rules: [{ |
required: true, |
||||
required: true, |
errorMessage: '请输入新密码', |
||||
errorMessage: '请输入原密码', |
}, { |
||||
}] |
validateFunction: function (rule, value, data, callback) { |
||||
}, |
if (data.confirmPassword != data.newPassword) { |
||||
newPassword: { |
callback("两次输入的密码不一致"); |
||||
rules: [{ |
|
||||
required: true, |
|
||||
errorMessage: '请输入新密码', |
|
||||
}, { |
|
||||
validateFunction: function(rule, value, data, callback) { |
|
||||
if (data.confirmPassword != data.newPassword) { |
|
||||
callback("两次输入的密码不一致"); |
|
||||
} |
|
||||
if (data.newPassword == data.oldPassword) { |
|
||||
callback("新密码不能和原密码一致"); |
|
||||
} |
|
||||
return true; |
|
||||
} |
} |
||||
}] |
if (data.newPassword == data.oldPassword) { |
||||
}, |
callback("新密码不能和原密码一致"); |
||||
confirmPassword: { |
} |
||||
rules: [{ |
return true; |
||||
required: true, |
} |
||||
errorMessage: '请输入确认密码', |
}] |
||||
}, { |
}, |
||||
validateFunction: function(rule, value, data, callback) { |
confirmPassword: { |
||||
if (data.confirmPassword != data.newPassword) { |
rules: [{ |
||||
callback("两次输入的密码不一致"); |
required: true, |
||||
} |
errorMessage: '请输入确认密码', |
||||
|
}, { |
||||
return true; |
validateFunction: function (rule, value, data, callback) { |
||||
|
if (data.confirmPassword != data.newPassword) { |
||||
|
callback("两次输入的密码不一致"); |
||||
} |
} |
||||
}] |
|
||||
} |
|
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
}] |
||||
} |
} |
||||
|
|
||||
} |
} |
||||
}, |
} |
||||
methods: { |
}, |
||||
onSubmit() { |
methods: { |
||||
this.$refs.form.validate().then(res => { |
onSubmit() { |
||||
this.$http({ |
this.$refs.form.validate().then(res => { |
||||
url: "/modifyPwd", |
this.$http({ |
||||
method: "PUT", |
url: "/modifyPwd", |
||||
data: this.formData |
method: "PUT", |
||||
}).then((res) => { |
data: this.formData |
||||
uni.showToast({ |
}).then((res) => { |
||||
title: "修改密码成功", |
uni.showToast({ |
||||
icon: 'none' |
title: "修改密码成功", |
||||
}) |
icon: 'none' |
||||
setTimeout(()=>{ |
|
||||
uni.navigateBack(); |
|
||||
},1000); |
|
||||
}) |
}) |
||||
}).catch(err => { |
setTimeout(() => { |
||||
console.log('表单错误信息:', err); |
uni.navigateBack(); |
||||
|
}, 1000); |
||||
}) |
}) |
||||
|
}).catch(err => { |
||||
|
console.log('表单错误信息:', err); |
||||
|
}) |
||||
|
|
||||
} |
|
||||
}, |
|
||||
onReady() { |
|
||||
// 需要在onReady中设置规则 |
|
||||
this.$refs.form.setRules(this.rules) |
|
||||
} |
} |
||||
|
}, |
||||
|
onReady() { |
||||
|
// 需要在onReady中设置规则 |
||||
|
this.$refs.form.setRules(this.rules) |
||||
} |
} |
||||
|
|
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<style scoped lang="scss"> |
<style scoped lang="scss"></style> |
||||
</style> |
|
||||
Loading…
Reference in new issue