Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/services/dashboardService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import axios from "axios"
import { clearAuth, getAuthorizationHeader } from "./authService"

const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || "http://localhost:8080"
const API_TIMEOUT_MS = 15000

const dashboardClient = axios.create({
baseURL: API_BASE_URL,
timeout: API_TIMEOUT_MS,
headers: { "Content-Type": "application/json" },
})
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const request = async (config, fallback) => {
try {
const { data } = await dashboardClient.request({
...config,
headers: getAuthorizationHeader(),
})
return data
} catch (error) {
if (error.response?.status === 401) clearAuth()
throw {
status: error.response?.status || 0,
message: error.response?.data?.message || fallback,
errors: error.response?.data?.errors || {},
}
}
}

export const getDashboardOverview = () => request(
{ method: "get", url: "/api/dashboard/overview" },
"Không thể tải dữ liệu dashboard.",
)
161 changes: 89 additions & 72 deletions src/views/ApprovalsView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,6 @@ function isPendingApproval(status) {
}

function approveLabel(status) {
if (isPendingApproval(status)) return "Duyệt phiếu";
return "Duyệt phiếu";
}

Expand Down Expand Up @@ -481,72 +480,79 @@ function getRejectionReason(receipt) {
Đang tải danh sách phiếu chờ duyệt...
</p>

<DataTable
:columns="columns"
:rows="receipts"
empty-text="Không có phiếu nào đang chờ duyệt"
>
<template #code="{ row, value }">
<div class="document-cell">
<span class="document-code">{{ value || "-" }}</span>
<span
class="badge doc-badge"
:class="documentTypeBadgeClass(documentType)"
>{{ documentTypeLabel(documentType) }}</span
>
</div>
</template>
<template #warehouseName="{ value }">{{ value || "-" }}</template>
<template #supplierName="{ value }">{{ value || "-" }}</template>
<template #createdByName="{ value }">{{ value || "-" }}</template>
<template #submittedAt="{ value }">{{ formatDateTime(value) }}</template>
<template #status="{ value }">
<span class="badge" :class="statusClass(value)">{{
statusLabel(value)
}}</span>
</template>
<template #totalAmount="{ value }">{{ formatCurrency(value) }}</template>
<template #actions="{ row }">
<div class="actions">
<button
class="btn btn-sm"
type="button"
:disabled="isAnyActionRunning(row)"
@click="openDetail(row)"
>
Xem
</button>
<button
class="btn btn-sm btn-secondary"
type="button"
:disabled="isAnyActionRunning(row)"
@click="openHistory(row)"
>
Lịch sử
</button>
<button
class="btn btn-sm btn-primary"
type="button"
:disabled="isAnyActionRunning(row) || !isPendingApproval(row.status)"
@click="handleApprove(row)"
>
{{
isActionRunning(row, "approve")
? "Đang duyệt..."
: approveLabel(row.status)
}}
</button>
<button
class="btn btn-sm btn-danger"
type="button"
:disabled="isAnyActionRunning(row) || !isPendingApproval(row.status)"
@click="openRejectModal(row)"
>
Từ chối
</button>
</div>
</template>
</DataTable>
<div v-if="!isLoading">
<DataTable
:columns="columns"
:rows="receipts"
empty-text="Không có phiếu nào đang chờ duyệt"
>
<template #code="{ row, value }">
<div class="document-cell">
<span class="document-code">{{ value || "-" }}</span>
<span
class="badge doc-badge"
:class="documentTypeBadgeClass(row.documentType)"
>
{{ documentTypeLabel(row.documentType) }}
</span>
</div>
</template>
<template #warehouseName="{ value }">{{ value || "-" }}</template>
<template #supplierName="{ value }">{{ value || "-" }}</template>
<template #createdByName="{ value }">{{ value || "-" }}</template>
<template #submittedAt="{ value }">{{ formatDateTime(value) }}</template>
<template #status="{ value }">
<span class="badge" :class="statusClass(value)">
{{ statusLabel(value) }}
</span>
</template>
<template #totalAmount="{ value }">{{ formatCurrency(value) }}</template>
<template #actions="{ row }">
<div class="actions">
<button
class="btn btn-sm"
type="button"
:disabled="isAnyActionRunning(row)"
@click="openDetail(row)"
>
Xem
</button>
<button
class="btn btn-sm btn-secondary"
type="button"
:disabled="isAnyActionRunning(row)"
@click="openHistory(row)"
>
Lịch sử
</button>
<button
class="btn btn-sm btn-primary"
type="button"
:disabled="
isAnyActionRunning(row) || !isPendingApproval(row.status)
"
@click="handleApprove(row)"
>
{{
isActionRunning(row, "approve")
? "Đang duyệt..."
: approveLabel(row.status)
}}
</button>
<button
class="btn btn-sm btn-danger"
type="button"
:disabled="
isAnyActionRunning(row) || !isPendingApproval(row.status)
"
@click="openRejectModal(row)"
>
Từ chối
</button>
</div>
</template>
</DataTable>
</div>

<div class="pagination-bar card card-pad">
<span class="muted">{{ totalElements }} phiếu chờ duyệt</span>
Expand Down Expand Up @@ -578,8 +584,13 @@ function getRejectionReason(receipt) {
<div class="modal detail-modal">
<div class="modal-head between">
<h2 class="section-title">
Chi tiết phiếu {{ documentType === "out" ? "xuất" : "nhập" }} chờ
duyệt
Chi tiết phiếu
{{
(detailState.receipt?.documentType || documentType) === "out"
? "xuất"
: "nhập"
}}
chờ duyệt
</h2>
<button class="btn btn-icon" aria-label="Đóng" @click="closeDetail">
<i class="mdi mdi-close"></i>
Expand Down Expand Up @@ -621,8 +632,10 @@ function getRejectionReason(receipt) {
<span class="detail-label">Loại phiếu</span
><span
class="badge doc-badge"
:class="documentTypeBadgeClass(documentType)"
>{{ documentTypeLabel(documentType) }}</span
:class="
documentTypeBadgeClass(detailState.receipt.documentType)
"
>{{ documentTypeLabel(detailState.receipt.documentType) }}</span
>
</div>
<div>
Expand All @@ -632,7 +645,11 @@ function getRejectionReason(receipt) {
}}</span>
</div>
<div>
<span class="detail-label">Nhà cung cấp</span
<span class="detail-label">{{
detailState.receipt.documentType === "out"
? "Khách hàng"
: "Nhà cung cấp"
}}</span
><span class="detail-value">{{
detailState.receipt.supplierName || "-"
}}</span>
Expand Down
Loading