refactor(user_msg): bootstrap5

This commit is contained in:
Baoshuo Ren 2023-01-16 15:34:51 +08:00
parent dc3515353e
commit 39df125d16
Signed by: baoshuo
GPG Key ID: 00CB9680AB29F51A
2 changed files with 208 additions and 121 deletions

View File

@ -1,100 +1,129 @@
<?php <?php
requireLib('bootstrap5');
if (!Auth::check()) { if (!Auth::check()) {
redirectToLogin(); redirectToLogin();
} }
function handleMsgPost() { function handleMsgPost() {
if (!isset($_POST['receiver'])) {
return 'fail';
}
if (!isset($_POST['message'])) { if (!isset($_POST['message'])) {
return 'fail'; return 'fail';
} }
if (0 > strlen($_POST['message']) || strlen($_POST['message']) > 65535) { if (0 > strlen($_POST['message']) || strlen($_POST['message']) > 65535) {
return 'fail'; return 'fail';
} }
$receiver = $_POST['receiver']; $receiver = UOJRequest::user(UOJRequest::POST, 'receiver');
$esc_message = DB::escape($_POST['message']); if (!$receiver) {
$sender = Auth::id(); return 'fail';
}
$message = $_POST['message'];
if (!validateUsername($receiver) || !UOJUser::query($receiver)) { if ($receiver['username'] === Auth::id()) {
return 'fail'; return 'fail';
} }
DB::query("insert into user_msg (sender, receiver, message, send_time) values ('$sender', '$receiver', '$esc_message', now())"); DB::insert([
"insert into user_msg",
"(sender, receiver, message, send_time)",
"values", DB::tuple([Auth::id(), $receiver['username'], $message, DB::now()])
]);
return "ok"; return "ok";
} }
function getConversations() { function getConversations() {
$username = Auth::id(); $username = Auth::id();
$result = DB::query("select * from user_msg where sender = '$username' or receiver = '$username' order by send_time DESC");
$ret = array(); $res = DB::selectAll([
while ($msg = DB::fetch($result)) { "select * from user_msg",
"where", DB::lor([
"sender" => $username,
"receiver" => $username,
]),
"order by send_time DESC"
]);
$ret = [];
foreach ($res as $msg) {
if ($msg['sender'] !== $username) { if ($msg['sender'] !== $username) {
if (isset($ret[$msg['sender']])) { if (isset($ret[$msg['sender']])) {
$ret[$msg['sender']][1] |= ($msg['read_time'] == null); $ret[$msg['sender']][1] |= ($msg['read_time'] == null);
continue; continue;
} }
$ret[$msg['sender']] = array($msg['send_time'], ($msg['read_time'] == null));
$ret[$msg['sender']] = [$msg['send_time'], ($msg['read_time'] == null)];
} else { } else {
if (isset($ret[$msg['receiver']])) { if (isset($ret[$msg['receiver']])) continue;
continue;
} $ret[$msg['receiver']] = [$msg['send_time'], 0];
$ret[$msg['receiver']] = array($msg['send_time'], 0);
} }
} }
$res = []; $res = [];
foreach ($ret as $name => $con) { foreach ($ret as $name => $con) {
$res[] = [$con[0], $con[1], $name]; $user = UOJUser::query($name);
$res[] = [
$con[0],
$con[1],
$name,
HTML::avatar_addr($user, 128),
UOJUser::getRealname($user),
UOJUser::getUserColor($user),
];
} }
usort($res, function ($a, $b) { usort($res, function ($a, $b) {
return -strcmp($a[0], $b[0]); return -strcmp($a[0], $b[0]);
}); });
return json_encode($res); return json_encode($res);
} }
function getHistory() { function getHistory() {
$username = Auth::id(); $username = Auth::id();
if (!isset($_GET['conversationName']) || !validateUsername($_GET['conversationName'])) { $receiver = UOJRequest::user(UOJRequest::GET, 'conversationName');
$page_num = UOJRequest::uint(UOJRequest::GET, 'pageNumber');
if (!$receiver || $receiver['username'] === $username) {
return '[]'; return '[]';
} }
if (!isset($_GET['pageNumber']) || !validateUInt($_GET['pageNumber'])) { if (!$page_num) { // false, null, or zero
return '[]'; return '[]';
} }
$conversationName = $_GET['conversationName']; DB::update([
$pageNumber = ($_GET['pageNumber'] - 1) * 10; "update user_msg",
DB::query("update user_msg set read_time = now() where sender = '$conversationName' and receiver = '$username' and read_time is null"); "set", ["read_time" => DB::now()],
"where", [
"sender" => $receiver['username'],
"receiver" => $username,
"read_time" => null,
]
]);
$result = DB::query("select * from user_msg where (sender = '$username' and receiver = '$conversationName') or (sender = '$conversationName' and receiver = '$username') order by send_time DESC limit $pageNumber, 11"); $result = DB::selectAll([
$ret = array(); "select * from user_msg",
while ($msg = DB::fetch($result)) { "where", DB::lor([
$ret[] = array($msg['message'], $msg['send_time'], $msg['read_time'], $msg['id'], ($msg['sender'] == $username)); DB::land([
"sender" => $username,
"receiver" => $receiver['username']
]),
DB::land([
"sender" => $receiver['username'],
"receiver" => $username
])
]),
"order by send_time DESC", DB::limit(($page_num - 1) * 10, 11)
]);
$ret = [];
foreach ($result as $msg) {
$ret[] = [
$msg['message'],
$msg['send_time'],
$msg['read_time'],
$msg['id'],
($msg['sender'] === $username),
];
} }
return json_encode($ret); return json_encode($ret);
} }
/*
function deleteMsg($msgId) {
return 1;
$str = <<<EOD
select * from user_msg
where id = $msgId
and read_time is null
EOD;
$result = DB::query($str);
if (DB::fetch($result)) {
$str = <<<EOD
delete from user_msg
where id = $msgId
EOD;
DB::query($str);
return 1;
}
return 0;
}
*/
if (isset($_POST['user_msg'])) { if (isset($_POST['user_msg'])) {
die(handleMsgPost()); die(handleMsgPost());
} elseif (isset($_GET['getConversations'])) { } elseif (isset($_GET['getConversations'])) {
@ -106,38 +135,55 @@ if (isset($_POST['user_msg'])) {
<?php echoUOJPageHeader('私信') ?> <?php echoUOJPageHeader('私信') ?>
<h1 class="page-header">私信</h1> <h1>私信</h1>
<div id="conversations"></div> <div class="card overflow-hidden" style="height: calc(100vh - 10rem);">
<div class="row gx-0 flex-grow-1 h-100">
<div id="history" style="display:none"> <div class="col-md-3 border-end">
<div class="card border-primary"> <div class="list-group list-group-flush" id="conversations"></div>
<div class="card-header bg-primary text-white">
<button type="button" id="goBack" class="btn btn-info btn-sm" style="position:absolute">返回</button>
<div id="conversation-name" class="text-center"></div>
</div> </div>
<div class="card-body">
<ul class="pagination top-buffer-no justify-content-between"> <div class="col-md-9 h-100" id="history" style="display: none">
<li class="previous"><a class="btn btn-outline-secondary text-primary" href="#" id="pageLeft">&larr; 更早的消息</a></li> <div class="card h-100 border-0 rounded-0 h-100">
<li class="text-center" id="pageShow" style="line-height:32px"></li> <div class="card-header">
<li class="next"><a class="btn btn-outline-secondary text-primary" href="#" id="pageRight">更新的消息 &rarr;</a></li> <button type="button" id="goBack" class="bg-transparent border-0 position-absolute text-muted">
</ul> <i class="bi bi-x-lg"></i>
<div id="history-list" style="min-height: 200px;"> </button>
<div id="conversation-name" class="text-center"></div>
</div>
<div class="card-body overflow-auto">
<div id="history-list" style="min-height: 200px;"></div>
</div>
<div class="card-footer bg-transparent">
<ul class="pagination pagination-sm justify-content-between">
<li class="page-item">
<button class="page-link rounded" id="pageLeft">
<i class="bi bi-chevron-left"></i>
更早的消息
</button>
</li>
<li class="page-item">
<button class="page-link rounded" id="pageRight">
更新的消息
<i class="bi bi-chevron-right"></i>
</button>
</li>
</ul>
<form id="form-message" class="">
<div id="form-group-message" class="flex-grow-1">
<textarea id="input-message" class="form-control" style="resize: none;" data-no-autosize></textarea>
<span id="help-message" class="help-block"></span>
</div>
<div class="text-end mt-2">
<span class="text-muted small"> Ctrl+Enter 键发送</span>
<button type="submit" id="message-submit" class="btn btn-primary flex-shrink-0 ms-3">
发送
<i class="bi bi-send"></i>
</button>
</div>
</form>
</div>
</div> </div>
<ul class="pagination top-buffer-no justify-content-between">
<li class="previous"><a class="btn btn-outline-secondary text-primary" href="#history" id="pageLeft2">&larr; 更早的消息</a></li>
<li class="next"><a class="btn btn-outline-secondary text-primary" href="#history" id="pageRight2">更新的消息 &rarr;</a></li>
</ul>
<hr />
<form id="form-message">
<div class="form-group" id="form-group-message">
<textarea id="input-message" class="form-control"></textarea>
<span id="help-message" class="help-block"></span>
</div>
<div class="text-right">
<button type="submit" id="message-submit" class="btn btn-info btn-md">发送</button>
</div>
</form>
</div> </div>
</div> </div>
</div> </div>
@ -155,17 +201,57 @@ if (isset($_POST['user_msg'])) {
</script> </script>
<script type="text/javascript"> <script type="text/javascript">
function addButton(conversationName, send_time, type) { var conversations = {};
var intervalId = 0;
var user_avatar = '<?= HTML::avatar_addr(Auth::user(), 80) ?>';
function formatDate(date) {
var d = new Date(date),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
if (month.length < 2)
month = '0' + month;
if (day.length < 2)
day = '0' + day;
return [year, month, day].join('-');
}
function formatTime(date) {
var d = new Date(date),
hour = '' + d.getHours(),
minute = '' + d.getMinutes();
if (hour.length < 2)
hour = '0' + hour;
if (minute.length < 2)
minute = '0' + minute;
return [hour, minute].join(':');
}
function addButton(conversationName, send_time, type, avatar_addr, realname, color) {
var now = new Date();
var time = new Date(send_time);
var timeStr = formatDate(send_time);
if (formatDate(now) === timeStr) {
timeStr = formatTime(send_time);
}
$("#conversations").append( $("#conversations").append(
'<div class="row top-buffer-sm">' + '<div class="list-group-item list-group-item-action p-2 d-flex ' + (type ? 'list-group-item-warning' : '') + '" style="cursor: pointer;" ' +
'<div class="col-sm-3">' +
'<button type="button" class="btn btn-' + (type ? 'warning' : 'primary') + ' btn-block" ' +
'onclick="enterConversation(\'' + conversationName + '\')">' + 'onclick="enterConversation(\'' + conversationName + '\')">' +
conversationName + '<div class="flex-shrink-0 me-3">' +
'</button>' + '<img class="rounded" width="56" height="56" src="' + avatar_addr + '" />' +
'</div>' + '</div>' +
'<div class="col-sm-9" style="line-height:34px">' + '<div class="flex-grow-1">' +
'最后发送时间:' + send_time + getUserSpan(conversationName, realname, color) +
'<span class="float-end text-muted">' +
timeStr +
'</span>' +
'</div>' + '</div>' +
'</div>' '</div>'
); );
@ -173,24 +259,22 @@ if (isset($_POST['user_msg'])) {
function addBubble(content, send_time, read_time, msgId, conversation, page, type) { function addBubble(content, send_time, read_time, msgId, conversation, page, type) {
$("#history-list").append( $("#history-list").append(
'<div style=' + (!type ? "margin-left:0%;margin-right:20%;" : "margin-left:20%;margin-right:0%;") + '>' + '<div class="d-flex align-items-end mt-3" style="' + (type ? 'margin-left:20%;' : 'margin-right:20%;') + '">' +
'<div class="card border-info mb-4">' + (type ? '' : '<img class="flex-shrink-0 me-2" width="32" height="32" src="' + conversations[conversation][1] + '" />') +
'<div class="card-body" style="background:#17a2b8; word-break: break-all">' + '<div class="card flex-grow-1">' +
'<div style="white-space:pre-wrap">' + '<div class="card-body px-3 py-2" style="white-space:pre-wrap">' +
htmlspecialchars(content) + htmlspecialchars(content) +
'</div>' + '</div>' +
'</div>' + '<div class="card-footer text-muted px-3 py-1">' +
'<div>' + '<span class="small">' +
'<div class="row">' + '<i class="bi bi-clock"></i> ' + send_time +
'<div class="col-sm-6">' + '</span>' +
'发送时间:' + send_time + (read_time == null ?
'</div>' + '<span class="float-end" data-bs-toggle="tooltip" data-bs-title="未读"><i class="bi bi-check2"></i></span>' :
'<div class="col-sm-6 text-right">' + '<span class="float-end" data-bs-toggle="tooltip" data-bs-title="' + read_time + '"><i class="bi bi-check2-all"></i></span>') +
'查看时间:' + (read_time == null ? '<strong>未查看</strong>' : read_time) +
'</div>' +
'</div>' +
'</div>' + '</div>' +
'</div>' + '</div>' +
(type ? '<img class="flex-shrink-0 ms-2" width="32" height="32" src="' + user_avatar + '" />' : '') +
'</div>' '</div>'
); );
} }
@ -204,7 +288,7 @@ if (isset($_POST['user_msg'])) {
$('#help-message').text(''); $('#help-message').text('');
$('#form-group-message').removeClass('has-error'); $('#form-group-message').removeClass('has-error');
$.post('', { $.post('/user_msg', {
user_msg: 1, user_msg: 1,
receiver: conversationName, receiver: conversationName,
message: $('#input-message').val() message: $('#input-message').val()
@ -216,9 +300,9 @@ if (isset($_POST['user_msg'])) {
function refreshHistory(conversation, page) { function refreshHistory(conversation, page) {
$("#history-list").empty(); $("#history-list").empty();
var ret = false; var ret = false;
$('#conversation-name').text(conversation); $('#conversation-name').html(getUserLink(conversation, conversations[conversation][2], conversations[conversation][3]));
$('#pageShow').text("" + page.toString() + ""); $('#pageShow').text("" + page.toString() + "");
$.get('', { $.get('/user_msg', {
getHistory: '', getHistory: '',
conversationName: conversation, conversationName: conversation,
pageNumber: page pageNumber: page
@ -236,29 +320,35 @@ if (isset($_POST['user_msg'])) {
} }
var message = result[msg]; var message = result[msg];
addBubble(message[0], message[1], message[2], message[3], conversation, page, message[4]); addBubble(message[0], message[1], message[2], message[3], conversation, page, message[4]);
if ((++cnt) + 1 == result.length && F) break; if ((++cnt) + 1 == result.length && F) {
break;
}
} }
if (result.length == 11) ret = true; if (result.length == 11) {
ret = true;
}
bootstrap.Tooltip.jQueryInterface.call($('#history-list [data-bs-toggle="tooltip"]'));
}); });
return ret; return ret;
} }
function refreshConversations() { function refreshConversations() {
$("#conversations").empty(); $("#conversations").empty();
$.get('', { $.get('/user_msg', {
getConversations: "" getConversations: 1
}, function(msg) { }, function(msg) {
var result = JSON.parse(msg); var result = JSON.parse(msg);
for (i in result) { for (i in result) {
var conversation = result[i]; var conversation = result[i];
if (conversation[1] == 1) { if (conversation[1] == 1) {
addButton(conversation[2], conversation[0], conversation[1]); addButton(conversation[2], conversation[0], conversation[1], conversation[3], conversation[4], conversation[5]);
} }
conversations[conversation[2]] = [conversation[0], conversation[3], conversation[4], conversation[5]];
} }
for (i in result) { for (i in result) {
var conversation = result[i]; var conversation = result[i];
if (conversation[1] == 0) { if (conversation[1] == 0) {
addButton(conversation[2], conversation[0], conversation[1]); addButton(conversation[2], conversation[0], conversation[1], conversation[3], conversation[4], conversation[5]);
} }
} }
}); });
@ -267,9 +357,14 @@ if (isset($_POST['user_msg'])) {
function enterConversation(conversationName) { function enterConversation(conversationName) {
var slideTime = 300; var slideTime = 300;
var page = 1; var page = 1;
$("#conversations").hide(slideTime);
var changeAble = refreshHistory(conversationName, page); var changeAble = refreshHistory(conversationName, page);
$("#history").slideDown(slideTime); $('#history').show();
$('#conversations').addClass('d-none d-md-block')
$('#input-message').unbind('keydown').keydown(function(e) {
if (e.keyCode == 13 && e.ctrlKey) {
$('#message-submit').click();
}
});
$('#form-message').unbind("submit").submit(function() { $('#form-message').unbind("submit").submit(function() {
submitMessagePost(conversationName); submitMessagePost(conversationName);
page = 1; page = 1;
@ -279,8 +374,8 @@ if (isset($_POST['user_msg'])) {
}); });
$('#goBack').unbind("click").click(function() { $('#goBack').unbind("click").click(function() {
refreshConversations(); refreshConversations();
$("#history").slideUp(slideTime); $("#history").hide();
$("#conversations").show(slideTime); $("#conversations").removeClass('d-none d-md-block');
return; return;
}); });
$('#pageLeft').unbind("click").click(function() { $('#pageLeft').unbind("click").click(function() {
@ -288,19 +383,11 @@ if (isset($_POST['user_msg'])) {
changeAble = refreshHistory(conversationName, page); changeAble = refreshHistory(conversationName, page);
return false; return false;
}); });
$('#pageLeft2').unbind("click").click(function() {
if (changeAble) page++;
changeAble = refreshHistory(conversationName, page);
});
$('#pageRight').unbind("click").click(function() { $('#pageRight').unbind("click").click(function() {
if (page > 1) page--; if (page > 1) page--;
changeAble = refreshHistory(conversationName, page); changeAble = refreshHistory(conversationName, page);
return false; return false;
}); });
$('#pageRight2').unbind("click").click(function() {
if (page > 1) page--;
changeAble = refreshHistory(conversationName, page);
});
} }
</script> </script>

View File

@ -1116,12 +1116,12 @@ function showCommentReplies(id, replies) {
// Tooltip // Tooltip
$(document).ready(function() { $(document).ready(function() {
[...document.querySelectorAll('[data-bs-toggle="tooltip"]')].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl)); bootstrap.Tooltip.jQueryInterface.call($('[data-bs-toggle="tooltip"]'));
}); });
// Popovers // Popovers
$(document).ready(function() { $(document).ready(function() {
[...document.querySelectorAll('[data-bs-toggle="popover"]')].map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl)); bootstrap.Popover.jQueryInterface.call($('[data-bs-toggle="popover"]'));
}); });
// Copy button // Copy button