เพิ่มฟัง์ชันและ api การค้นหาหัวข้อปัญหา (support)
This commit is contained in:
parent
12ac44c7c2
commit
7ac8cbc87c
3 changed files with 105 additions and 31 deletions
|
|
@ -4,9 +4,21 @@ const support = `${env.API_URL_SUPPORT}`;
|
|||
|
||||
export default {
|
||||
supportMessageStatus: (id: string) => `${support}/issue/${id}/message-status`,
|
||||
|
||||
supportMessage: (id: string, pageSize: number = 999, page: number = 1) =>
|
||||
`${support}/issue/${id}/message?pageSize=${pageSize}&page=${page}`,
|
||||
|
||||
supportIssueUserId: (userId: string) => `${support}/issue?userId=${userId}`,
|
||||
supportIssue: `${support}/issue`,
|
||||
|
||||
supportIssue: (pageSize: number = 999, page: number = 1) =>
|
||||
`${support}/issue?pageSize=${pageSize}&page=${page}`,
|
||||
|
||||
supportSearchIssue: (
|
||||
search: string,
|
||||
pageSize: number = 999,
|
||||
page: number = 1
|
||||
) => `${support}/issue?pageSize=${pageSize}&page=${page}&search=${search}`,
|
||||
|
||||
supportIssueCategory: `${support}/issue-category`,
|
||||
supportNewIssue: `${support}/issue`,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import { useCounterMixin } from "@/stores/mixin";
|
|||
export const useSupportStore = defineStore("supportServiceStore", () => {
|
||||
const { showLoader, hideLoader, messageError } = useCounterMixin();
|
||||
const $q = useQuasar();
|
||||
const icon = ref<string>("mdi-account-check");
|
||||
const userId = ref<string | undefined>(keycloak.subject);
|
||||
const userStatus = ref<SupportUserStatus[]>([]);
|
||||
const issue = ref<SupportIssueResponse>();
|
||||
|
|
@ -27,7 +28,7 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
|
|||
const currentIssue = ref<string>("");
|
||||
const currentTitle = ref<string>("");
|
||||
const items = ref<any>([{}, {}, {}, {}, {}, {}, {}]);
|
||||
const scrollTargetRef = ref();
|
||||
const scrollContainer = ref();
|
||||
|
||||
const socket = io("http://192.168.1.10:3000/", {
|
||||
auth: { token: keycloak.token },
|
||||
|
|
@ -67,26 +68,16 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
|
|||
});
|
||||
|
||||
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", { issueId: currentIssue.value });
|
||||
message.value?.result.message.push(r);
|
||||
|
||||
if (issue.value) {
|
||||
issue.value.result = issue.value.result.map((v) => {
|
||||
if (v.id === r.issueId) {
|
||||
v.lastMessage = r.content;
|
||||
}
|
||||
if (v.id === r.issueId) v.lastMessage = r.content;
|
||||
return v;
|
||||
});
|
||||
}
|
||||
|
||||
socket.emit("mark-read", { issueId: currentIssue.value });
|
||||
scrollToEnd();
|
||||
// console.log(r.id);
|
||||
// console.log(message.value?.result.message);
|
||||
});
|
||||
|
|
@ -101,10 +92,17 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
|
|||
// console.log("event(read):", messageStatus.value);
|
||||
});
|
||||
|
||||
function scrollToEnd(position: Number = 1) {
|
||||
setTimeout(() => {
|
||||
scrollContainer.value?.setScrollPercentage("vertical", position);
|
||||
}, 150);
|
||||
}
|
||||
|
||||
function sendMessage(content: string, to: string) {
|
||||
// console.log(content);
|
||||
// console.log(to);
|
||||
socket.emit("message", { to, content });
|
||||
scrollToEnd();
|
||||
}
|
||||
|
||||
async function fetchMessageStatus(issueId: string) {
|
||||
|
|
@ -138,6 +136,7 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
|
|||
message.value?.result.message.reverse();
|
||||
socket.emit("join-issue", { issueId });
|
||||
socket.emit("mark-read", { issueId });
|
||||
scrollToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +185,7 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
|
|||
};
|
||||
|
||||
const res = await http
|
||||
.post(config.API.supportIssue, requestBody)
|
||||
.post(config.API.supportNewIssue, requestBody)
|
||||
.catch((err) => {
|
||||
messageError($q, err);
|
||||
})
|
||||
|
|
@ -200,6 +199,18 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
|
|||
}
|
||||
}
|
||||
|
||||
async function searchIssue(searchData: string) {
|
||||
const res = await http
|
||||
.get(config.API.supportSearchIssue(searchData))
|
||||
.catch((err) => {
|
||||
messageError($q, err);
|
||||
});
|
||||
if (res && res.data) {
|
||||
issue.value = res.data;
|
||||
// console.log(issue.value);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
userId,
|
||||
issue,
|
||||
|
|
@ -215,8 +226,10 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
|
|||
fetchMessage,
|
||||
sendMessage,
|
||||
newIssue,
|
||||
scrollTargetRef,
|
||||
searchIssue,
|
||||
items,
|
||||
socket,
|
||||
scrollContainer,
|
||||
icon,
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,13 +1,31 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, ref } from "vue";
|
||||
import { onMounted, onUnmounted, ref, watch } from "vue";
|
||||
import { useSupportStore } from "@/modules/00_support/store/Main";
|
||||
import FormChat from "@/modules/00_support/components/FormChat.vue";
|
||||
import NewIssue from "@/modules/00_support/components/NewIssue.vue";
|
||||
import moment from "moment";
|
||||
|
||||
const store = useSupportStore();
|
||||
const searchData = ref<string>("");
|
||||
|
||||
const search = ref<string>("");
|
||||
const icon = ref<string>("mdi-account-check");
|
||||
function dateIssue(timestamp: string): string {
|
||||
const parsedTimestamp = moment(timestamp);
|
||||
const diff = moment().diff(parsedTimestamp);
|
||||
|
||||
if (diff < 1000) {
|
||||
return "just now";
|
||||
} else if (diff < 60000) {
|
||||
return `${Math.floor(diff / 1000)}s`;
|
||||
} else if (diff < 3600000) {
|
||||
return `${Math.floor(diff / 60000)}m`;
|
||||
} else if (diff < 86400000) {
|
||||
return `${Math.floor(diff / 3600000)}h`;
|
||||
} else {
|
||||
const beYear = parsedTimestamp.year() + 543;
|
||||
const formattedDate = parsedTimestamp.clone().year(beYear).format("DD MMM");
|
||||
return formattedDate;
|
||||
}
|
||||
}
|
||||
|
||||
onUnmounted(async () => {
|
||||
store.socket.disconnect();
|
||||
|
|
@ -17,6 +35,10 @@ onMounted(async () => {
|
|||
store.socket.connect();
|
||||
store.fetchIssue();
|
||||
});
|
||||
|
||||
watch(searchData, () => {
|
||||
store.searchIssue(searchData.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -28,6 +50,7 @@ onMounted(async () => {
|
|||
<div class="row">
|
||||
<!-- Left -->
|
||||
<div class="col-xs-12 col-sm-4 col-md-3">
|
||||
<!-- New -->
|
||||
<div class="q-pt-md bg-white">
|
||||
<div class="q-px-md q-pb-md">
|
||||
<q-input
|
||||
|
|
@ -36,8 +59,9 @@ onMounted(async () => {
|
|||
dense
|
||||
placeholder="ค้นหา"
|
||||
debounce="300"
|
||||
v-model="search"
|
||||
v-model="searchData"
|
||||
id="inputSearch"
|
||||
@keydown.enter.prevent="store.searchIssue(searchData)"
|
||||
>
|
||||
<template v-slot:prepend
|
||||
><q-icon name="mdi-magnify" class="pointer" />
|
||||
|
|
@ -49,6 +73,25 @@ onMounted(async () => {
|
|||
<new-issue />
|
||||
</div>
|
||||
<q-separator inset />
|
||||
<!-- No Issue -->
|
||||
<div
|
||||
v-if="store.issue?.result.length === 0"
|
||||
class="col-10 row items-center q-pa-md new"
|
||||
>
|
||||
<div class="noactive-avatar">
|
||||
<q-avatar
|
||||
color="transparent"
|
||||
text-color="white"
|
||||
size="40px"
|
||||
>
|
||||
<q-icon name="mdi-close" size="24px" color="negative" />
|
||||
</q-avatar>
|
||||
</div>
|
||||
|
||||
<div class="col column q-ml-md">
|
||||
<span class="col text-grey"> ไม่พบเรื่องปรึกษา </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- List Issue -->
|
||||
|
|
@ -81,10 +124,14 @@ onMounted(async () => {
|
|||
:class="{ active: store.currentIssue === item.id }"
|
||||
class="noactive row q-py-md justify-between items-center q-px-md"
|
||||
>
|
||||
<div class="col-10 row items-center">
|
||||
<div class="col-9 row items-center">
|
||||
<div class="noactive-avatar">
|
||||
<q-avatar color="grey-2" text-color="white" size="40px">
|
||||
<q-icon :name="icon" size="24px" color="primary" />
|
||||
<q-icon
|
||||
:name="store.icon"
|
||||
size="24px"
|
||||
color="primary"
|
||||
/>
|
||||
</q-avatar>
|
||||
</div>
|
||||
<div class="col column q-ml-md">
|
||||
|
|
@ -102,7 +149,7 @@ onMounted(async () => {
|
|||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2 items-center text-right">
|
||||
<div class="col-3 items-center text-right">
|
||||
<q-icon
|
||||
v-if="item.lastMessage?.length === 0"
|
||||
name="mdi-send"
|
||||
|
|
@ -110,7 +157,9 @@ onMounted(async () => {
|
|||
color="primary"
|
||||
/>
|
||||
<div v-else class="column">
|
||||
<span class="col text-caption text-grey">20 s</span>
|
||||
<span class="col text-caption text-grey">{{
|
||||
dateIssue(item.updatedAt)
|
||||
}}</span>
|
||||
<div class="col">
|
||||
<q-badge
|
||||
v-if="item.unreadCount > 0"
|
||||
|
|
@ -138,7 +187,7 @@ onMounted(async () => {
|
|||
|
||||
<!-- Right -->
|
||||
<div v-if="$q.screen.gt.xs" class="col-grow">
|
||||
<form-chat v-if="store.currentIssue.length !== 0" :icon="icon" />
|
||||
<form-chat v-if="store.currentIssue.length !== 0" />
|
||||
</div>
|
||||
</div>
|
||||
</q-card>
|
||||
|
|
@ -160,7 +209,7 @@ onMounted(async () => {
|
|||
.noactive-avatar {
|
||||
transition: 0.1s ease all;
|
||||
border-radius: 50%;
|
||||
border: 1px solid teal;
|
||||
border: 1px solid $primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -172,11 +221,11 @@ onMounted(async () => {
|
|||
|
||||
.active {
|
||||
background: #ebf9f7;
|
||||
border-left: 5px solid #03a898;
|
||||
border-left: 5px solid $primary;
|
||||
& {
|
||||
.noactive-avatar {
|
||||
border-radius: 50%;
|
||||
border: 1px solid #03a898;
|
||||
border: 1px solid $primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue