feat: quotation stats
This commit is contained in:
parent
c5b3e4dbd7
commit
1d73d8084e
4 changed files with 89 additions and 179 deletions
|
|
@ -2,6 +2,7 @@
|
|||
const props = withDefaults(
|
||||
defineProps<{
|
||||
branch: {
|
||||
hidden?: boolean;
|
||||
icon: string;
|
||||
count: number;
|
||||
label: string;
|
||||
|
|
@ -32,7 +33,7 @@ const props = withDefaults(
|
|||
<template>
|
||||
<div class="row no-wrap" style="gap: var(--size-4)" :class="{ dark }">
|
||||
<div
|
||||
v-for="v in props.branch"
|
||||
v-for="v in branch.filter((v) => !v.hidden)"
|
||||
class="no-padding stat-card"
|
||||
:class="{ [`stat-card__${v.color}`]: true }"
|
||||
:key="v.label"
|
||||
|
|
|
|||
|
|
@ -97,20 +97,6 @@ const tabFieldRequired = ref<{ [key: string]: (keyof CustomerBranchCreate)[] }>(
|
|||
const productServiceStore = useProductServiceStore();
|
||||
const router = useRouter();
|
||||
|
||||
type ProductGroupId = string;
|
||||
|
||||
const productGroup = ref<ProductGroup[]>([]);
|
||||
const productList = ref<Partial<Record<ProductGroupId, Product[]>>>({});
|
||||
const serviceList = ref<Partial<Record<ProductGroupId, Service[]>>>({});
|
||||
|
||||
type Id = string;
|
||||
const product = ref<Record<Id, Product>>({});
|
||||
const service = ref<Record<Id, Service>>({});
|
||||
|
||||
const selectedGroup = ref<ProductGroup | null>(null);
|
||||
const selectedGroupSub = ref<'product' | 'service' | null>(null);
|
||||
const selectedProductServiceId = ref('');
|
||||
|
||||
const selectedEmployee = ref<Employee[]>([]);
|
||||
|
||||
const pageState = reactive({
|
||||
|
|
@ -127,58 +113,11 @@ const pageState = reactive({
|
|||
productServiceModal: false,
|
||||
});
|
||||
|
||||
const statData = ref<
|
||||
{
|
||||
icon: string;
|
||||
count: number;
|
||||
label: string;
|
||||
color:
|
||||
| 'pink'
|
||||
| 'purple'
|
||||
| 'green'
|
||||
| 'orange'
|
||||
| 'cyan'
|
||||
| 'yellow'
|
||||
| 'red'
|
||||
| 'magenta'
|
||||
| 'blue'
|
||||
| 'lime'
|
||||
| 'light-purple';
|
||||
}[]
|
||||
>([
|
||||
{
|
||||
icon: 'mdi-cash',
|
||||
count: 0,
|
||||
label: 'quotation.type.fullAmountCash',
|
||||
color: 'red',
|
||||
},
|
||||
{
|
||||
icon: 'mdi-hand-coin-outline',
|
||||
count: 0,
|
||||
label: 'quotation.type.installmentsCash',
|
||||
color: 'blue',
|
||||
},
|
||||
{
|
||||
icon: 'mdi-receipt-text-outline',
|
||||
count: 0,
|
||||
label: 'quotation.type.fullAmountBill',
|
||||
color: 'lime',
|
||||
},
|
||||
{
|
||||
icon: 'mdi-receipt-text-send-outline',
|
||||
count: 0,
|
||||
label: 'quotation.type.installmentsBill',
|
||||
color: 'light-purple',
|
||||
},
|
||||
]);
|
||||
|
||||
const formDataCustomerBranch = ref<
|
||||
CustomerBranchCreate & {
|
||||
id?: string;
|
||||
branchCode?: string;
|
||||
codeCustomer?: string;
|
||||
}
|
||||
>({
|
||||
const CUSTOMER_BRANCH_DEFAULT: CustomerBranchCreate & {
|
||||
id?: string;
|
||||
branchCode?: string;
|
||||
codeCustomer?: string;
|
||||
} = {
|
||||
customerCode: '',
|
||||
customerId: '',
|
||||
legalPersonNo: '',
|
||||
|
|
@ -226,58 +165,18 @@ const formDataCustomerBranch = ref<
|
|||
authorizedName: '',
|
||||
authorizedNameEN: '',
|
||||
code: '',
|
||||
});
|
||||
};
|
||||
|
||||
const formDataCustomerBranch = ref<
|
||||
CustomerBranchCreate & {
|
||||
id?: string;
|
||||
branchCode?: string;
|
||||
codeCustomer?: string;
|
||||
}
|
||||
>(structuredClone(CUSTOMER_BRANCH_DEFAULT));
|
||||
|
||||
function setDefaultCustomerd() {
|
||||
formDataCustomerBranch.value = {
|
||||
customerCode: '',
|
||||
customerId: '',
|
||||
legalPersonNo: '',
|
||||
citizenId: '',
|
||||
namePrefix: '',
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
firstNameEN: '',
|
||||
lastNameEN: '',
|
||||
telephoneNo: '',
|
||||
gender: '',
|
||||
birthDate: new Date().toString(),
|
||||
businessType: '',
|
||||
jobPosition: '',
|
||||
jobDescription: '',
|
||||
payDate: '',
|
||||
payDateEN: '',
|
||||
wageRate: 0,
|
||||
wageRateText: '',
|
||||
homeCode: '',
|
||||
employmentOffice: '',
|
||||
employmentOfficeEN: '',
|
||||
address: '',
|
||||
addressEN: '',
|
||||
street: '',
|
||||
streetEN: '',
|
||||
moo: '',
|
||||
mooEN: '',
|
||||
soi: '',
|
||||
soiEN: '',
|
||||
provinceId: '',
|
||||
districtId: '',
|
||||
subDistrictId: '',
|
||||
contactName: '',
|
||||
email: '',
|
||||
contactTel: '',
|
||||
officeTel: '',
|
||||
agent: '',
|
||||
status: 'CREATED',
|
||||
customerName: '',
|
||||
registerName: '',
|
||||
registerNameEN: '',
|
||||
registerDate: new Date(),
|
||||
authorizedCapital: '',
|
||||
authorizedName: '',
|
||||
authorizedNameEN: '',
|
||||
code: '',
|
||||
};
|
||||
formDataCustomerBranch.value = structuredClone(CUSTOMER_BRANCH_DEFAULT);
|
||||
}
|
||||
|
||||
async function submitCustomer() {
|
||||
|
|
@ -335,70 +234,21 @@ function triggerProductServiceDialog() {
|
|||
// TODO: form and state controll
|
||||
}
|
||||
|
||||
async function getAllProduct(
|
||||
groupId: string,
|
||||
opts?: { force?: false; page?: number; pageSize?: number },
|
||||
) {
|
||||
selectedGroupSub.value = 'product';
|
||||
if (!opts?.force && productList.value[groupId] !== undefined) return;
|
||||
const ret = await productServiceStore.fetchListProduct({
|
||||
page: opts?.page ?? 1,
|
||||
pageSize: opts?.pageSize ?? 9999,
|
||||
productGroupId: groupId,
|
||||
});
|
||||
if (ret) productList.value[groupId] = ret.result;
|
||||
}
|
||||
|
||||
async function getAllService(
|
||||
groupId: string,
|
||||
opts?: { force?: false; page?: number; pageSize?: number },
|
||||
) {
|
||||
selectedGroupSub.value = 'service';
|
||||
if (!opts?.force && serviceList.value[groupId] !== undefined) return;
|
||||
const ret = await productServiceStore.fetchListService({
|
||||
page: opts?.page ?? 1,
|
||||
pageSize: opts?.pageSize ?? 9999,
|
||||
productGroupId: groupId,
|
||||
fullDetail: true,
|
||||
});
|
||||
if (ret) serviceList.value[groupId] = ret.result;
|
||||
}
|
||||
|
||||
async function getProduct(id: string, force = false) {
|
||||
selectedGroupSub.value = 'product';
|
||||
selectedProductServiceId.value = id;
|
||||
if (!force && product.value[id] !== undefined) return;
|
||||
const ret = await productServiceStore.fetchListProductById(id);
|
||||
if (ret) product.value[id] = ret;
|
||||
}
|
||||
|
||||
async function getService(id: string, force = false) {
|
||||
selectedGroupSub.value = 'service';
|
||||
selectedProductServiceId.value = id;
|
||||
if (!force && service.value[id] !== undefined) return;
|
||||
const ret = await productServiceStore.fetchListServiceById(id);
|
||||
if (ret) service.value[id] = ret;
|
||||
}
|
||||
|
||||
function convertToTree() {
|
||||
// TODO: convert quotation product service data to tree
|
||||
}
|
||||
|
||||
const quotationStore = useQuotationStore();
|
||||
const {
|
||||
data: quotationData,
|
||||
page: quotationPage,
|
||||
pageSize: quotationPageSize,
|
||||
pageMax: quotationPageMax,
|
||||
stats: quotationStats,
|
||||
} = storeToRefs(quotationStore);
|
||||
|
||||
onMounted(async () => {
|
||||
{
|
||||
const ret = await productServiceStore.fetchListProductService({
|
||||
page: 1,
|
||||
pageSize: 9999,
|
||||
});
|
||||
if (ret) productGroup.value = ret.result;
|
||||
const ret = await quotationStore.getQuotationStats();
|
||||
if (ret) {
|
||||
quotationStats.value = Object.assign(quotationStats.value, ret);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -517,13 +367,44 @@ watch(() => pageState.currentTab, fetchQuotationList);
|
|||
<div style="display: inline-block">
|
||||
<StatCardComponent
|
||||
labelI18n
|
||||
:branch="
|
||||
pageState.currentTab === 'all'
|
||||
? statData
|
||||
: statData.filter((i) =>
|
||||
i.label.split('.').pop()?.includes(pageState.currentTab),
|
||||
)
|
||||
"
|
||||
:branch="[
|
||||
{
|
||||
icon: 'mdi-cash',
|
||||
count: quotationStats.full,
|
||||
label: 'quotation.type.fullAmountCash',
|
||||
color: 'red',
|
||||
hidden:
|
||||
pageState.currentTab !== 'all' &&
|
||||
pageState.currentTab !== 'fullAmountCash',
|
||||
},
|
||||
{
|
||||
icon: 'mdi-hand-coin-outline',
|
||||
count: quotationStats.split,
|
||||
label: 'quotation.type.installmentsCash',
|
||||
color: 'blue',
|
||||
hidden:
|
||||
pageState.currentTab !== 'all' &&
|
||||
pageState.currentTab !== 'installmentsCash',
|
||||
},
|
||||
{
|
||||
icon: 'mdi-receipt-text-outline',
|
||||
count: quotationStats.billFull,
|
||||
label: 'quotation.type.fullAmountBill',
|
||||
color: 'lime',
|
||||
hidden:
|
||||
pageState.currentTab !== 'all' &&
|
||||
pageState.currentTab !== 'fullAmountBill',
|
||||
},
|
||||
{
|
||||
icon: 'mdi-receipt-text-send-outline',
|
||||
count: quotationStats.billSplit,
|
||||
label: 'quotation.type.installmentsBill',
|
||||
color: 'light-purple',
|
||||
hidden:
|
||||
pageState.currentTab !== 'all' &&
|
||||
pageState.currentTab !== 'installmentsBill',
|
||||
},
|
||||
]"
|
||||
:dark="$q.dark.isActive"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,12 @@ import { defineStore } from 'pinia';
|
|||
|
||||
import { api } from 'src/boot/axios';
|
||||
|
||||
import { Quotation, QuotationFull, QuotationPayload } from './types';
|
||||
import {
|
||||
Quotation,
|
||||
QuotationFull,
|
||||
QuotationPayload,
|
||||
QuotationStats,
|
||||
} from './types';
|
||||
import { PaginationResult } from 'src/types';
|
||||
|
||||
export const useQuotationStore = defineStore('quotation-store', () => {
|
||||
|
|
@ -11,6 +16,20 @@ export const useQuotationStore = defineStore('quotation-store', () => {
|
|||
const page = ref<number>(1);
|
||||
const pageMax = ref<number>(1);
|
||||
const pageSize = ref<number>(30);
|
||||
const stats = ref<QuotationStats>({
|
||||
full: 0,
|
||||
split: 0,
|
||||
billFull: 0,
|
||||
billSplit: 0,
|
||||
});
|
||||
|
||||
async function getQuotationStats() {
|
||||
const res = await api.get<QuotationStats>(`/quotation/stats`);
|
||||
if (res.status < 400) {
|
||||
return res.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async function getQuotation(id: string) {
|
||||
const res = await api.get<QuotationFull>(`/quotation/${id}`);
|
||||
|
|
@ -92,6 +111,8 @@ export const useQuotationStore = defineStore('quotation-store', () => {
|
|||
page,
|
||||
pageSize,
|
||||
pageMax,
|
||||
stats,
|
||||
getQuotationStats,
|
||||
getQuotation,
|
||||
getQuotationList,
|
||||
createQuotation,
|
||||
|
|
|
|||
|
|
@ -151,6 +151,13 @@ type ServiceRelation = {
|
|||
updatedByUserId: string;
|
||||
};
|
||||
|
||||
export type QuotationStats = {
|
||||
full: number;
|
||||
split: number;
|
||||
billFull: number;
|
||||
billSplit: number;
|
||||
};
|
||||
|
||||
export type Quotation = {
|
||||
_count: { worker: number };
|
||||
id: string;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue