feat: 개인 메시지, 외교 메시지 수신 시 toast 알림, 모두 읽음 버튼 추가

This commit is contained in:
2023-03-09 02:20:26 +09:00
parent e404f3145c
commit 1d477a285a
+136 -7
View File
@@ -27,7 +27,7 @@
</BFormSelect>
</div>
<div id="msg_input-col" class="col-12 col-md-8 d-grid">
<input v-model="newMessageText" type="text" maxlength="99" @keydown.enter="sendMessage" class="form-control" />
<input v-model="newMessageText" type="text" maxlength="99" class="form-control" @keydown.enter="sendMessage" />
</div>
<div id="msg_submit-col" class="col-6 col-md-2 d-grid">
<BButton variant="primary" @click="sendMessage">서신전달&amp;갱신</BButton>
@@ -83,7 +83,18 @@
</div>
<div class="PrivateTalk">
<div class="stickyAnchor"></div>
<div class="BoardHeader bg0">개인 메시지</div>
<div class="BoardHeader bg0 d-flex">
<div class="flex-grow-1 align-self-center">개인 메시지</div>
<div>
<BButton
v-if="messagePrivate.length > 0 && latestPrivateMsgToastInfo[2] > latestPrivateMsgToastInfo[1]"
size="sm"
variant="secondary"
@click="readLatestMsg('private')"
>모두 읽음</BButton
>
</div>
</div>
<template v-if="messagePrivate.length == 0">
<div>메시지가 없습니다.</div>
</template>
@@ -107,7 +118,18 @@
</div>
<div class="DiplomacyTalk">
<div class="stickyAnchor"></div>
<div class="BoardHeader bg0">외교 메시지</div>
<div class="BoardHeader bg0 d-flex">
<div class="flex-grow-1 align-self-center">외교 메시지</div>
<div>
<BButton
v-if="messageDiplomacy.length > 0 && latestDiplomacyMsgToastInfo[2] > latestDiplomacyMsgToastInfo[1]"
ize="sm"
variant="secondary"
@click="readLatestMsg('diplomacy')"
>모두 읽음</BButton
>
</div>
</div>
<template v-if="messageDiplomacy.length == 0">
<div>메시지가 없습니다.</div>
</template>
@@ -132,17 +154,27 @@
</div>
</template>
<script lang="ts">
declare const staticValues: {
serverName: string;
serverNick: string;
serverID: string;
mapName: string;
unitSet: string;
};
</script>
<script setup lang="ts">
import { onMounted, ref, toRef, watch, type Ref } from "vue";
import { delay } from "@/util/delay";
import { SammoAPI } from "@/SammoAPI";
import { isString } from "lodash";
import type { MabilboxListResponse, MailboxItem, MsgItem, MsgResponse, MsgType } from "@/defs/API/Message";
import type { MabilboxListResponse, MsgItem, MsgResponse, MsgType } from "@/defs/API/Message";
import MessagePlate from "@/components/MessagePlate.vue";
import { useToast, BFormSelect, BFormSelectOptionGroup } from "bootstrap-vue-3";
import { useToast, BFormSelect } from "bootstrap-vue-3";
import { unwrap } from "@/util/unwrap";
import { isBrightColor } from "@/util/isBrightColor";
const serverID = staticValues.serverID;
const toasts = unwrap(useToast());
const emit = defineEmits<{
@@ -187,12 +219,107 @@ const messageIndexedList: Record<MsgType, Ref<MsgItem[]>> = {
diplomacy: messageDiplomacy,
};
function generateLatestMsgState(msgType: MsgType) {
const storageKey = `state.${serverID}.latestReadMsg.${msgType}`;
const latestReadMsgID = parseInt(localStorage.getItem(storageKey) ?? "0");
const obj = ref<[string | undefined, number, number]>([undefined, latestReadMsgID, latestReadMsgID]);
watch(obj, ([, newMsgID], [, oldMsgID]) => {
if (newMsgID == oldMsgID) {
return;
}
localStorage.setItem(storageKey, newMsgID.toString());
});
return obj;
}
const latestPrivateMsgToastInfo = generateLatestMsgState("private");
const latestDiplomacyMsgToastInfo = generateLatestMsgState("diplomacy");
function readLatestMsg(msgType: MsgType) {
const targetMap = {
private: latestPrivateMsgToastInfo,
diplomacy: latestDiplomacyMsgToastInfo,
public: undefined,
national: undefined,
};
const target = targetMap[msgType];
if (!target) {
return;
}
const [toastID, , lastestReceivedID] = target.value;
if (toastID) {
toasts.remove(toastID);
}
target.value = [undefined, lastestReceivedID, lastestReceivedID];
}
function _updateLatestMsg(msg: MsgItem) {
const msgType = msg.msgType;
//TODO: 메시지함으로 바로 이동하는 기능이 나중에 필요할 것
if (msgType == "private") {
const [toastID, latestMsgID] = latestPrivateMsgToastInfo.value;
if (msg.id <= latestMsgID) {
return;
}
if (toastID) {
toasts.remove(toastID);
}
const newToastID = toasts.show(
{
title: "새로운 개인 메시지",
body: "새로운 개인 메시지가 도착했습니다.",
},
{
delay: 1000 * 60 * 10,
variant: 'warning'
}
).options.id;
latestPrivateMsgToastInfo.value = [newToastID, latestMsgID, msg.id];
return;
}
if (msgType == "diplomacy") {
const [toastID, latestMsgID] = latestDiplomacyMsgToastInfo.value;
if (msg.id <= latestMsgID) {
return;
}
if (toastID) {
toasts.remove(toastID);
}
const newToastID = toasts.show(
{
title: "새로운 외교 메시지",
body: "새로운 외교 메시지가 도착했습니다.",
},
{
delay: 1000 * 60 * 10,
variant: 'warning'
}
).options.id;
latestDiplomacyMsgToastInfo.value = [newToastID, latestMsgID, msg.id];
return;
}
}
function updateLatestMsg(msg: MsgItem[]) {
for (const msgItem of msg) {
if (msgItem.src.id == generalID.value) continue;
_updateLatestMsg(msgItem);
break;
}
}
function processMsg(msg: MsgItem) {
if (msg.option.delete) {
(() => {
const targetID = msg.option.delete;
const targetMsg = messageStorage.get(targetID);
if(!targetMsg){
if (!targetMsg) {
return;
}
targetMsg.option.invalid = true;
@@ -232,6 +359,7 @@ function updateMsgResponse(response: MsgResponse) {
if (msgList.value.length == 0) {
msgList.value = newMsgList;
updateLatestMsg(newMsgList);
continue;
}
@@ -256,6 +384,7 @@ function updateMsgResponse(response: MsgResponse) {
const newMsgTailID = filteredMsgList[filteredMsgList.length - 1].id;
if (newMsgTailID > msgHeadID) {
msgList.value = [...filteredMsgList, ...msgList.value];
updateLatestMsg(filteredMsgList);
continue;
}
@@ -592,7 +721,7 @@ onMounted(async () => {
display: none;
}
.MessageList{
.MessageList {
overflow-y: auto;
overflow-x: hidden;
height: 650px;