Logs: เลือก วัน เวลา ช่วงเวลา + sort เวลา

This commit is contained in:
oat_dev 2024-07-31 15:53:14 +07:00
parent 65d7c05e9b
commit 6e2603c734
4 changed files with 309 additions and 139 deletions

View file

@ -21,7 +21,6 @@ const columns = ref<QTableProps["columns"]>([
name: "startTimeStamp",
align: "left",
label: "เวลา",
sortable: true,
field: "startTimeStamp",
headerStyle: "font-size: 14px",
format: (v) => date2Thai(v, false, true),
@ -33,7 +32,6 @@ const columns = ref<QTableProps["columns"]>([
name: "username",
align: "left",
label: "ผู้ใช้",
sortable: true,
field: "username",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
@ -44,7 +42,6 @@ const columns = ref<QTableProps["columns"]>([
name: "host",
align: "left",
label: "Host",
sortable: true,
field: "host",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
@ -55,7 +52,6 @@ const columns = ref<QTableProps["columns"]>([
name: "endpoint",
align: "left",
label: "Endpoint",
sortable: true,
field: "endpoint",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
@ -66,7 +62,6 @@ const columns = ref<QTableProps["columns"]>([
name: "method",
align: "left",
label: "Method",
sortable: true,
field: "method",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
@ -77,7 +72,6 @@ const columns = ref<QTableProps["columns"]>([
name: "responseCode",
align: "left",
label: "Response Code",
sortable: true,
field: "responseCode",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
@ -88,7 +82,6 @@ const columns = ref<QTableProps["columns"]>([
name: "logType",
align: "left",
label: "สถานะ",
sortable: true,
field: "logType",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
@ -100,7 +93,6 @@ const columns = ref<QTableProps["columns"]>([
name: "responseDescription",
align: "left",
label: "ข้อความ",
sortable: true,
field: "responseDescription",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
@ -110,13 +102,18 @@ const columns = ref<QTableProps["columns"]>([
{
name: "dataDiff",
align: "left",
label: "ข้อมูลที่เปลี่ยนแปลง",
label: "รายละเอียด",
field: "dataDiff",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
const startTime = ref<string>();
const startDate = ref<string>("");
const endTime = ref<string>();
const sortTime = ref<"desc" | "asc">("desc");
const endDate = ref<string>("");
const openDialog = ref<boolean>(false);
const currentlogData =
ref<Omit<ResLog, "endTimeStamp" | "tId" | "processTime" | "systemName">>();
@ -166,7 +163,15 @@ function handleScroll() {
search: inputSearch.value ?? undefined,
systemName: systemName.value ?? undefined,
searchAfter: searchAfter.value ?? undefined,
date: date.value,
date: new Date(startDate.value),
startDate:
startDate.value.split("T")[0] === endDate.value.split("T")[0]
? undefined
: new Date(startDate.value),
endDate:
startDate.value.split("T")[0] === endDate.value.split("T")[0]
? undefined
: new Date(endDate.value),
},
true
);
@ -179,6 +184,24 @@ function handleScroll() {
const infiniteScroll = handleScroll();
function selectedDate() {
startDate.value = date.value[0].toISOString();
endDate.value = date.value[1].toISOString();
if (!!startTime.value) {
replaceTimeInISOString(startDate.value, startTime.value, "start");
} else {
const date = new Date(startDate.value);
date.setHours(0, 0, 0, 0);
startDate.value = date.toISOString();
}
if (!!endTime.value) {
replaceTimeInISOString(endDate.value, endTime.value, "end");
} else {
const date = new Date(endDate.value);
date.setHours(23, 59, 59, 999);
endDate.value = date.toISOString();
}
logData.value = [];
searchAfter.value = undefined;
storeData.fetchLog(
@ -187,7 +210,16 @@ function selectedDate() {
search: inputSearch.value ?? undefined,
systemName: systemName.value ?? undefined,
searchAfter: searchAfter.value ?? undefined,
date: date.value,
sort: sortTime.value,
date: new Date(startDate.value),
startDate:
startDate.value.split("T")[0] === endDate.value.split("T")[0]
? undefined
: new Date(startDate.value),
endDate:
startDate.value.split("T")[0] === endDate.value.split("T")[0]
? undefined
: new Date(endDate.value),
},
true
);
@ -211,8 +243,38 @@ function classColorMethod(val: string) {
}
}
function replaceTimeInISOString(isoString: string, time: string, type: string) {
const [datePart] = isoString.split("T");
const [hours, minutes] = time.split(":").map(Number);
const newDate = new Date(isoString);
newDate.setUTCHours(hours - 7);
newDate.setUTCMinutes(minutes);
newDate.setUTCSeconds(0);
newDate.setUTCMilliseconds(0);
if (type === "start") {
startDate.value = newDate.toISOString();
} else {
endDate.value = newDate.toISOString();
}
}
function dateThaiRange(val: [Date, Date]) {
if (val === null) {
} else if (date2Thai(val[0]) === date2Thai(val[1])) {
return `${date2Thai(val[0])}`;
} else {
return `${date2Thai(val[0])} - ${date2Thai(val[1])} `;
}
}
onMounted(() => {
systemName.value = route.query.system as string;
startDate.value = date.value[0].toISOString();
endDate.value = date.value[1].toISOString();
});
</script>
@ -224,6 +286,8 @@ onMounted(() => {
v-model="date"
:locale="'th'"
autoApply
range
:class="$q.screen.gt.sm ? 'col-3' : 'col-5'"
:enableTimePicker="false"
@update:modelValue="selectedDate"
week-start="0"
@ -235,8 +299,9 @@ onMounted(() => {
<template #trigger>
<q-input
outlined
style="min-width: 250px"
dense
:model-value="date2Thai(date ?? new Date())"
:model-value="dateThaiRange(date)"
hide-bottom-space
>
<template v-slot:prepend>
@ -246,6 +311,44 @@ onMounted(() => {
</q-input>
</template>
</datepicker>
<div class="q-pl-sm row">
<div class="row items-center">
งแต
<q-input
v-model="startTime"
outlined
clearable
@update:model-value="
(v:string) => {
replaceTimeInISOString(startDate,v,'start'),
selectedDate()
}
"
hide-bottom-space
dense
class="q-px-sm"
type="time"
/>
</div>
<div class="row items-center">
<q-input
v-model="endTime"
outlined
clearable
hide-bottom-space
@update:model-value="
(v:string) => {
replaceTimeInISOString(endDate,v,'end'),
selectedDate()
}
"
dense
class="q-px-sm"
type="time"
/>
</div>
</div>
<q-space />
<div class="items-center q-gutter-md" style="display: flex">
<!-- นหาขอความใน table -->
@ -260,7 +363,15 @@ onMounted(() => {
size: size ?? undefined,
search: inputSearch ?? undefined,
systemName: systemName ?? undefined,
date: date ?? undefined,
date: new Date(startDate),
startDate:
startDate.split('T')[0] === endDate.split('T')[0]
? undefined
: new Date(startDate),
endDate:
startDate.split('T')[0] === endDate.split('T')[0]
? undefined
: new Date(endDate),
})
"
outlined
@ -290,6 +401,7 @@ onMounted(() => {
/>
</div>
</div>
<div class="q-pa-md">
<div style="max-height: 70vh; overflow: scroll" @scroll="infiniteScroll">
<d-table
@ -309,7 +421,39 @@ onMounted(() => {
<template v-slot:header="props">
<q-tr :props="props">
<q-th v-for="col in props.cols" :key="col.name" :props="props">
<span class="text-weight-medium">{{ col.label }}</span>
<div
v-if="col.name === 'startTimeStamp'"
class="text-weight-medium"
>
{{ col.label }}
<q-btn
v-if="sortTime === 'desc'"
flat
round
size="8px"
icon="mdi-arrow-up"
@click="
() => {
sortTime = 'asc';
selectedDate();
}
"
/>
<q-btn
v-else
flat
round
size="8px"
icon="mdi-arrow-down"
@click="
() => {
sortTime = 'desc';
selectedDate();
}
"
/>
</div>
<span v-else class="text-weight-medium">{{ col.label }}</span>
</q-th>
</q-tr>
</template>
@ -365,7 +509,7 @@ onMounted(() => {
<q-tooltip> {{ col.value }} </q-tooltip>
</div>
<div v-else-if="col.name === 'dataDiff' && !!col.value">
<div v-else-if="col.name === 'dataDiff'">
<q-btn
dense
flat
@ -387,6 +531,8 @@ onMounted(() => {
responseDescription: props.row.responseDescription,
sequence: props.row.sequence,
dataDiff: props.row.dataDiff,
input: props.row.input,
output: props.row.output,
};
openDialog = true;
}
@ -419,139 +565,158 @@ onMounted(() => {
style="max-width: 100%"
>
<div style="border: #f0ecec 1px solid; border-radius: 7px">
<div
class="col row"
:class="{ 'bg-grey-3': index % 2 }"
v-for="(item, key, index) in currentlogData"
:key="key"
style="border-bottom: #f0ecec 1px solid; min-height: 40px"
>
<template :key="key" v-for="(item, key, index) in currentlogData">
<div
class="col q-pl-sm text-bold"
:class="{
'self-center': key !== 'dataDiff' && key !== 'sequence',
'q-pt-md': key === 'dataDiff',
}"
style="max-width: 150px"
class="col row"
:class="{ 'bg-grey-3': index % 2 }"
style="border-bottom: #f0ecec 1px solid"
v-if="!!item"
>
{{
{
startTimeStamp: "เวลา",
username: "ผู้ใช้",
host: "Host",
endpoint: "Endpoint",
method: "Method",
responseCode: "Response Code",
logType: "สถานะ",
responseDescription: "ข้อความ",
sequence: "ลำดับการทำงาน",
dataDiff: "ข้อมูลที่เปลี่ยนแปลง",
}[key] || key
}}
</div>
<div
class="self-center"
v-if="key === 'startTimeStamp' && typeof item === 'string'"
>
{{ date2Thai(new Date(item), true, true) }}
</div>
<div class="self-center" v-if="key === 'method'">
<q-badge text-color="blue" style="background-color: #f0ecec">{{
item ?? "-"
}}</q-badge>
</div>
<div class="self-center" v-else-if="key === 'logType'">
<q-badge
text-color="white"
:color="
item === 'error' ? 'red' : item === 'info' ? 'primary' : 'warning'
"
>{{ item ?? "-" }}</q-badge
<div
class="col q-pl-sm text-bold q-pa-sm"
:class="{
'self-center': ![
'dataDiff',
'input',
'output',
'sequence',
].includes(key),
}"
style="max-width: 150px"
>
</div>
<div class="col q-pr-md" v-else-if="key === 'sequence'">
<div v-for="(row, index) in item">
<div class="text-subtitle1 text-bold">ลำดบท {{ index + 1 }}</div>
<div
class="q-pa-md q-mb-md"
style="border: 1px solid hsla(0 0% 0% / 0.1); border-radius: 7px"
{{
{
startTimeStamp: "เวลา",
username: "ผู้ใช้",
host: "Host",
endpoint: "Endpoint",
method: "Method",
responseCode: "Response Code",
logType: "สถานะ",
responseDescription: "ข้อความ",
sequence: "ลำดับการทำงาน",
dataDiff: "ข้อมูลที่เปลี่ยนแปลง",
input: "ข้อมูลเข้า",
output: "ข้อมูลออก",
}[key] || key
}}
</div>
<div
class="self-center"
v-if="key === 'startTimeStamp' && typeof item === 'string'"
>
{{ date2Thai(new Date(item), true, true) }}
</div>
<div class="self-center" v-if="key === 'method'">
<q-badge text-color="blue" style="background-color: #f0ecec">{{
item ?? "-"
}}</q-badge>
</div>
<div class="self-center" v-else-if="key === 'logType'">
<q-badge
text-color="white"
:color="
item === 'error'
? 'red'
: item === 'info'
? 'primary'
: 'warning'
"
>{{ item ?? "-" }}</q-badge
>
<div class="row" v-for="(value, key) in row" :key="key">
<div v-if="typeof key === 'string' && key === 'query'">
{{ `${key}: ` }}
<div
class="q-pa-md q-mt-sm"
style="
background-color: hsla(0 0% 0% / 0.07);
color: hsl(0 0% 30%);
border: 1px solid hsla(0 0% 0% / 0.1);
border-radius: 7px;
"
v-for="q in value"
>
{{ `${q}` }}
</div>
</div>
<div v-else-if="typeof key === 'string' && key === 'request'">
{{ `${key}: ` }}
<div
class="q-pa-md q-mt-sm"
style="
background-color: hsla(0 0% 0% / 0.07);
color: hsl(0 0% 30%);
border: 1px solid hsla(0 0% 0% / 0.1);
border-radius: 7px;
max-width: 60vw;
word-wrap: break-word;
"
>
<div v-for="(req, k) in value">
{{ `${k}: ${req}` }}
</div>
<div class="col q-pr-md" v-else-if="key === 'sequence'">
<div v-for="(row, index) in item">
<div class="text-subtitle1 text-bold">
ลำดบท {{ index + 1 }}
</div>
<div
class="q-pa-md q-mb-md"
style="
border: 1px solid hsla(0 0% 0% / 0.1);
border-radius: 7px;
"
>
<div class="row" v-for="(value, key) in row" :key="key">
<div v-if="typeof key === 'string' && key === 'query'">
{{ `${key}: ` }}
<div
class="q-pa-md q-mt-sm"
style="
background-color: hsla(0 0% 0% / 0.07);
color: hsl(0 0% 30%);
border: 1px solid hsla(0 0% 0% / 0.1);
border-radius: 7px;
"
v-for="q in value"
>
{{ `${q}` }}
</div>
</div>
</div>
<div v-else>
{{ `${key}: ${value}` }}
<div v-else-if="typeof key === 'string' && key === 'request'">
{{ `${key}: ` }}
<div
class="q-pa-md q-mt-sm"
style="
background-color: hsla(0 0% 0% / 0.07);
color: hsl(0 0% 30%);
border: 1px solid hsla(0 0% 0% / 0.1);
border-radius: 7px;
max-width: 60vw;
word-wrap: break-word;
"
>
<div v-for="(req, k) in value">
{{ `${k}: ${req}` }}
</div>
</div>
</div>
<div v-else>
{{ `${key}: ${value}` }}
</div>
</div>
</div>
</div>
</div>
<div
class="col self-center"
v-if="
key !== 'dataDiff' &&
key !== 'method' &&
key !== 'logType' &&
key !== 'startTimeStamp' &&
key !== 'sequence' &&
key !== 'input' &&
key !== 'output'
"
>
{{ item }}
</div>
<div
v-if="
item &&
typeof item === 'object' &&
'before' in item &&
'after' in item
"
class="col"
>
<code-diff
:old-string="JSON.stringify(JSON.parse(item.before), null, 4)"
:new-string="JSON.stringify(JSON.parse(item.after), null, 4)"
output-format="side-by-side"
/>
</div>
<div
class="col q-py-sm"
v-if="(item && key === 'input') || key === 'output'"
>
<pre style="margin: 0; max-width: 100%; overflow-x: auto">{{
item
}}</pre>
</div>
</div>
<div
class="col self-center"
v-if="
key !== 'dataDiff' &&
key !== 'method' &&
key !== 'logType' &&
key !== 'startTimeStamp' &&
key !== 'sequence'
"
>
{{ item }}
</div>
<div
v-if="
item &&
typeof item === 'object' &&
'before' in item &&
'after' in item
"
class="col"
>
<code-diff
:old-string="JSON.stringify(JSON.parse(item.before), null, 4)"
:new-string="JSON.stringify(JSON.parse(item.after), null, 4)"
output-format="side-by-side"
/>
</div>
</div>
</template>
</div>
</DialogDataDiff>
</template>

View file

@ -30,6 +30,8 @@ interface ResLog {
responseDescription: string; //
sequence: Record<string, any>;
tId: string;
input: string;
output: string;
}
export type { ResRound, ResLog };

View file

@ -24,7 +24,7 @@ export const useDataStore = defineStore("logStore", () => {
const logData = ref<ResLog[]>([]);
const systemName = ref<string>();
const searchAfter = ref<number>();
const date = ref<Date>(new Date());
const date = ref<[Date, Date]>([new Date(), new Date()]);
async function fetchLog(
opts?: {
size?: number;
@ -32,6 +32,9 @@ export const useDataStore = defineStore("logStore", () => {
searchAfter?: number;
systemName?: string;
date?: Date;
sort?: string;
startDate?: Date;
endDate?: Date;
},
isBottom?: boolean
) {

View file

@ -113,7 +113,7 @@ onMounted(async () => {
await storeData.fetchLog({
size: size.value,
systemName: systemName.value ?? undefined,
date: date.value,
date: date.value[0],
});
if (route.query.system) {
const a = menuList.value.find((v) => {