เพิ่ม Socket เข้าสู่หน้าหลัก , เปิดห้องแซท , รับ-ส่ง ข้อความ
This commit is contained in:
parent
0a98d96d38
commit
5b081878c4
4 changed files with 131 additions and 48 deletions
|
|
@ -1,13 +1,22 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, onMounted } from "vue";
|
||||
import { ref, watch, onUpdated, onMounted, nextTick } from "vue";
|
||||
import { useSupportStore } from "@/modules/00_support/store/Main.ts";
|
||||
import MessageChat from "@/modules/00_support/components/MessageChat.vue";
|
||||
|
||||
const store = useSupportStore();
|
||||
const currentIssue = ref<string>("");
|
||||
|
||||
const content = ref<string>("");
|
||||
const scrollContainerRef = ref();
|
||||
const readStatus = ref<boolean>(false);
|
||||
|
||||
onUpdated(() => {
|
||||
nextTick(() => {
|
||||
store.scrollToEnd();
|
||||
});
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
store.scrollContainer = scrollContainerRef.value;
|
||||
store.fetchIssue();
|
||||
});
|
||||
</script>
|
||||
|
|
@ -34,22 +43,22 @@ onMounted(async () => {
|
|||
</q-avatar>
|
||||
|
||||
<q-item-section class="q-pl-sm">
|
||||
<q-item-label>สุวิมล คงสวัสดิ์</q-item-label>
|
||||
<q-item-label caption>
|
||||
<q-item-label>{{ currentTitle }}</q-item-label>
|
||||
<!-- <q-item-label caption>
|
||||
<q-icon name="noise_control_off" color="positive" />
|
||||
ออนไลน์
|
||||
</q-item-label>
|
||||
</q-item-label> -->
|
||||
</q-item-section>
|
||||
<q-space />
|
||||
|
||||
<q-btn
|
||||
<!-- <q-btn
|
||||
flat
|
||||
round
|
||||
dense
|
||||
icon="o_videocam"
|
||||
class="q-mr-xs"
|
||||
text-color="primary"
|
||||
/>
|
||||
/> -->
|
||||
<q-btn flat round dense icon="o_info" text-color="grey" />
|
||||
</q-toolbar>
|
||||
</div>
|
||||
|
|
@ -62,7 +71,8 @@ onMounted(async () => {
|
|||
:active="currentIssue === data.id"
|
||||
@click="
|
||||
() => {
|
||||
currentIssue = data.id;
|
||||
store.currentIssue = data.id;
|
||||
store.currentTitle = data.title;
|
||||
store.fetchMessage(data.id);
|
||||
}
|
||||
"
|
||||
|
|
@ -74,8 +84,20 @@ onMounted(async () => {
|
|||
|
||||
<q-item-section class="q-pl-sm">
|
||||
<q-item-label>{{ data.title }}</q-item-label>
|
||||
<q-item-label caption>
|
||||
|
||||
<q-item-label class="flex" caption>
|
||||
{{ data.lastMessage }}
|
||||
|
||||
<q-space />
|
||||
<q-toggle v-model="readStatus" label="test" />
|
||||
<q-badge
|
||||
v-if="readStatus"
|
||||
class=""
|
||||
rounded
|
||||
color="red"
|
||||
label="1"
|
||||
/>
|
||||
<q-icon v-else size="18px" name="done_all" />
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
|
@ -83,9 +105,12 @@ onMounted(async () => {
|
|||
</div>
|
||||
</q-list>
|
||||
</div>
|
||||
<div class="i4 bg-grey-3 q-pa-sm" style="overflow-y: auto">
|
||||
|
||||
<div class="i4 bg-grey-3">
|
||||
<!-- <div class="i4 bg-grey-3 q-pa-sm"> -->
|
||||
<message-chat v-if="currentIssue" />
|
||||
<q-scroll-area ref="scrollContainerRef" style="height: 400px; width: 1fr">
|
||||
<message-chat class="q-pr-md" />
|
||||
</q-scroll-area>
|
||||
</div>
|
||||
<div class="i5 bg-white container-input align-center">
|
||||
<div class="input-file">
|
||||
|
|
@ -101,6 +126,12 @@ onMounted(async () => {
|
|||
standout="bg-teal text-white"
|
||||
label="Aa"
|
||||
v-model="content"
|
||||
@keydown.enter.prevent="
|
||||
() => {
|
||||
store.sendMessage(content, store.currentIssue);
|
||||
content = '';
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
@ -108,7 +139,8 @@ onMounted(async () => {
|
|||
<q-btn
|
||||
@click="
|
||||
() => {
|
||||
store.sendMessage(content, currentIssue);
|
||||
store.sendMessage(content, store.currentIssue);
|
||||
content = '';
|
||||
}
|
||||
"
|
||||
flat
|
||||
|
|
@ -121,6 +153,9 @@ onMounted(async () => {
|
|||
</template>
|
||||
|
||||
<style scoped>
|
||||
.scroll {
|
||||
overflow-y: auto;
|
||||
}
|
||||
.align-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -158,6 +193,7 @@ onMounted(async () => {
|
|||
.i1 {
|
||||
grid-area: search;
|
||||
}
|
||||
|
||||
.i2 {
|
||||
grid-area: toolbar;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,28 @@
|
|||
<script setup lang="ts">
|
||||
import "moment/dist/locale/th";
|
||||
import moment from "moment";
|
||||
import { useSupportStore } from "@/modules/00_support/store/Main";
|
||||
import { ref, onMounted } from "vue";
|
||||
import type { SupportMessageResponse } from "@/modules/00_support/interface/index/Main";
|
||||
import { useSupportStore } from "@/modules/00_support/store/Main";
|
||||
const store = useSupportStore();
|
||||
moment.locale("th");
|
||||
console.log(moment.locale());
|
||||
|
||||
onMounted(() => {});
|
||||
</script>
|
||||
<template>
|
||||
<q-infinite-scroll reverse>
|
||||
<div class="bg-grey-3 q-pb-sm">
|
||||
<q-chat-message label="Sunday, 19th" />
|
||||
<q-chat-message
|
||||
v-if="store.message"
|
||||
v-for="data in store.message?.result.message.reverse()"
|
||||
:id="data.id"
|
||||
avatar="https://cdn.quasar.dev/img/avatar4.jpg"
|
||||
:text="[data.content]"
|
||||
:bg-color="data.fromUserId === store.userId ? 'primary' : 'white'"
|
||||
:text-color="data.fromUserId === store.userId ? 'white' : 'black'"
|
||||
:sent="data.fromUserId === store.userId"
|
||||
:stamp="moment(data.createdAt).fromNow()"
|
||||
/>
|
||||
</div>
|
||||
</q-infinite-scroll>
|
||||
<div class="bg-grey-3 q-pb-sm">
|
||||
<q-chat-message label="Sunday, 19th" />
|
||||
<q-chat-message
|
||||
v-for="(data, index) in store.message?.result.message"
|
||||
:key="index"
|
||||
:id="data.id"
|
||||
avatar="https://cdn.quasar.dev/img/avatar4.jpg"
|
||||
:text="[data.content]"
|
||||
:bg-color="data.fromUserId === store.userId ? 'primary' : 'white'"
|
||||
:text-color="data.fromUserId === store.userId ? 'white' : 'black'"
|
||||
:sent="data.fromUserId === store.userId"
|
||||
:stamp="moment(data.createdAt).fromNow()"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
export interface SupportStatusUser {
|
||||
socketId: string;
|
||||
userId: string;
|
||||
name: string;
|
||||
role: string[];
|
||||
}
|
||||
|
||||
export interface SupportIssueResponse {
|
||||
result: SupportIssue[];
|
||||
page: number;
|
||||
|
|
@ -15,6 +22,7 @@ export interface SupportIssue {
|
|||
status: string;
|
||||
category: SupportIssueCategory;
|
||||
unreadCount: number;
|
||||
lastMessage: string;
|
||||
}
|
||||
|
||||
export interface SupportIssueCategory {
|
||||
|
|
@ -51,4 +59,4 @@ export interface SupportIssueMessage {
|
|||
issueId: string;
|
||||
}
|
||||
|
||||
export type { SupportMessageResponse, SupportIssueResponse };
|
||||
export type { SupportMessageResponse, SupportIssueResponse, SupportStatusUser };
|
||||
|
|
|
|||
|
|
@ -3,14 +3,30 @@ import { ref } from "vue";
|
|||
import { io } from "socket.io-client";
|
||||
import http from "@/plugins/http";
|
||||
import config from "@/app.config";
|
||||
|
||||
import { useCounterMixin } from "@/stores/mixin";
|
||||
import type {
|
||||
SupportMessageResponse,
|
||||
SupportIssueResponse,
|
||||
SupportStatusUser,
|
||||
} from "@/modules/00_support/interface/index/Main";
|
||||
import keycloak from "@/plugins/keycloak";
|
||||
|
||||
export const useSupportStore = defineStore("supportServiceStore", () => {
|
||||
const { showLoader, hideLoader } = useCounterMixin();
|
||||
const userId = ref<string>(keycloak.subject);
|
||||
const issue = ref<SupportIssueResponse>();
|
||||
const message = ref<SupportMessageResponse>();
|
||||
const statusUser = ref<SupportStatusUser>([]);
|
||||
const currentIssue = ref<string>("");
|
||||
const currentTitle = ref<string>("");
|
||||
const items = ref<string>([{}, {}, {}, {}, {}, {}, {}]);
|
||||
const scrollContainer = ref();
|
||||
|
||||
function scrollToEnd() {
|
||||
scrollContainer.value.setScrollPosition("vertical", 10000);
|
||||
}
|
||||
|
||||
const socket = io("http://192.168.1.10:3000/", {
|
||||
auth: { token: keycloak.token },
|
||||
});
|
||||
|
|
@ -19,21 +35,40 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
|
|||
// console.log(users);
|
||||
});
|
||||
|
||||
socket.on("message", (r) => {
|
||||
socket.on("online", (r) => {
|
||||
console.log(r);
|
||||
});
|
||||
const { showLoader, hideLoader } = useCounterMixin();
|
||||
statusUser.value.push({
|
||||
socketId: r.socketId,
|
||||
userId: r.userId,
|
||||
name: r.name,
|
||||
role: r.role,
|
||||
});
|
||||
|
||||
const userId = ref<string>(keycloak.subject);
|
||||
const issue = ref<SupportIssueResponse>();
|
||||
const message = ref<SupportMessageResponse>();
|
||||
const items = ref<string>([{}, {}, {}, {}, {}, {}, {}]);
|
||||
const scrollTargetRef = ref();
|
||||
console.log(statusUser.value);
|
||||
|
||||
// console.log(JSON.stringify(r, null, -2));
|
||||
});
|
||||
|
||||
socket.on("message", (r) => {
|
||||
message.value.result.message.push({
|
||||
id: r.id,
|
||||
fromUserId: r.fromUserId,
|
||||
fromUserName: r.fromUserName,
|
||||
createdAt: r.createdAt,
|
||||
updatedAt: r.updatedAt,
|
||||
content: r.content,
|
||||
read: r.read,
|
||||
issueId: r.issueId,
|
||||
});
|
||||
socket.emit("mark-read", { currentIssue });
|
||||
});
|
||||
|
||||
function sendMessage(content: string, to: string) {
|
||||
console.log(content);
|
||||
console.log(to);
|
||||
socket.emit("message", { to, content });
|
||||
|
||||
setTimeout(() => {
|
||||
scrollToEnd();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
async function fetchMessage(issueId: string) {
|
||||
|
|
@ -47,17 +82,19 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
|
|||
hideLoader();
|
||||
});
|
||||
if (res && res.data) {
|
||||
message.value = res.data;
|
||||
|
||||
console.log(res.data);
|
||||
message.value = await res.data;
|
||||
message.value.result.message.reverse();
|
||||
socket.emit("join-issue", { issueId });
|
||||
socket.emit("mark-read", { issueId });
|
||||
|
||||
setTimeout(() => {
|
||||
scrollToEnd();
|
||||
}, 3);
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchIssue() {
|
||||
showLoader();
|
||||
|
||||
const res = await http
|
||||
.get(config.API.supportIssue)
|
||||
.catch((err) => {
|
||||
|
|
@ -69,7 +106,7 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
|
|||
|
||||
if (res && res.data) {
|
||||
issue.value = res.data;
|
||||
console.log(JSON.stringify(res.data, null, -2));
|
||||
// console.log(JSON.stringify(res.data, null, -2));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +117,10 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
|
|||
fetchIssue,
|
||||
fetchMessage,
|
||||
sendMessage,
|
||||
scrollTargetRef,
|
||||
items,
|
||||
scrollToEnd,
|
||||
scrollContainer,
|
||||
currentIssue,
|
||||
currentTitle,
|
||||
};
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue