@7365admin1/layer-common 3.0.29 → 3.0.30-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish-staging.yml +36 -0
- package/components/Nfc/NFCPatrolReportMain.vue +2 -0
- package/components/Nfc/PatrolReport/DailyReportTab.vue +10 -4
- package/components/Nfc/PatrolReport/MonthlyReportTab.vue +3 -1
- package/components/Nfc/PatrolReport/PatrolReportTab.vue +6 -0
- package/components/VisitorManagement.vue +1 -0
- package/composables/useNFCPatrolDailyReport.ts +84 -4
- package/composables/useNFCPatrolLog.ts +4 -1
- package/composables/useNFCPatrolMonthlyReport.ts +90 -4
- package/composables/useNFCPatrolReport.ts +125 -25
- package/composables/useNFCPatrolReportFilters.ts +9 -1
- package/package.json +1 -1
- package/types/nfc-patrol-report.ts +2 -2
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: Publish Staging
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- staging
|
|
6
|
+
|
|
7
|
+
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
publish:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- uses: actions/setup-node@v4
|
|
16
|
+
with:
|
|
17
|
+
node-version: 20.x
|
|
18
|
+
cache: "yarn"
|
|
19
|
+
cache-dependency-path: yarn.lock
|
|
20
|
+
|
|
21
|
+
- run: yarn install --immutable
|
|
22
|
+
|
|
23
|
+
- run: yarn build
|
|
24
|
+
|
|
25
|
+
- name: Create .npmrc for publishing
|
|
26
|
+
run: |
|
|
27
|
+
echo '//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}' > ~/.npmrc
|
|
28
|
+
|
|
29
|
+
- name: Set staging prerelease version
|
|
30
|
+
run: |
|
|
31
|
+
BASE=$(node -p "const [x,y,z]=require('./package.json').version.split('-')[0].split('.'); [x,y,+z+1].join('.')")
|
|
32
|
+
npm version "$BASE-staging.${{ github.run_number }}" --no-git-tag-version
|
|
33
|
+
node -p "'Publishing ' + require('./package.json').version"
|
|
34
|
+
|
|
35
|
+
- name: Publish to npm with staging tag
|
|
36
|
+
run: npm publish --tag staging --registry https://registry.npmjs.org
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
<v-window-item value="daily">
|
|
36
36
|
<DailyReportTab
|
|
37
37
|
:active="activeTab === 'daily'"
|
|
38
|
+
:site="site"
|
|
38
39
|
:filters="filters"
|
|
39
40
|
:options="options"
|
|
40
41
|
@update:filters="updateFilters"
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
<v-window-item value="monthly">
|
|
46
47
|
<MonthlyReportTab
|
|
47
48
|
:active="activeTab === 'monthly'"
|
|
49
|
+
:site="site"
|
|
48
50
|
:filters="filters"
|
|
49
51
|
:options="options"
|
|
50
52
|
@update:filters="updateFilters"
|
|
@@ -16,10 +16,12 @@
|
|
|
16
16
|
</template>
|
|
17
17
|
|
|
18
18
|
<ReportEmptyState
|
|
19
|
-
v-else-if="!loading"
|
|
20
|
-
title="No Daily Report
|
|
21
|
-
message="
|
|
19
|
+
v-else-if="!loading && notFound"
|
|
20
|
+
title="No Daily Report"
|
|
21
|
+
message="No patrol log for this date"
|
|
22
22
|
/>
|
|
23
|
+
|
|
24
|
+
<ReportEmptyState v-else-if="!loading" />
|
|
23
25
|
</div>
|
|
24
26
|
</template>
|
|
25
27
|
|
|
@@ -36,6 +38,7 @@ import SummaryReportTable from "./SummaryReportTable.vue";
|
|
|
36
38
|
|
|
37
39
|
const props = defineProps<{
|
|
38
40
|
active: boolean;
|
|
41
|
+
site: string; // ✅ thêm
|
|
39
42
|
filters: NFCPatrolReportFilters;
|
|
40
43
|
options: NFCPatrolReportFilterOptions;
|
|
41
44
|
}>();
|
|
@@ -45,7 +48,10 @@ defineEmits<{
|
|
|
45
48
|
export: [];
|
|
46
49
|
}>();
|
|
47
50
|
|
|
48
|
-
const { report, loading, fetchReport } = useNFCPatrolDailyReport(
|
|
51
|
+
const { report, loading, notFound, fetchReport } = useNFCPatrolDailyReport(
|
|
52
|
+
props.filters,
|
|
53
|
+
props.site, // ✅
|
|
54
|
+
);
|
|
49
55
|
|
|
50
56
|
watch(
|
|
51
57
|
() => [props.filters.route, props.filters.timeRange, props.filters.date, props.active],
|
|
@@ -36,6 +36,7 @@ import SummaryReportTable from "./SummaryReportTable.vue";
|
|
|
36
36
|
|
|
37
37
|
const props = defineProps<{
|
|
38
38
|
active: boolean;
|
|
39
|
+
site: string;
|
|
39
40
|
filters: NFCPatrolReportFilters;
|
|
40
41
|
options: NFCPatrolReportFilterOptions;
|
|
41
42
|
}>();
|
|
@@ -45,7 +46,8 @@ defineEmits<{
|
|
|
45
46
|
export: [];
|
|
46
47
|
}>();
|
|
47
48
|
|
|
48
|
-
const { report, loading, fetchReport } =
|
|
49
|
+
const { report, loading, fetchReport } =
|
|
50
|
+
useNFCPatrolMonthlyReport(props.filters, props.site);
|
|
49
51
|
|
|
50
52
|
watch(
|
|
51
53
|
() => [props.filters.route, props.filters.timeRange, props.filters.date, props.active],
|
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
/>
|
|
23
23
|
</template>
|
|
24
24
|
|
|
25
|
+
<ReportEmptyState
|
|
26
|
+
v-else-if="!loading && notFound"
|
|
27
|
+
title="No Patrol Log"
|
|
28
|
+
message="No patrol log for this date"
|
|
29
|
+
/>
|
|
25
30
|
<ReportEmptyState v-else-if="!loading" />
|
|
26
31
|
|
|
27
32
|
<RemarksDialog v-model="dialogRemarks" :remarks="selectedActivityRemarks" />
|
|
@@ -56,6 +61,7 @@ defineEmits<{
|
|
|
56
61
|
const {
|
|
57
62
|
report,
|
|
58
63
|
loading,
|
|
64
|
+
notFound,
|
|
59
65
|
selectedActivityRemarks,
|
|
60
66
|
dialogRemarks,
|
|
61
67
|
fetchReport,
|
|
@@ -1,19 +1,98 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
NFCPatrolReportFilters,
|
|
3
3
|
NFCPatrolSummaryReport,
|
|
4
|
+
NFCPatrolReportSummaryRow,
|
|
4
5
|
} from "../types/nfc-patrol-report";
|
|
5
|
-
import
|
|
6
|
+
import useNFCPatrolLog from "./useNFCPatrolLog";
|
|
7
|
+
import useSite from "./useSite";
|
|
8
|
+
|
|
9
|
+
interface NFCPatrolLogListResponse {
|
|
10
|
+
items?: Record<string, any>[];
|
|
11
|
+
pages?: number;
|
|
12
|
+
pageRange?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function buildAddress(address?: Record<string, string>) {
|
|
16
|
+
if (!address) return undefined;
|
|
17
|
+
const parts = [
|
|
18
|
+
address.line1,
|
|
19
|
+
address.line2,
|
|
20
|
+
address.city,
|
|
21
|
+
address.state,
|
|
22
|
+
address.postalCode,
|
|
23
|
+
address.country,
|
|
24
|
+
].filter((p) => p && p.trim() !== "");
|
|
25
|
+
return parts.length ? parts.join(", ") : undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function mapLogToSummaryRow(log: Record<string, any>, index: number): NFCPatrolSummaryRow {
|
|
29
|
+
const checkpoints: Record<string, any>[] = log.checkPoints ?? [];
|
|
30
|
+
const checked = checkpoints.filter((cp) => cp.status === "Completed").length;
|
|
31
|
+
const missed = checkpoints.filter((cp) => cp.status === "Skipped").length;
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
id: log._id,
|
|
35
|
+
routeName: `${index + 1}. ${log.route?.name ?? "-"}`,
|
|
36
|
+
securityCheckSchedule: log.route?.startTime ?? "-",
|
|
37
|
+
checked,
|
|
38
|
+
missed,
|
|
39
|
+
status: missed === 0 ? "Completed" : "Incomplete",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function useNFCPatrolDailyReport(
|
|
44
|
+
filters: NFCPatrolReportFilters,
|
|
45
|
+
site: string,
|
|
46
|
+
) {
|
|
47
|
+
const { getAll: getPatrolLogs } = useNFCPatrolLog();
|
|
48
|
+
const { getSiteById } = useSite();
|
|
6
49
|
|
|
7
|
-
export function useNFCPatrolDailyReport(filters: NFCPatrolReportFilters) {
|
|
8
|
-
const reportService = useNFCPatrolReportService();
|
|
9
50
|
const report = ref<NFCPatrolSummaryReport | null>(null);
|
|
10
51
|
const loading = ref(false);
|
|
52
|
+
const notFound = ref(false);
|
|
11
53
|
|
|
12
54
|
async function fetchReport() {
|
|
55
|
+
if (!site || !filters.date || !filters.route) {
|
|
56
|
+
report.value = null;
|
|
57
|
+
notFound.value = false;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
13
61
|
loading.value = true;
|
|
62
|
+
notFound.value = false;
|
|
14
63
|
|
|
15
64
|
try {
|
|
16
|
-
|
|
65
|
+
const [logsRes, siteInfo] = await Promise.all([
|
|
66
|
+
getPatrolLogs<NFCPatrolLogListResponse>({
|
|
67
|
+
page: 1,
|
|
68
|
+
limit: 100,
|
|
69
|
+
site,
|
|
70
|
+
date: filters.date,
|
|
71
|
+
routeId: filters.route,
|
|
72
|
+
routeStartTime: filters.timeRange
|
|
73
|
+
? filters.timeRange.split(" - ")[0]
|
|
74
|
+
: undefined,
|
|
75
|
+
}),
|
|
76
|
+
getSiteById(site),
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
const logs = logsRes.items ?? [];
|
|
80
|
+
|
|
81
|
+
if (logs.length) {
|
|
82
|
+
const routeName = logs[0]?.route?.name ?? "-";
|
|
83
|
+
|
|
84
|
+
report.value = {
|
|
85
|
+
location: {
|
|
86
|
+
name: siteInfo.name,
|
|
87
|
+
address: buildAddress(siteInfo.address),
|
|
88
|
+
},
|
|
89
|
+
title: `Patrol Route Summary: ${routeName}`,
|
|
90
|
+
rows: logs.map(mapLogToSummaryRow),
|
|
91
|
+
};
|
|
92
|
+
} else {
|
|
93
|
+
report.value = null;
|
|
94
|
+
notFound.value = true;
|
|
95
|
+
}
|
|
17
96
|
} finally {
|
|
18
97
|
loading.value = false;
|
|
19
98
|
}
|
|
@@ -22,6 +101,7 @@ export function useNFCPatrolDailyReport(filters: NFCPatrolReportFilters) {
|
|
|
22
101
|
return {
|
|
23
102
|
report,
|
|
24
103
|
loading,
|
|
104
|
+
notFound,
|
|
25
105
|
fetchReport,
|
|
26
106
|
};
|
|
27
107
|
}
|
|
@@ -3,8 +3,9 @@ interface NFCPatrolLogQuery {
|
|
|
3
3
|
limit?: number;
|
|
4
4
|
site: string;
|
|
5
5
|
date: string;
|
|
6
|
+
type?: string;
|
|
6
7
|
routeId: string;
|
|
7
|
-
routeStartTime
|
|
8
|
+
routeStartTime?: string;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export default function useNFCPatrolLog() {
|
|
@@ -13,6 +14,7 @@ export default function useNFCPatrolLog() {
|
|
|
13
14
|
limit = 10,
|
|
14
15
|
site,
|
|
15
16
|
date,
|
|
17
|
+
type,
|
|
16
18
|
routeId,
|
|
17
19
|
routeStartTime,
|
|
18
20
|
}: NFCPatrolLogQuery) {
|
|
@@ -23,6 +25,7 @@ export default function useNFCPatrolLog() {
|
|
|
23
25
|
limit,
|
|
24
26
|
site,
|
|
25
27
|
date,
|
|
28
|
+
type,
|
|
26
29
|
"route._id": routeId,
|
|
27
30
|
"route.startTime": routeStartTime,
|
|
28
31
|
},
|
|
@@ -1,19 +1,104 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
NFCPatrolReportFilters,
|
|
3
3
|
NFCPatrolSummaryReport,
|
|
4
|
+
NFCPatrolReportSummaryRow,
|
|
4
5
|
} from "../types/nfc-patrol-report";
|
|
5
|
-
import
|
|
6
|
+
import useNFCPatrolLog from "./useNFCPatrolLog";
|
|
7
|
+
import useSite from "./useSite";
|
|
8
|
+
|
|
9
|
+
interface NFCPatrolLogListResponse {
|
|
10
|
+
items?: Record<string, any>[];
|
|
11
|
+
pages?: number;
|
|
12
|
+
pageRange?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function buildAddress(address?: Record<string, string>) {
|
|
16
|
+
if (!address) return undefined;
|
|
17
|
+
|
|
18
|
+
const parts = [
|
|
19
|
+
address.line1,
|
|
20
|
+
address.line2,
|
|
21
|
+
address.city,
|
|
22
|
+
address.state,
|
|
23
|
+
address.postalCode,
|
|
24
|
+
address.country,
|
|
25
|
+
].filter((p) => p && p.trim() !== "");
|
|
26
|
+
|
|
27
|
+
return parts.length ? parts.join(", ") : undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function mapLogToSummaryRow(
|
|
31
|
+
log: Record<string, any>,
|
|
32
|
+
index: number,
|
|
33
|
+
): NFCPatrolReportSummaryRow {
|
|
34
|
+
const checkpoints: Record<string, any>[] = log.checkPoints ?? [];
|
|
35
|
+
const checked = checkpoints.filter((cp) => cp.status === "Completed").length;
|
|
36
|
+
const missed = checkpoints.filter((cp) => cp.status === "Skipped").length;
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
id: log._id,
|
|
40
|
+
routeName: `${index + 1}. ${log.route?.name ?? "-"}`,
|
|
41
|
+
securityCheckSchedule: log.route?.startTime ?? "-",
|
|
42
|
+
checked,
|
|
43
|
+
missed,
|
|
44
|
+
status: missed === 0 ? "Completed" : "Incomplete",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function useNFCPatrolMonthlyReport(
|
|
49
|
+
filters: NFCPatrolReportFilters,
|
|
50
|
+
site: string,
|
|
51
|
+
) {
|
|
52
|
+
const { getAll: getPatrolLogs } = useNFCPatrolLog();
|
|
53
|
+
const { getSiteById } = useSite();
|
|
6
54
|
|
|
7
|
-
export function useNFCPatrolMonthlyReport(filters: NFCPatrolReportFilters) {
|
|
8
|
-
const reportService = useNFCPatrolReportService();
|
|
9
55
|
const report = ref<NFCPatrolSummaryReport | null>(null);
|
|
10
56
|
const loading = ref(false);
|
|
57
|
+
const notFound = ref(false);
|
|
11
58
|
|
|
12
59
|
async function fetchReport() {
|
|
60
|
+
if (!site || !filters.date || !filters.route) {
|
|
61
|
+
report.value = null;
|
|
62
|
+
notFound.value = false;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
13
66
|
loading.value = true;
|
|
67
|
+
notFound.value = false;
|
|
14
68
|
|
|
15
69
|
try {
|
|
16
|
-
|
|
70
|
+
const [logsRes, siteInfo] = await Promise.all([
|
|
71
|
+
getPatrolLogs<NFCPatrolLogListResponse>({
|
|
72
|
+
page: 1,
|
|
73
|
+
limit: 100,
|
|
74
|
+
site,
|
|
75
|
+
date: filters.date,
|
|
76
|
+
routeId: filters.route,
|
|
77
|
+
routeStartTime: filters.timeRange
|
|
78
|
+
? filters.timeRange.split(" - ")[0]
|
|
79
|
+
: undefined,
|
|
80
|
+
type: "month",
|
|
81
|
+
}),
|
|
82
|
+
getSiteById(site),
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
const logs = logsRes.items ?? [];
|
|
86
|
+
|
|
87
|
+
if (logs.length) {
|
|
88
|
+
const routeName = logs[0]?.route?.name ?? "-";
|
|
89
|
+
|
|
90
|
+
report.value = {
|
|
91
|
+
location: {
|
|
92
|
+
name: siteInfo.name,
|
|
93
|
+
address: buildAddress(siteInfo.address),
|
|
94
|
+
},
|
|
95
|
+
title: `Patrol Route Summary: ${routeName}`,
|
|
96
|
+
rows: logs.map(mapLogToSummaryRow),
|
|
97
|
+
};
|
|
98
|
+
} else {
|
|
99
|
+
report.value = null;
|
|
100
|
+
notFound.value = true;
|
|
101
|
+
}
|
|
17
102
|
} finally {
|
|
18
103
|
loading.value = false;
|
|
19
104
|
}
|
|
@@ -22,6 +107,7 @@ export function useNFCPatrolMonthlyReport(filters: NFCPatrolReportFilters) {
|
|
|
22
107
|
return {
|
|
23
108
|
report,
|
|
24
109
|
loading,
|
|
110
|
+
notFound,
|
|
25
111
|
fetchReport,
|
|
26
112
|
};
|
|
27
113
|
}
|
|
@@ -3,12 +3,80 @@ import type {
|
|
|
3
3
|
NFCPatrolReport,
|
|
4
4
|
NFCPatrolReportFilters,
|
|
5
5
|
} from "../types/nfc-patrol-report";
|
|
6
|
+
import useNFCPatrolLog from "./useNFCPatrolLog";
|
|
7
|
+
import useSite from "./useSite";
|
|
6
8
|
|
|
7
|
-
interface
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
interface NFCPatrolLogListResponse {
|
|
10
|
+
items?: Record<string, any>[];
|
|
11
|
+
pages?: number;
|
|
12
|
+
pageRange?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function formatTime(iso?: string) {
|
|
16
|
+
return iso ? iso.slice(11, 16) : "-";
|
|
17
|
+
}
|
|
18
|
+
function formatDuration(totalMinutes: number) {
|
|
19
|
+
if (totalMinutes < 60) return `${totalMinutes} mins`;
|
|
20
|
+
|
|
21
|
+
const hrs = Math.floor(totalMinutes / 60);
|
|
22
|
+
const mins = totalMinutes % 60;
|
|
23
|
+
|
|
24
|
+
if (mins === 0) return `${hrs} hrs`;
|
|
25
|
+
return `${hrs} hrs ${mins} mins`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function diffMinutes(startIso?: string, endIso?: string) {
|
|
29
|
+
if (!startIso || !endIso) return "-";
|
|
30
|
+
const totalMinutes = Math.max(
|
|
31
|
+
0,
|
|
32
|
+
Math.round((new Date(endIso).getTime() - new Date(startIso).getTime()) / 60000),
|
|
33
|
+
);
|
|
34
|
+
return formatDuration(totalMinutes);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
function mapLogToPatrolReport(
|
|
39
|
+
log: Record<string, any>,
|
|
40
|
+
location: NFCPatrolReport["location"],
|
|
41
|
+
): NFCPatrolReport {
|
|
42
|
+
const checkpoints: Record<string, any>[] = log.checkPoints ?? [];
|
|
43
|
+
const actualStart = checkpoints[0]?.startDateTime ?? log.startDateTime;
|
|
44
|
+
const actualEnd = checkpoints[checkpoints.length - 1]?.endDateTime ?? log.endDateTime;
|
|
45
|
+
|
|
46
|
+
const totalTravelMinutes = checkpoints.reduce(
|
|
47
|
+
(sum, cp) => sum + (Number(cp.travelTime) || 0),
|
|
48
|
+
0,
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const activities: NFCPatrolActivity[] = checkpoints.map((cp) => ({
|
|
52
|
+
id: cp.nfcTag_id,
|
|
53
|
+
checkpoint: cp.nfcTag_name,
|
|
54
|
+
startTime: formatTime(cp.startDateTime),
|
|
55
|
+
endTime: formatTime(cp.endDateTime),
|
|
56
|
+
actualTime: diffMinutes(cp.startDateTime, cp.endDateTime),
|
|
57
|
+
expectedTime: formatDuration(cp.travelTime),
|
|
58
|
+
status: cp.status,
|
|
59
|
+
remarks: cp.skippedRemarks && cp.skippedRemarks !== "N/A" ? cp.skippedRemarks : undefined,
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
location,
|
|
64
|
+
routeSummary: {
|
|
65
|
+
routeName: log.route?.name,
|
|
66
|
+
tolerance: totalTravelMinutes,
|
|
67
|
+
schedule: {
|
|
68
|
+
start: log.route?.startTime,
|
|
69
|
+
end: log.route?.endTime,
|
|
70
|
+
totalTime: diffMinutes(log.startDateTime, log.endDateTime),
|
|
71
|
+
},
|
|
72
|
+
actual: {
|
|
73
|
+
start: formatTime(actualStart),
|
|
74
|
+
end: formatTime(actualEnd),
|
|
75
|
+
totalTime: diffMinutes(actualStart, actualEnd),
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
activities,
|
|
79
|
+
};
|
|
12
80
|
}
|
|
13
81
|
|
|
14
82
|
export function useNFCPatrolReport(
|
|
@@ -16,43 +84,51 @@ export function useNFCPatrolReport(
|
|
|
16
84
|
site: string,
|
|
17
85
|
) {
|
|
18
86
|
const { getAll: getPatrolLogs } = useNFCPatrolLog();
|
|
87
|
+
const { getSiteById } = useSite();
|
|
88
|
+
|
|
19
89
|
const report = ref<NFCPatrolReport | null>(null);
|
|
20
90
|
const loading = ref(false);
|
|
91
|
+
const notFound = ref(false);
|
|
21
92
|
const selectedActivityRemarks = ref("");
|
|
22
93
|
const dialogRemarks = ref(false);
|
|
23
94
|
|
|
24
95
|
async function fetchReport() {
|
|
25
96
|
if (!site || !filters.date || !filters.route || !filters.timeRange) {
|
|
26
97
|
report.value = null;
|
|
98
|
+
notFound.value = false;
|
|
27
99
|
return;
|
|
28
100
|
}
|
|
29
101
|
|
|
30
102
|
loading.value = true;
|
|
103
|
+
notFound.value = false;
|
|
31
104
|
|
|
32
105
|
try {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
loading.value = false;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
106
|
+
const [logsRes, siteInfo] = await Promise.all([
|
|
107
|
+
getPatrolLogs<NFCPatrolLogListResponse>({
|
|
108
|
+
page: 1,
|
|
109
|
+
limit: 10,
|
|
110
|
+
site,
|
|
111
|
+
date: filters.date,
|
|
112
|
+
routeId: filters.route,
|
|
113
|
+
routeStartTime: filters.timeRange.split(" - ")[0],
|
|
114
|
+
}),
|
|
115
|
+
getSiteById(site),
|
|
116
|
+
]);
|
|
47
117
|
|
|
48
|
-
|
|
49
|
-
const payload = response.data ?? response;
|
|
118
|
+
const log = logsRes.items?.[0];
|
|
50
119
|
|
|
51
|
-
|
|
52
|
-
|
|
120
|
+
if (log) {
|
|
121
|
+
report.value = mapLogToPatrolReport(log, {
|
|
122
|
+
name: siteInfo.name,
|
|
123
|
+
address: buildAddress(siteInfo.address),
|
|
124
|
+
});
|
|
125
|
+
} else {
|
|
126
|
+
report.value = null;
|
|
127
|
+
notFound.value = true;
|
|
128
|
+
}
|
|
129
|
+
} finally {
|
|
130
|
+
loading.value = false;
|
|
53
131
|
}
|
|
54
|
-
|
|
55
|
-
return payload.nfcPatrolLog ?? payload.item ?? payload.items?.[0] ?? null;
|
|
56
132
|
}
|
|
57
133
|
|
|
58
134
|
function openRemarksDialog(activity: NFCPatrolActivity) {
|
|
@@ -60,9 +136,33 @@ export function useNFCPatrolReport(
|
|
|
60
136
|
dialogRemarks.value = true;
|
|
61
137
|
}
|
|
62
138
|
|
|
139
|
+
function buildAddress(address?: {
|
|
140
|
+
line1?: string;
|
|
141
|
+
line2?: string;
|
|
142
|
+
city?: string;
|
|
143
|
+
state?: string;
|
|
144
|
+
country?: string;
|
|
145
|
+
postalCode?: string;
|
|
146
|
+
}) {
|
|
147
|
+
if (!address) return undefined;
|
|
148
|
+
|
|
149
|
+
const parts = [
|
|
150
|
+
address.line1,
|
|
151
|
+
address.line2,
|
|
152
|
+
address.city,
|
|
153
|
+
address.state,
|
|
154
|
+
address.postalCode,
|
|
155
|
+
address.country,
|
|
156
|
+
].filter((part) => part && part.trim() !== "");
|
|
157
|
+
|
|
158
|
+
return parts.length ? parts.join(", ") : undefined;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
|
|
63
162
|
return {
|
|
64
163
|
report,
|
|
65
164
|
loading,
|
|
165
|
+
notFound,
|
|
66
166
|
selectedActivityRemarks,
|
|
67
167
|
dialogRemarks,
|
|
68
168
|
fetchReport,
|
|
@@ -2,14 +2,22 @@ import type {
|
|
|
2
2
|
NFCPatrolReportFilterOptions,
|
|
3
3
|
NFCPatrolReportFilters,
|
|
4
4
|
} from "../types/nfc-patrol-report";
|
|
5
|
+
import useNFCPatrolRoute from "./useNFCPatrolRoute";
|
|
5
6
|
|
|
7
|
+
function getTodayDate() {
|
|
8
|
+
const now = new Date();
|
|
9
|
+
const y = now.getFullYear();
|
|
10
|
+
const m = String(now.getMonth() + 1).padStart(2, "0");
|
|
11
|
+
const d = String(now.getDate()).padStart(2, "0");
|
|
12
|
+
return `${y}-${m}-${d}`;
|
|
13
|
+
}
|
|
6
14
|
export function useNFCPatrolReportFilters(site: string) {
|
|
7
15
|
const { getAll: getPatrolRoutes } = useNFCPatrolRoute();
|
|
8
16
|
|
|
9
17
|
const filters = reactive<NFCPatrolReportFilters>({
|
|
10
18
|
route: "",
|
|
11
19
|
timeRange: "",
|
|
12
|
-
date:
|
|
20
|
+
date: getTodayDate(),
|
|
13
21
|
});
|
|
14
22
|
|
|
15
23
|
const options = ref<NFCPatrolReportFilterOptions>({
|
package/package.json
CHANGED