update หน้า support user (แยก component)

This commit is contained in:
puri-ph4tt 2024-02-02 17:13:59 +07:00
parent 666fb8e4d9
commit a17625c13c
4 changed files with 437 additions and 124 deletions

View file

@ -0,0 +1,47 @@
<script setup lang="ts">
import "moment/dist/locale/th";
import moment from "moment";
import { useSupportStore } from "@/modules/00_support/store/Main";
const store = useSupportStore();
</script>
<template>
<div class="col-grow q-pt-md q-pb-sm">
<div v-for="(data, index) in store.message?.result.message">
<q-item-label>
<q-chat-message
ref="myElement"
:key="index"
:id="data.id"
avatar="https://cdn.quasar.dev/img/avatar4.jpg"
:text="[data.content]"
:bg-color="data.fromUserId === store.userId ? 'teal' : 'white'"
:text-color="data.fromUserId === store.userId ? 'white' : 'black'"
:sent="data.fromUserId === store.userId"
:stamp="moment(data.createdAt).fromNow()"
/>
</q-item-label>
<q-item-label
v-if="data.fromUserId === store.userId"
class="flex"
caption
>
<q-space />
<div
v-if="
store.messageStatus?.result.some(
(v) =>
new Date(v.lastAccessDate).getTime() >=
new Date(data.createdAt).getTime() &&
index + 1 === store.message?.result.message.length
)
"
>
านเเล
</div>
</q-item-label>
</div>
</div>
</template>

View file

@ -0,0 +1,117 @@
<script setup lang="ts">
import { ref } from "vue";
import { useSupportStore } from "@/modules/00_support/store/Main";
import ChatMessage from "@/modules/00_support/components/ChatMessage.vue";
const store = useSupportStore();
const content = ref<string>("");
function getOnlineStatus(option: "icon" | "status") {
const isAdmin = store.userStatus.some((u) => u.role.includes("admin"));
if (option === "icon") return isAdmin ? "green" : "grey";
if (option === "status") return isAdmin ? "ออนไลน์" : "ออฟไลน์";
}
defineProps({
icon: String,
});
</script>
<template>
<div
class="row q-py-md q-px-lg justify-between items-center"
v-if="store.currentTitle && store.currentTitle.length > 0"
>
<div class="col row">
<div style="border-radius: 50%; border: 1px solid teal">
<q-avatar color="teal-1" text-color="white" size="40px">
<q-icon :name="icon" size="24px" color="teal" />
</q-avatar>
</div>
<div class="col column q-ml-md">
<span class="col text-weight-bold">
{{ store.currentTitle }}
</span>
<span>
<q-icon
name="mdi-circle"
size="10px"
:color="getOnlineStatus('icon')"
/>
{{ getOnlineStatus("status") }}
</span>
</div>
</div>
<div class="col-2 text-right q-gutter-x-md">
<q-icon class="col" name="mdi-video-outline" size="24px" color="teal" />
<q-icon
class="col"
name="mdi-information-outline"
size="24px"
color="grey"
/>
</div>
</div>
<q-separator />
<q-scroll-area
style="background-color: #f5f4f4"
:style="{
height: $q.screen.gt.md ? '600px' : '450px',
}"
>
<div class="q-px-xl row col-12 justify-between">
<chat-message />
</div>
</q-scroll-area>
<q-separator />
<div class="row q-py-md q-px-lg justify-between items-center q-gutter-x-lg">
<div>
<q-btn flat class="col-1">
<q-icon
name="mdi-paperclip"
size="20px"
style="transform: rotate(-125deg)"
color="grey"
/>
</q-btn>
</div>
<div class="col-grow">
<q-input
@keydown.enter.prevent="
() => {
if (store.currentIssue) {
store.sendMessage(content, store.currentIssue);
content = '';
}
}
"
outlined
dense
placeholder="Aa"
v-model="content"
id="message"
>
</q-input>
</div>
<div>
<q-btn
@click="
() => {
if (store.currentIssue) {
store.sendMessage(content, store.currentIssue);
content = '';
}
}
"
flat
class="col-2"
style="color: #009789"
label="ส่งข้อความ"
/>
</div>
</div>
</template>

View file

@ -0,0 +1,114 @@
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { useSupportStore } from "@/modules/00_support/store/Main";
const store = useSupportStore();
const isOpen = ref<boolean>(false);
const title = ref<string>("");
const categoryId = ref<string>("");
const options = ref<{ label: string; value: string }[]>([]);
onMounted(async () => {
await store.fetchIssueCategory();
if (store.issueCategory) {
options.value = store.issueCategory?.result.map((v) => ({
label: v.name,
value: v.id,
}));
}
});
</script>
<template>
<div @click="isOpen = true" class="col-10 row items-center q-pa-md new">
<div class="noactive-avatar">
<div class="new-avatar">
<q-icon name="mdi-plus" size="24px" color="primary" />
</div>
</div>
<div class="col column q-ml-md">
<span class="col text-grey"> เพมเรองปรกษาใหม </span>
</div>
</div>
<!-- Dialog -->
<q-dialog v-model="isOpen">
<q-card class="q-pa-md" style="width: 100%">
<q-card-section class="row items-center">
<div class="text-h6">เพมเรองปรกษาใหม</div>
<q-space />
<q-btn
icon="close"
unelevated
round
dense
v-close-popup
style="color: #ff8080; background-color: #ffdede"
/>
</q-card-section>
<q-card-section class="q-gutter-x-md row">
<q-select
class="col-3"
outlined
dense
emit-value
map-options
v-model="categoryId"
:options="options"
option-value="value"
option-label="label"
label="หมวดหมู่"
/>
<q-input
class="col-grow"
outlined
dense
v-model="title"
label="ชื่อเรื่อง"
/>
</q-card-section>
<q-card-actions align="right">
<q-btn flat v-close-popup label="ยกเลิก" text-color="primary" />
<q-btn
@click="
async () => {
await store.newIssue(title, categoryId);
isOpen = false;
}
"
label="บันทึก"
color="primary"
text-color="white"
/>
</q-card-actions>
</q-card>
</q-dialog>
</template>
<style scoped lang="scss">
.new {
transition: 0.1s ease all;
opacity: 1;
cursor: pointer;
border-left: 5px solid transparent;
&:hover {
background: #ebf9f7;
}
}
.new-avatar {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 50%;
border: 2px dashed #9e9e9e;
}
</style>

View file

@ -1,30 +1,22 @@
<script setup lang="ts">
import { ref } from "vue";
import { onMounted, onUnmounted, ref } 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";
const search = ref("");
const store = useSupportStore();
const items = ref<any>([
{
icon: "mdi-account-settings-outline",
title: "ข้อมูลหลัก",
},
{
icon: "mdi-account-group-outline",
title: "โครงสร้างอัตรากำลัง",
},
{
icon: "mdi-file-account-outline",
title: "ทะเบียนประวัติ",
},
{
icon: "mdi-magnify",
title: "สรรหา",
},
{
icon: "mdi-account-check",
title: "บรรจุแต่งตั้ง",
},
]);
const search = ref<string>("");
const icon = ref<string>("mdi-account-check");
onUnmounted(async () => {
store.socket.disconnect();
});
onMounted(async () => {
store.socket.connect();
store.fetchIssue();
});
</script>
<template>
@ -35,117 +27,118 @@ const items = ref<any>([
<q-card bordered>
<div class="row">
<!-- Left -->
<div class="col-3">
<div class="q-px-md q-py-md">
<q-input
rounded
outlined
dense
placeholder="ค้นหา"
debounce="300"
v-model="search"
id="inputSearch"
>
<template v-slot:prepend
><q-icon name="mdi-magnify" class="pointer" />
</template>
</q-input>
<div class="col-xs-12 col-sm-4 col-md-3">
<div class="q-pt-md bg-white">
<div class="q-px-md q-pb-md">
<q-input
rounded
outlined
dense
placeholder="ค้นหา"
debounce="300"
v-model="search"
id="inputSearch"
>
<template v-slot:prepend
><q-icon name="mdi-magnify" class="pointer" />
</template>
</q-input>
</div>
<q-separator inset />
<div>
<new-issue />
</div>
<q-separator inset />
</div>
<div v-for="(item, j) in items">
<div
class="noactive row q-py-md justify-between items-center q-px-md"
>
<div class="col-11 row items-center">
<div class="noactive-avatar">
<q-avatar color="grey-2" text-color="white" size="40px">
<q-icon :name="item.icon" size="24px" color="teal" />
</q-avatar>
<!-- List Issue -->
<div
class="scrollable-content"
:style="{
'max-height': $q.screen.gt.md ? '600px' : '450px',
}"
>
<div v-for="(item, index) in store.issue?.result" :key="index">
<div
@click="
async () => {
store.currentIssue = item.id;
store.currentTitle = item.title;
store.issue
? (store.issue.result = store.issue.result.map(
(v) => {
if (v.id === item.id) {
v.unreadCount = 0;
}
return v;
}
))
: '';
await store.fetchMessageStatus(item.id);
await store.fetchMessage(item.id);
}
"
: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="noactive-avatar">
<q-avatar color="grey-2" text-color="white" size="40px">
<q-icon :name="icon" size="24px" color="primary" />
</q-avatar>
</div>
<div class="col column q-ml-md">
<span class="col text-weight-bold line-ellipsis">
{{ item.title }}
</span>
<span
class="col text-caption line-ellipsis"
:class="{
'text-weight-bold': item.unreadCount > 0,
'text-grey-8': item.unreadCount > 0,
'text-grey': item.unreadCount === 0,
}"
>{{ item.lastMessage }}</span
>
</div>
</div>
<div class="col column q-ml-md">
<span class="col text-weight-bold">
{{ item.title }}
</span>
<!-- <span class="col">ขอสอบถาม</span> -->
<div class="col-2 items-center text-right">
<q-icon
v-if="item.lastMessage?.length === 0"
name="mdi-send"
size="xs"
color="primary"
/>
<div v-else class="column">
<span class="col text-caption text-grey">20 s</span>
<div class="col">
<q-badge
v-if="item.unreadCount > 0"
rounded
color="negative"
text-color="white"
:label="item.unreadCount"
/>
<q-icon
v-else
name="mdi-check-all"
size="xs"
color="grey"
/>
</div>
</div>
</div>
</div>
<div class="col-1">
<q-icon name="mdi-send" size="xs" color="teal" />
</div>
<q-separator inset />
</div>
<q-separator v-if="j < items.length - 1" inset />
</div>
</div>
<q-separator vertical />
<!-- Right -->
<div class="col-grow">
<div class="row q-py-md q-px-lg justify-between items-center">
<div class="col row">
<div style="border-radius: 50%; border: 1px solid teal">
<q-avatar color="teal-1" text-color="white" size="40px">
<q-icon :name="items[0].icon" size="24px" color="teal" />
</q-avatar>
</div>
<div class="col column q-ml-md">
<span class="col text-weight-bold">
{{ items[0].title }}
</span>
<span>
<q-icon name="mdi-circle" size="10px" color="green" />
ออนไลน
</span>
</div>
</div>
<div class="col-2 text-right q-gutter-x-md">
<q-icon
class="col"
name="mdi-video-outline"
size="24px"
color="teal"
/>
<q-icon
class="col"
name="mdi-information-outline"
size="24px"
color="grey"
/>
</div>
</div>
<q-separator />
<div class="row" style="background-color: #f5f4f4; height: 400px;">asas</div>
<q-separator />
<div class="row q-py-md q-px-lg justify-between items-center">
<div class="col-1 text-left">
<q-btn flat>
<q-icon
name="mdi-paperclip"
size="20px"
style="transform: rotate(-125deg)"
color="grey"
/>
</q-btn>
</div>
<div class="col-grow">
<q-input
outlined
dense
placeholder="Aa"
v-model="search"
id="message"
>
</q-input>
</div>
<div class="col-2">
<q-btn flat style="color: #009789" label="ส่งข้อความ" />
</div>
</div>
<div v-if="$q.screen.gt.xs" class="col-grow">
<form-chat v-if="store.currentIssue.length !== 0" :icon="icon" />
</div>
</div>
</q-card>
@ -156,14 +149,16 @@ const items = ref<any>([
<style scoped lang="scss">
.noactive {
transition: 0.1s ease;
transition: 0.1s ease all;
opacity: 1;
cursor: pointer;
border-left: 5px solid transparent;
&:hover {
background: #ebf9f7;
.noactive-avatar {
transition: 0.1s ease all;
border-radius: 50%;
border: 1px solid teal;
}
@ -174,4 +169,44 @@ const items = ref<any>([
border-radius: 50%;
border: 1px solid #f5f4f4;
}
.active {
background: #ebf9f7;
border-left: 5px solid #03a898;
& {
.noactive-avatar {
border-radius: 50%;
border: 1px solid #03a898;
}
}
}
.line-ellipsis {
display: block;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
max-width: 90%;
}
.scrollable-content {
overflow: hidden;
overflow-y: scroll;
}
.scrollable-content::-webkit-scrollbar {
width: 0.3em;
}
.scrollable-content::-webkit-scrollbar-track {
background-color: #f5f4f4;
}
.scrollable-content::-webkit-scrollbar-thumb {
background-color: #c5c3c2;
}
.scrollable-content::-webkit-scrollbar-thumb:hover {
background-color: #7a7b7b;
}
</style>