mirror of
https://github.com/LingChair/LingChair-V0.git
synced 2025-12-07 09:35:49 +08:00
feat: 多标签页聊天(实验性)
This commit is contained in:
@@ -23,14 +23,14 @@
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: flex-start;
|
||||
margin: 13px;
|
||||
margin: 13px 13px 13px 10%;
|
||||
}
|
||||
|
||||
.chat-message-left {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
margin: 13px;
|
||||
margin: 13px 10% 13px 13px;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
@@ -39,9 +39,10 @@
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
max-width: 100%;
|
||||
min-width: 0%;
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
font-size: medium;
|
||||
/* font-size: medium; */
|
||||
/* 使用了 CardView 就不需要边框了 */
|
||||
/* border: 1.3px solid; */
|
||||
padding: 15px;
|
||||
|
||||
@@ -188,14 +188,14 @@ class NickCache {
|
||||
* @returns {String} nick
|
||||
*/
|
||||
static async getNick(name) {
|
||||
return await new Promise((res, rej) => {
|
||||
return await new Promise((res, _rej) => {
|
||||
// 这个this别摆着不放啊 不然两下就会去世
|
||||
let nick = this.data[name]
|
||||
let nick = NickCache.data[name]
|
||||
if (nick == null)
|
||||
client.emit("user.getNick", { name: localStorage.userName }, (re) => {
|
||||
client.emit("user.getNick", { name: name }, (re) => {
|
||||
let nk = re.data != null ? re.data.nick : name
|
||||
if (nk == null) nk = name
|
||||
this.data[name] = nk
|
||||
NickCache.data[name] = nk
|
||||
res(nk)
|
||||
})
|
||||
else
|
||||
@@ -204,6 +204,10 @@ class NickCache {
|
||||
}
|
||||
}
|
||||
|
||||
// ================================
|
||||
// 联系人
|
||||
// ================================
|
||||
|
||||
class ContactsList {
|
||||
/**
|
||||
* 重载联系人列表
|
||||
@@ -221,7 +225,7 @@ class ContactsList {
|
||||
for (let index in ls) {
|
||||
let name = ls[index]
|
||||
let dick = await NickCache.getNick(name)
|
||||
$($.parseHTML(`<li class="mdui-list-item mdui-ripple" mdui-drawer-close><div class="mdui-list-item-avatar"><img src="` + CurrentUser.getUserHeadUrl(name) + `" onerror="this.src='res/default_head.png'" /></div><div class="mdui-list-item-content">` + dick + `</div></li>`)).appendTo(viewBinding.contactsList).click(() => {
|
||||
$($.parseHTML(`<li class="mdui-list-item mdui-ripple" mdui-drawer-close><div class="mdui-list-item-avatar"><img src="${ CurrentUser.getUserHeadUrl(name) }" onerror="this.src='res/default_head.png'" /></div><div class="mdui-list-item-content">` + dick + `</div></li>`)).appendTo(viewBinding.contactsList).click(() => {
|
||||
ChatMsgAdapter.switchTo(name, "single")
|
||||
})
|
||||
}
|
||||
@@ -232,9 +236,16 @@ class ContactsList {
|
||||
* 添加联系人/群峦
|
||||
* @param {String} nameOrId
|
||||
*/
|
||||
static add(name, type) {
|
||||
static async add(name, type) {
|
||||
if (type == "single") {
|
||||
|
||||
client.emit("user.addFriend", {
|
||||
name: localStorage.userName,
|
||||
target: name,
|
||||
accessToken: await CurrentUser.getAccessToken(),
|
||||
}, async (re) => {
|
||||
// if (re.code !== 0)
|
||||
return mdui.snackbar(re.msg)
|
||||
})
|
||||
}
|
||||
}
|
||||
/**
|
||||
@@ -245,21 +256,256 @@ class ContactsList {
|
||||
}
|
||||
}
|
||||
|
||||
// 消息核心
|
||||
// ================================
|
||||
// 消息核心
|
||||
// ================================
|
||||
|
||||
class ChatTabManager {
|
||||
static tabs = {}
|
||||
/**
|
||||
* 添加Tab
|
||||
* @param { String } title
|
||||
* @param { String } target
|
||||
*/
|
||||
static add(title, target) {
|
||||
$($.parseHTML(`<a onclick="ChatMsgAdapter.switchTo('${target}');" tag="chatTab" id="chatTab_${target}" class="mdui-ripple" style="text-transform: none;">${title}</a>`)).appendTo(viewBinding.chatTab)
|
||||
}
|
||||
/**
|
||||
* 寻找Tab
|
||||
* @param { String } target
|
||||
* @returns { jQuery } element
|
||||
*/
|
||||
static find(target) {
|
||||
return $("#chatTab_" + target)
|
||||
}
|
||||
/**
|
||||
* 点击Tab
|
||||
* @param { String } target
|
||||
*/
|
||||
static click(target) {
|
||||
this.find(this.target).click()
|
||||
}
|
||||
/**
|
||||
* 删除Tab
|
||||
* @param { String } target
|
||||
*/
|
||||
static remove(target) {
|
||||
this.find(target).remove()
|
||||
}
|
||||
}
|
||||
|
||||
class ChatPage {
|
||||
static cached = {}
|
||||
constructor(name, type) {
|
||||
|
||||
constructor(name, title, type) {
|
||||
this.chatTarget = name
|
||||
this.chatType = type
|
||||
ChatTabManager.add(title, this.chatTarget)
|
||||
this.chatPageElement = $($.parseHTML(`<div class="chat-seesion" id="chatPageTargetIs${this.chatTarget}" target="${this.chatTarget}"></div>`))
|
||||
this.chatPageElement.appendTo(viewBinding.pageChatSeesion)
|
||||
}
|
||||
/**
|
||||
* 切换到某一个聊天对象
|
||||
* @param {String} name
|
||||
* @param {String} type
|
||||
* 获取当前的聊天栏
|
||||
* @returns { jQuery }
|
||||
*/
|
||||
static switchTo(name, type) {
|
||||
if (!this.cached[name])
|
||||
this.cached[name] = new ChatPage(name, type)
|
||||
static getCurrentChatSeesion() {
|
||||
return $(".chat-seesion[actived=true]")
|
||||
}
|
||||
/**
|
||||
* 获取当前聊天页面
|
||||
* @returns { ChatPage }
|
||||
*/
|
||||
static getCurrentChatPage(name) {
|
||||
return ChatPage.cached[$(".chat-seesion[actived=true]").attr("target")]
|
||||
}
|
||||
/**
|
||||
* 切换选择的聊天对象
|
||||
*/
|
||||
async show() {
|
||||
ChatTabManager.click(this.chatTarget)
|
||||
|
||||
this.minMsgId = null
|
||||
|
||||
for (let k of Object.keys(ChatPage.cached)) {
|
||||
let cpe = ChatPage.cached[k].chatPageElement
|
||||
cpe.attr("actived", null)
|
||||
cpe.hide()
|
||||
let tbe = ChatTabManager.find(k)
|
||||
tbe.removeClass("mdui-tab-active")
|
||||
}
|
||||
|
||||
$(this.chatPageElement).empty()
|
||||
$(this.chatPageElement).attr("actived", "true")
|
||||
$(this.chatPageElement).show()
|
||||
ChatTabManager.find(this.chatTarget).addClass("mdui-tab-active")
|
||||
|
||||
await this.loadMore()
|
||||
ChatMsgAdapter.scrollToBottom()
|
||||
}
|
||||
/**
|
||||
* 连带Tab一起销毁
|
||||
*/
|
||||
remove() {
|
||||
ChatTabManager.remove(this.chatTarget)
|
||||
ChatPage.cached[this.chatTarget].chatPageElement.remove()
|
||||
ChatPage.cached[this.chatTarget] = null
|
||||
}
|
||||
/**
|
||||
* 加载更多聊天记录
|
||||
* @param {int} 加载数量
|
||||
*/
|
||||
async loadMore(limit) {
|
||||
let histroy = await this.getHistroy(this.minMsgId, limit == null ? 13 : limit)
|
||||
let chatPager = viewBinding.chatPager.get(0)
|
||||
|
||||
if (histroy.length == 0)
|
||||
return mdui.snackbar("已经加载完了~")
|
||||
|
||||
let re = this.minMsgId != null
|
||||
this.minMsgId = histroy[0].msgid - 1
|
||||
let sc = 0
|
||||
if (re) histroy = histroy.reverse()
|
||||
for (let index in histroy) {
|
||||
let i = histroy[index]
|
||||
let e = await this.addMsg(i.name, i.msg, i.time, re, i.msgid)
|
||||
// 因为某些因素直接DEBUG到吐血 断点继续都不报错 原因不明
|
||||
sc = sc + (e == null ? 35 : getOffsetTop(chatPager, e.get(0)))
|
||||
}
|
||||
chatPager.scrollBy({
|
||||
top: sc,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 获取聊天消息记录
|
||||
* @param {int} 起始点
|
||||
* @param {int} 获取数量
|
||||
*/
|
||||
async getHistroy(start, limit) {
|
||||
if (this.chatType == "single")
|
||||
return new Promise(async (res, _rej) => {
|
||||
client.emit("user.getSingleChatHistroy", {
|
||||
name: localStorage.userName,
|
||||
target: this.chatTarget,
|
||||
limit: limit,
|
||||
accessToken: await CurrentUser.getAccessToken(),
|
||||
startId: start,
|
||||
}, (re) => {
|
||||
if (re.code !== 0)
|
||||
return mdui.snackbar(re.msg)
|
||||
res(re.data.histroy)
|
||||
})
|
||||
})
|
||||
throw new TypeError("Unsupported chat type!")
|
||||
}
|
||||
/**
|
||||
* 发送消息
|
||||
* @param { String } msg
|
||||
*/
|
||||
async send(msg) {
|
||||
if (this.chatType == "single")
|
||||
client.emit("user.sendSingleMsg", {
|
||||
name: localStorage.userName,
|
||||
target: this.chatTarget,
|
||||
msg: msg,
|
||||
accessToken: await CurrentUser.getAccessToken(),
|
||||
}, async (re) => {
|
||||
if (re.code !== 0)
|
||||
return mdui.snackbar(re.msg)
|
||||
|
||||
viewBinding.inputMsg.val("")
|
||||
|
||||
// 微机课闲的没事干玩玩 发现私聊会多发一个(一个是本地的, 另一个是发送成功的) 选择一个关掉就好了
|
||||
// 这里我选择服务端不发送回调, 不然多设备同步会吵死
|
||||
// 错了 应该是客户端少发条才对 不然不能多设备同步
|
||||
if (ChatMsgAdapter.target !== localStorage.userName) {
|
||||
let i = ChatMsgAdapter.isAtBottom()
|
||||
await ChatMsgAdapter.addMsg(localStorage.userName, msg, re.data.time, re.data.msgid)
|
||||
if (i) ChatMsgAdapter.scrollToBottom()
|
||||
}
|
||||
})
|
||||
throw new TypeError("Unsupported chat type!")
|
||||
}
|
||||
/**
|
||||
* 添加系统消息
|
||||
* @param { String } 消息
|
||||
* @param { Boolean } 是否加到顶部
|
||||
* @returns { jQuery } 消息元素
|
||||
*/
|
||||
addSystemMsg(msg, addToTop) {
|
||||
let element
|
||||
if (addToTop)
|
||||
// 加到头部
|
||||
element = $($.parseHTML(msg)).prependTo(this.chatPageElement)
|
||||
else
|
||||
// 加到尾部
|
||||
element = $($.parseHTML(msg)).appendTo(this.chatPageElement)
|
||||
return element
|
||||
}
|
||||
/**
|
||||
* 添加聊天记录
|
||||
* @param { String } name
|
||||
* @param { String } msg
|
||||
* @param { String } type
|
||||
* @param { Boolean } 是否加到头部
|
||||
* @param { String || int } 消息id
|
||||
* @returns { jQuery } 消息元素
|
||||
*/
|
||||
async addMsg(name, preMsg, time, addToTop, msgid) {
|
||||
|
||||
let nick = await NickCache.getNick(name) // re.data == null ? name : re.data.nick
|
||||
|
||||
let msg
|
||||
|
||||
try {
|
||||
msg = await marked.parse(preMsg)
|
||||
} catch (error) {
|
||||
console.log("解析消息失败: " + error)
|
||||
msg = escapeHTML(preMsg)
|
||||
}
|
||||
|
||||
let temp
|
||||
if (name === localStorage.userName)
|
||||
temp = `<div class="chat-message-right">
|
||||
<div class="message-content-with-nickname-right">
|
||||
<span class="nickname">${nick}</span>
|
||||
<div class="message-content mdui-card" tag="msg-card" id="msgid_${msgid}">
|
||||
<span id="msg-content">${msg}</span>
|
||||
<pre class="mdui-hidden" id="raw-msg-content">${preMsg}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<img class="avatar" src="${CurrentUser.getUserHeadUrl(name)}" onerror="this.src='res/default_head.png'" />
|
||||
</div>`
|
||||
else
|
||||
temp = `<div class="chat-message-left">
|
||||
<img class="avatar" src="${CurrentUser.getUserHeadUrl(name)}" onerror="this.src='res/default_head.png'" />
|
||||
<div class="message-content-with-nickname-left">
|
||||
<span class="nickname">${nick}</span>
|
||||
<div class="message-content mdui-card" tag="msg-card" id="msgid_${msgid}">
|
||||
<span id="msg-content">${msg}</span>
|
||||
<pre class="mdui-hidden" id="raw-msg-content">${preMsg}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
let nowMinutes = new Date(time).getMinutes()
|
||||
let msgElement
|
||||
if (addToTop) {
|
||||
this.addSystemMsg(temp, addToTop)
|
||||
if (this.minutesCache != nowMinutes) {
|
||||
msgElement = this.addSystemMsg(`<div class="mdui-center">${new Date().format(time == null ? Date.parse("1000-1-1 00:00:00") : time, "yyyy年MM月dd日 hh:mm:ss")}</div>`, addToTop)
|
||||
this.time = nowMinutes
|
||||
}
|
||||
} else {
|
||||
if (this.minutesCache != nowMinutes) {
|
||||
msgElement = this.addSystemMsg(`<div class="mdui-center">${new Date().format(time == null ? Date.parse("1000-1-1 00:00:00") : time, "yyyy年MM月dd日 hh:mm:ss")}</div>`, addToTop)
|
||||
this.time = nowMinutes
|
||||
}
|
||||
this.addSystemMsg(temp, addToTop)
|
||||
}
|
||||
|
||||
this.minutesCache = new Date(time).getMinutes()
|
||||
|
||||
return msgElement
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +522,11 @@ class ChatMsgAdapter {
|
||||
* @param {String} type
|
||||
*/
|
||||
static async switchTo(name, type) {
|
||||
viewBinding.tabChatSeesion.show()
|
||||
if (!ChatPage.cached[name])
|
||||
ChatPage.cached[name] = new ChatPage(name, await NickCache.getNick(name), type)
|
||||
|
||||
ChatPage.cached[name].show()
|
||||
/* viewBinding.tabChatSeesion.show()
|
||||
viewBinding.tabChatSeesion.text(await NickCache.getNick(name))
|
||||
viewBinding.tabChatSeesion.get(0).click()
|
||||
|
||||
@@ -287,14 +537,15 @@ class ChatMsgAdapter {
|
||||
viewBinding.pageChatSeesion.empty()
|
||||
|
||||
await this.loadMore()
|
||||
this.scrollToBottom()
|
||||
this.scrollToBottom() */
|
||||
}
|
||||
/**
|
||||
* 发送消息
|
||||
* @param {String} msg
|
||||
*/
|
||||
static async send(msg) {
|
||||
client.emit("user.sendSingleMsg", {
|
||||
ChatPage.getCurrentChatPage().send(msg)
|
||||
/* client.emit("user.sendSingleMsg", {
|
||||
name: localStorage.userName,
|
||||
target: this.target,
|
||||
msg: msg,
|
||||
@@ -313,7 +564,7 @@ class ChatMsgAdapter {
|
||||
await ChatMsgAdapter.addMsg(localStorage.userName, msg, re.data.time, re.data.msgid)
|
||||
if (i) ChatMsgAdapter.scrollToBottom()
|
||||
}
|
||||
})
|
||||
}) */
|
||||
}
|
||||
/**
|
||||
* 获取聊天消息记录
|
||||
@@ -337,10 +588,12 @@ class ChatMsgAdapter {
|
||||
}
|
||||
/**
|
||||
* 加载更多聊天记录
|
||||
* @param {int}} 加载数量
|
||||
* @param {int} 加载数量
|
||||
*/
|
||||
static async loadMore(limit) {
|
||||
let histroy = await this.getHistroy(this.minMsgId, limit == null ? 13 : limit)
|
||||
ChatPage.getCurrentChatPage().loadMore(limit)
|
||||
/* let histroy = await this.getHistroy(this.minMsgId, limit == null ? 13 : limit)
|
||||
let chatPager = viewBinding.chatPager.get(0)
|
||||
|
||||
if (histroy.length == 0)
|
||||
return mdui.snackbar("已经加载完了~")
|
||||
@@ -353,12 +606,21 @@ class ChatMsgAdapter {
|
||||
let i = histroy[index]
|
||||
let e = await this.addMsg(i.name, i.msg, i.time, re, i.msgid)
|
||||
// 因为某些因素直接DEBUG到吐血 断点继续都不报错 原因不明
|
||||
sc = sc + (e == null ? 25 : e.get(0).offsetTop)
|
||||
sc = sc + (e == null ? 35 : getOffsetTop(chatPager, e.get(0)))
|
||||
}
|
||||
window.scrollBy({
|
||||
chatPager.scrollBy({
|
||||
top: sc,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
}) */
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否在底部
|
||||
* @returns {Boolean} 是否在底部
|
||||
*/
|
||||
static isAtBottom() {
|
||||
let elementRect = viewBinding.pageChatSeesion.get(0).getBoundingClientRect()
|
||||
return (elementRect.bottom <= window.innerHeight)
|
||||
}
|
||||
/**
|
||||
* 添加系统消息
|
||||
@@ -376,14 +638,6 @@ class ChatMsgAdapter {
|
||||
e = $($.parseHTML(m)).appendTo(viewBinding.pageChatSeesion)
|
||||
return e
|
||||
}
|
||||
/**
|
||||
* 是否在底部
|
||||
* @returns {Boolean} 是否在底部
|
||||
*/
|
||||
static isAtBottom() {
|
||||
let elementRect = viewBinding.pageChatSeesion.get(0).getBoundingClientRect()
|
||||
return (elementRect.bottom <= window.innerHeight)
|
||||
}
|
||||
// 添加消息 返回消息的JQ对象
|
||||
// name: 用户id m: 消息 t: 时间戳 re: 默认加到尾部 msgid: 消息id
|
||||
/**
|
||||
@@ -400,10 +654,10 @@ class ChatMsgAdapter {
|
||||
let nick = await NickCache.getNick(name) // re.data == null ? name : re.data.nick
|
||||
|
||||
let msg
|
||||
|
||||
|
||||
try {
|
||||
msg = await marked.parse(preMsg)
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
console.log("解析消息失败: " + error)
|
||||
msg = escapeHTML(preMsg)
|
||||
}
|
||||
@@ -412,22 +666,22 @@ class ChatMsgAdapter {
|
||||
if (name === localStorage.userName)
|
||||
temp = `<div class="chat-message-right">
|
||||
<div class="message-content-with-nickname-right">
|
||||
<span class="nickname">${ nick }</span>
|
||||
<div class="message-content mdui-card" tag="msg-card" id="msgid_${ msgid }">
|
||||
<span id="msg-content">${ msg }</span>
|
||||
<pre class="mdui-hidden" id="raw-msg-content">${ preMsg }</pre>
|
||||
<span class="nickname">${nick}</span>
|
||||
<div class="message-content mdui-card" tag="msg-card" id="msgid_${msgid}">
|
||||
<span id="msg-content">${msg}</span>
|
||||
<pre class="mdui-hidden" id="raw-msg-content">${preMsg}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<img class="avatar" src="${ CurrentUser.getUserHeadUrl(name) }" onerror="this.src='res/default_head.png'" />
|
||||
<img class="avatar" src="${CurrentUser.getUserHeadUrl(name)}" onerror="this.src='res/default_head.png'" />
|
||||
</div>`
|
||||
else
|
||||
temp = `<div class="chat-message-left">
|
||||
<img class="avatar" src="${ CurrentUser.getUserHeadUrl(name) }" onerror="this.src='res/default_head.png'" />
|
||||
<img class="avatar" src="${CurrentUser.getUserHeadUrl(name)}" onerror="this.src='res/default_head.png'" />
|
||||
<div class="message-content-with-nickname-left">
|
||||
<span class="nickname">${ nick }</span>
|
||||
<div class="message-content mdui-card" tag="msg-card" id="msgid_${ msgid }">
|
||||
<span id="msg-content">${ msg }</span>
|
||||
<pre class="mdui-hidden" id="raw-msg-content">${ preMsg }</pre>
|
||||
<span class="nickname">${nick}</span>
|
||||
<div class="message-content mdui-card" tag="msg-card" id="msgid_${msgid}">
|
||||
<span id="msg-content">${msg}</span>
|
||||
<pre class="mdui-hidden" id="raw-msg-content">${preMsg}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
@@ -437,12 +691,12 @@ class ChatMsgAdapter {
|
||||
if (addToTop) {
|
||||
this.addSystemMsg(temp, addToTop)
|
||||
if (this.minutesCache != nowMinutes) {
|
||||
msgElement = this.addSystemMsg(`<div class="mdui-center">` + new Date().format(time == null ? Date.parse("1000-1-1 00:00:00") : time, "yyyy年MM月dd日 hh:mm:ss") + `</div>`, addToTop)
|
||||
msgElement = this.addSystemMsg(`<div class="mdui-center">${new Date().format(time == null ? Date.parse("1000-1-1 00:00:00") : time, "yyyy年MM月dd日 hh:mm:ss")}</div>`, addToTop)
|
||||
this.time = nowMinutes
|
||||
}
|
||||
} else {
|
||||
if (this.minutesCache != nowMinutes) {
|
||||
msgElement = this.addSystemMsg(`<div class="mdui-center">` + new Date().format(time == null ? Date.parse("1000-1-1 00:00:00") : time, "yyyy年MM月dd日 hh:mm:ss") + `</div>`, addToTop)
|
||||
msgElement = this.addSystemMsg(`<div class="mdui-center">${new Date().format(time == null ? Date.parse("1000-1-1 00:00:00") : time, "yyyy年MM月dd日 hh:mm:ss")}</div>`, addToTop)
|
||||
this.time = nowMinutes
|
||||
}
|
||||
this.addSystemMsg(temp, addToTop)
|
||||
@@ -478,7 +732,7 @@ class ChatMsgAdapter {
|
||||
// 可以利用这个特性来实现自动滚动文本
|
||||
let resize = () => {
|
||||
// CSS 牵一发而动全身 因此这个减少的数值是每天都要更改的
|
||||
viewBinding.pageChatSeesion.height(window.innerHeight - viewBinding.inputToolbar.height() - $("header.mdui-appbar").height() - viewBinding.chatTab.height() - 65)
|
||||
viewBinding.chatPager.height(window.innerHeight - viewBinding.inputToolbar.height() - $("header.mdui-appbar").height() - viewBinding.chatTab.height() - 17)
|
||||
let ledi = this.resizeDick - window.innerHeight
|
||||
if (isMobile()) viewBinding.chatPager.get(0).scrollBy({
|
||||
// 5.19晚10:56分调配出来的秘方
|
||||
@@ -509,10 +763,10 @@ class ChatMsgAdapter {
|
||||
e = $(ele)
|
||||
let menuHtml = $.parseHTML(`<ul class="mdui-menu menu-on-message">
|
||||
<li class="mdui-menu-item">
|
||||
<a onclick="copyText(\`${ e.find("#msg-content").text() }\`)" class="mdui-ripple">复制</a>
|
||||
<a onclick="copyText(\`${e.find("#msg-content").text()}\`)" class="mdui-ripple">复制</a>
|
||||
</li>
|
||||
<li class="mdui-menu-item">
|
||||
<a onclick="mdui.alert(\`${ e.find("#raw-msg-content").text() }\`, '消息原文', () => { }, { confirmText: '关闭' })" class="mdui-ripple">原文</a>
|
||||
<a onclick="mdui.alert(\`${e.find("#raw-msg-content").text()}\`, '消息原文', () => { }, { confirmText: '关闭' })" class="mdui-ripple">原文</a>
|
||||
</li>
|
||||
<li class="mdui-menu-item">
|
||||
<a onclick="mdui.alert('未制作功能', '提示', () => { }, { confirmText: '关闭' })" class="mdui-ripple">转发</a>
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
<div class="mdui-tab mdui-accent-theme mdui-theme-color-auto" style="position: fixed; z-index: 114;width: 100%;"
|
||||
mdui-tab n-id="chatTab">
|
||||
<!-- 侧滑栏的 z-index 是2000, 在移动端会直接覆盖 -->
|
||||
<a href="#page-chat-seesion" n-id="tabChatSeesion" class="mdui-ripple" style="text-transform: none;"></a>
|
||||
<!-- <a href="#page-chat-seesion" n-id="tabChatSeesion" tag="chatTab" class="mdui-ripple" style="text-transform: none;"></a> -->
|
||||
</div>
|
||||
<!-- 滚动到底部咋这么难写... -->
|
||||
<div style="display: flex;flex-direction: column;">
|
||||
@@ -132,8 +132,7 @@
|
||||
<div class="mdui-center" style="margin: 15px;"><a href="javascript:;" onclick="ChatMsgAdapter.loadMore()"
|
||||
class="mdui-text-color-theme">加载更多</a> | <a href="javascript:;"
|
||||
onclick="ChatMsgAdapter.scrollToBottom()" class="mdui-text-color-theme">回到底部</a></div>
|
||||
<div n-id="pageChatSeesion" class="chat-seesion">
|
||||
</div>
|
||||
<div n-id="pageChatSeesion" class="chat-seesion" id="page-chat-seesion"></div>
|
||||
<!-- 输入框和聊天消息重叠的原因就是死人 scrollbar, 把自动调整的距离调小, margin调大就行了 -->
|
||||
</div>
|
||||
<!-- 妈的黑化了 私人玩意这么难整 早知道 z-index 弄死它得了 浪费我时间 我就没试过这么离谱的样式表 第三方库真难写CSS 就应该先写后端的 啊啊啊啊啊啊 -->
|
||||
|
||||
@@ -42,6 +42,16 @@ const checkEmpty = (i) => {
|
||||
return (i == null) || ("" === i) || (0 === i)
|
||||
}
|
||||
|
||||
// AI的力量太强了
|
||||
function getOffsetTop(parent, child) {
|
||||
let top = 0
|
||||
while (child && child !== parent) {
|
||||
top += child.offsetTop
|
||||
child = child.offsetParent
|
||||
}
|
||||
return top
|
||||
}
|
||||
|
||||
function escapeHTML(str) {
|
||||
return str.replace(/[<>&"']/g, function (match) {
|
||||
switch (match) {
|
||||
|
||||
@@ -29,7 +29,7 @@ let apis = {
|
||||
// 账号文件结构: {uid: 10000, name: "GenShin", nick: "Impact", passwd: "SHA-256 + MD5"}
|
||||
// 注意: 密码在客户端也应该经过哈希处理(SHA256 + MD5)
|
||||
// @APi
|
||||
signUp: (name, passwd) => {
|
||||
signUp(name, passwd) {
|
||||
if (passwd == null || name == null)
|
||||
return { msg: "必须输入 账号和密码", code: -1 }
|
||||
|
||||
@@ -56,7 +56,7 @@ let apis = {
|
||||
// 登录账号: 账号, 密码 返回刷新令牌 失败返回 null 和原因
|
||||
// 注意: 密码在客户端应该经过哈希处理(SHA256 + MD5)
|
||||
// @API
|
||||
signIn: (name, passwd) => {
|
||||
signIn(name, passwd) {
|
||||
if (passwd == null || name == null)
|
||||
return { msg: "必须输入 账号和密码", code: -1 }
|
||||
|
||||
@@ -73,7 +73,7 @@ let apis = {
|
||||
// 注意: 密码在客户端也应该经过哈希处理(SHA256 + MD5)
|
||||
// 刷新令牌算法: 哈希(用户ID + 当前年 + 当前月 + 密码 + 盐)
|
||||
// 有效期: 一个月
|
||||
getRefreshToken: (name, passwd) => {
|
||||
getRefreshToken(name, passwd) {
|
||||
let d = new Date()
|
||||
let raw = name + d.getFullYear() + d.getMonth() + passwd + "LINGCHAIR-TEST-DEMO"
|
||||
return hash.sha256(raw) + hash.md5(raw)
|
||||
@@ -83,7 +83,7 @@ let apis = {
|
||||
// 注意: 密码在客户端也应该经过哈希处理(SHA256 + MD5)
|
||||
// 刷新令牌算法: 哈希(用户ID + 当前年 + 当前月 + 密码 + 盐)
|
||||
// 有效期: 一天
|
||||
getAccessTokenNonApi: (name, rt) => {
|
||||
getAccessTokenNonApi(name, rt) {
|
||||
if (!apis.checkRefreshToken(name, rt))
|
||||
return null
|
||||
let date = new Date().toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'numeric', day: 'numeric' })
|
||||
@@ -94,25 +94,25 @@ let apis = {
|
||||
// 在密码被设置前已经被哈希过,不需要重复
|
||||
// 算法: (SHA256 + MD5)
|
||||
// 警告: 这是经过二次哈希的
|
||||
getPassWordHashed: (name) => {
|
||||
getPassWordHashed(name) {
|
||||
return hash.sha256(apis.getPassWordHashedRaw(name)) + hash.md5(apis.getPassWordHashedRaw(name))
|
||||
},
|
||||
|
||||
// 请勿与上面的混淆
|
||||
// 上面的是经过第二次哈希的
|
||||
getPassWordHashedRaw: (name) => {
|
||||
getPassWordHashedRaw(name) {
|
||||
return io.open(getUserPath(name) + "/user.json").readJson().passwd
|
||||
},
|
||||
|
||||
// 检测刷新令牌是否正确: 账号, 刷新令牌 返回布尔值
|
||||
// 密码在服务端经过哈希保存 不需要重复输入密码
|
||||
checkRefreshToken: (name, rt) => {
|
||||
checkRefreshToken(name, rt) {
|
||||
return apis.getRefreshToken(name, apis.getPassWordHashed(name)) === rt
|
||||
},
|
||||
|
||||
// 检测访问令牌是否正确: 账号, 访问令牌 返回布尔值
|
||||
// 密码在服务端经过哈希保存 不需要重复输入密码
|
||||
checkAccessToken: (name, at) => {
|
||||
checkAccessToken(name, at) {
|
||||
return apis.getAccessTokenNonApi(name, apis.getRefreshToken(name, apis.getPassWordHashed(name /* 就是你这个傻逼害得我找两年BUG */))) === at
|
||||
},
|
||||
|
||||
@@ -124,7 +124,7 @@ let apis = {
|
||||
// 有效期: 一天
|
||||
// 算法: SHA256(name) + MD5(rt + 盐)
|
||||
// @Api
|
||||
getAccessToken: (name, rt) => {
|
||||
getAccessToken(name, rt) {
|
||||
if (!apis.checkRefreshToken(name, rt))
|
||||
return { msg: "刷新令牌不正确!", code: -1 }
|
||||
|
||||
@@ -133,7 +133,7 @@ let apis = {
|
||||
|
||||
// 设置头像: 账号, 访问令牌, 头像数据 返回结果
|
||||
// @API
|
||||
setHeadImage: (name, at, head) => {
|
||||
setHeadImage(name, at, head) {
|
||||
if (!apis.checkAccessToken(name, at))
|
||||
return { msg: "访问令牌不正确!", code: -1 }
|
||||
|
||||
@@ -144,7 +144,7 @@ let apis = {
|
||||
|
||||
// 修改昵称
|
||||
// @APi
|
||||
setNick: (name, at, nick) => {
|
||||
setNick(name, at, nick) {
|
||||
if (!apis.checkAccessToken(name, at))
|
||||
return { msg: "访问令牌不正确!", code: -1 }
|
||||
|
||||
@@ -160,8 +160,8 @@ let apis = {
|
||||
return { msg: "成功", code: 0 }
|
||||
},
|
||||
|
||||
// 取联系人列表(好友): 账号, 访问令牌 返回好友列表
|
||||
getFriendsNonApi: (name, at) => {
|
||||
// 取联系人列表(好友): 账号 返回好友列表
|
||||
getFriendsNonApi(name) {
|
||||
let file = getUserPath(name) + "/friends.json"
|
||||
if (!io.exists(file))
|
||||
io.open(file, "w").writeJson({list: [name]}).close()
|
||||
@@ -169,8 +169,19 @@ let apis = {
|
||||
return io.open(file, "r").readJson().list
|
||||
},
|
||||
|
||||
// 加好友: 账号, 欲添加对象
|
||||
addFriendNonApi(name, target) {
|
||||
let file = getUserPath(name) + "/friends.json"
|
||||
if (!io.exists(file))
|
||||
io.open(file, "w").writeJson({list: [name]}).close()
|
||||
|
||||
let friends = io.open(file, "r").readJson()
|
||||
friends.list.push(target)
|
||||
io.open(file, "r").writeJson(friends).close()
|
||||
},
|
||||
|
||||
// 取用户昵称: 账号 返回昵称
|
||||
getNickNonApi: (name) => {
|
||||
getNickNonApi(name) {
|
||||
let file = getUserPath(name) + "/user.json"
|
||||
|
||||
return io.open(file, "r").readJson().nick
|
||||
@@ -178,18 +189,29 @@ let apis = {
|
||||
|
||||
// 取昵称: 账号 返回昵称
|
||||
// @API
|
||||
getNick: (name, at) => {
|
||||
getNick(name, at) {
|
||||
return { msg: "成功", code: 0, nick: apis.getNickNonApi(name)}
|
||||
},
|
||||
|
||||
// 取联系人列表(好友): 账号, 访问令牌 返回好友列表
|
||||
// @API
|
||||
getFriends: (name, at) => {
|
||||
getFriends(name, at) {
|
||||
if (!apis.checkAccessToken(name, at))
|
||||
return { msg: "访问令牌不正确!", code: -1 }
|
||||
|
||||
return { msg: "成功", code: 0, friends: apis.getFriendsNonApi(name, at)}
|
||||
},
|
||||
|
||||
// 加到好友列表: 账号, 欲加的好友, 访问令牌
|
||||
// @API
|
||||
addFriend(name, target, at) {
|
||||
if (!apis.checkAccessToken(name, at))
|
||||
return { msg: "访问令牌不正确!", code: -1 }
|
||||
|
||||
apis.addFriendNonApi(name, target, at)
|
||||
|
||||
return { msg: "成功", code: 0 }
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = apis
|
||||
|
||||
@@ -149,18 +149,17 @@ let api = {
|
||||
},
|
||||
|
||||
// 添加好友
|
||||
// {name: 账号, accessToken: 访问令牌} 返回 {friends: []}
|
||||
// WIP
|
||||
// {name: 账号, accessToken: 访问令牌}
|
||||
"user.addFriend": (a, cb) => {
|
||||
if (checkEmpty([a.name, a.accessToken]))
|
||||
if (checkEmpty([a.name, a.target, a.accessToken]))
|
||||
return cb({ msg: "参数缺失", code: -1 })
|
||||
|
||||
let { msg, code, friends } = users.getFriends(a.name, a.accessToken)
|
||||
let { msg, code } = users.addFriend(a.name, a.target, a.accessToken)
|
||||
|
||||
if (code !== 0)
|
||||
return cb({ msg: msg, code: code })
|
||||
|
||||
cb({ msg: msg, code: 0, data: { friends: friends } })
|
||||
cb({ msg: msg, code: 0 })
|
||||
},
|
||||
|
||||
"user.getNick": (a, cb) => {
|
||||
|
||||
Reference in New Issue
Block a user