fix: receipt dialog
This commit is contained in:
parent
6df13d034e
commit
8d87368a7c
2 changed files with 149 additions and 22 deletions
|
|
@ -1,12 +1,13 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useConfigStore } from 'stores/config';
|
import { useConfigStore } from 'stores/config';
|
||||||
import { formatNumberDecimal, commaInput } from 'stores/utils';
|
import { formatNumberDecimal, commaInput, deleteItem } from 'stores/utils';
|
||||||
import DialogForm from 'src/components/DialogForm.vue';
|
import DialogForm from 'src/components/DialogForm.vue';
|
||||||
import { reactive, ref, watch } from 'vue';
|
import { reactive, ref, watch } from 'vue';
|
||||||
import { useQuotationPayment } from 'src/stores/quotations';
|
import { useQuotationPayment } from 'src/stores/quotations';
|
||||||
import { Quotation, QuotationPaymentData } from 'src/stores/quotations/types';
|
import { Quotation, QuotationPaymentData } from 'src/stores/quotations/types';
|
||||||
import { dateFormat } from 'src/utils/datetime';
|
import { dateFormat } from 'src/utils/datetime';
|
||||||
|
import { QFile } from 'quasar';
|
||||||
|
|
||||||
const configStore = useConfigStore();
|
const configStore = useConfigStore();
|
||||||
const quotationPayment = useQuotationPayment();
|
const quotationPayment = useQuotationPayment();
|
||||||
|
|
@ -19,8 +20,16 @@ defineEmits<{
|
||||||
const model = defineModel<boolean>({ default: false, required: true });
|
const model = defineModel<boolean>({ default: false, required: true });
|
||||||
const data = defineModel<Quotation | undefined>('data', { required: true });
|
const data = defineModel<Quotation | undefined>('data', { required: true });
|
||||||
|
|
||||||
|
const refQFile = ref<InstanceType<typeof QFile>[]>([]);
|
||||||
const paymentData = ref<QuotationPaymentData[]>([]);
|
const paymentData = ref<QuotationPaymentData[]>([]);
|
||||||
const payAll = ref<boolean>(false);
|
const payAll = ref<boolean>(false);
|
||||||
|
const slipFile = ref<
|
||||||
|
{
|
||||||
|
quotationId: string;
|
||||||
|
paymentId: string;
|
||||||
|
file: File[];
|
||||||
|
}[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
waitExpansion: true,
|
waitExpansion: true,
|
||||||
|
|
@ -33,6 +42,10 @@ function monthDisplay(date: Date | string) {
|
||||||
return arr.join(' ');
|
return arr.join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pickFile(index: number) {
|
||||||
|
refQFile.value[index].pickFiles();
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => model.value,
|
() => model.value,
|
||||||
async (open) => {
|
async (open) => {
|
||||||
|
|
@ -43,6 +56,14 @@ watch(
|
||||||
const ret = await quotationPayment.getQuotationPayment(data.value.id);
|
const ret = await quotationPayment.getQuotationPayment(data.value.id);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
paymentData.value = ret.quotationPaymentData;
|
paymentData.value = ret.quotationPaymentData;
|
||||||
|
slipFile.value = paymentData.value.map((v) => ({
|
||||||
|
quotationId: ret.id,
|
||||||
|
paymentId: v.id,
|
||||||
|
file: [],
|
||||||
|
}));
|
||||||
|
console.log(ret);
|
||||||
|
console.log(paymentData.value);
|
||||||
|
console.log(slipFile.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -393,23 +414,6 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- <div
|
|
||||||
class="q-px-md q-py-xs text-weight-medium row items-center"
|
|
||||||
style="background-color: hsla(var(--info-bg) / 0.1)"
|
|
||||||
>
|
|
||||||
งานที่ดำเนินการในงวดนี้
|
|
||||||
<q-btn
|
|
||||||
dense
|
|
||||||
flat
|
|
||||||
padding="0px 8px"
|
|
||||||
label="เพิ่มงาน"
|
|
||||||
class="q-ml-auto app-text-info"
|
|
||||||
></q-btn>
|
|
||||||
</div>
|
|
||||||
<div class="q-px-md q-py-sm">
|
|
||||||
<span class="app-text-muted">ยังไม่พบงาน</span>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="q-px-md q-py-xs text-weight-medium row items-center"
|
class="q-px-md q-py-xs text-weight-medium row items-center"
|
||||||
style="background-color: hsla(var(--info-bg) / 0.1)"
|
style="background-color: hsla(var(--info-bg) / 0.1)"
|
||||||
|
|
@ -420,8 +424,10 @@ watch(
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="surface-2" style="height: 200px">
|
<div class="surface-2 q-pa-md">
|
||||||
<div class="column full-height items-center justify-center">
|
<div
|
||||||
|
class="upload-section column rounded q-py-md full-height items-center justify-center no-wrap"
|
||||||
|
>
|
||||||
<q-img src="/images/upload.png" width="150px" />
|
<q-img src="/images/upload.png" width="150px" />
|
||||||
{{ $t('general.upload', { msg: ' E-slip' }) }}
|
{{ $t('general.upload', { msg: ' E-slip' }) }}
|
||||||
{{
|
{{
|
||||||
|
|
@ -436,10 +442,70 @@ watch(
|
||||||
:label="$t('general.upload')"
|
:label="$t('general.upload')"
|
||||||
rounded
|
rounded
|
||||||
class="app-bg-info q-mt-sm"
|
class="app-bg-info q-mt-sm"
|
||||||
@click.stop="$emit('upload', i)"
|
@click.stop="() => pickFile(i)"
|
||||||
|
/>
|
||||||
|
<q-file
|
||||||
|
ref="refQFile"
|
||||||
|
v-show="false"
|
||||||
|
v-model="slipFile[i].file"
|
||||||
|
label="Pick files"
|
||||||
|
filled
|
||||||
|
multiple
|
||||||
|
append
|
||||||
|
style="max-width: 300px"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<section class="surface-2 row q-px-md">
|
||||||
|
<div
|
||||||
|
v-for="(file, j) in slipFile[i].file"
|
||||||
|
:key="j"
|
||||||
|
class="col-12 q-pa-md bordered rounded row items-center"
|
||||||
|
:class="{ 'q-mb-md': i === 5, 'q-mb-sm': i < 5 }"
|
||||||
|
>
|
||||||
|
<q-icon
|
||||||
|
name="mdi-file-image-outline"
|
||||||
|
size="lg"
|
||||||
|
class="app-text-muted"
|
||||||
|
/>
|
||||||
|
<article class="col column q-pl-md">
|
||||||
|
{{ console.log(file) }}
|
||||||
|
<span>{{ file.name }}</span>
|
||||||
|
<span class="text-caption app-text-muted-2">
|
||||||
|
{{ file.size }} •
|
||||||
|
<q-spinner-ios
|
||||||
|
v-if="i % 2 === 0"
|
||||||
|
class="q-mx-xs"
|
||||||
|
color="primary"
|
||||||
|
size="1.5em"
|
||||||
|
/>
|
||||||
|
<q-icon
|
||||||
|
v-else
|
||||||
|
name="mdi-check-circle"
|
||||||
|
color="positive"
|
||||||
|
size="1rem"
|
||||||
|
/>
|
||||||
|
Uploading...
|
||||||
|
</span>
|
||||||
|
</article>
|
||||||
|
<q-btn
|
||||||
|
icon="mdi-close"
|
||||||
|
flat
|
||||||
|
rounded
|
||||||
|
size="sm"
|
||||||
|
padding="0"
|
||||||
|
class="q-ml-auto self-start"
|
||||||
|
style="color: hsl(var(--text-mute))"
|
||||||
|
@click="deleteItem(slipFile[i].file, j)"
|
||||||
|
/>
|
||||||
|
<q-linear-progress
|
||||||
|
:value="40"
|
||||||
|
class="q-mt-sm rounded"
|
||||||
|
color="info"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</q-expansion-item>
|
</q-expansion-item>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -511,4 +577,9 @@ watch(
|
||||||
.dark .badge-card__Split {
|
.dark .badge-card__Split {
|
||||||
--_color: var(--blue-10-hsl);
|
--_color: var(--blue-10-hsl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.upload-section {
|
||||||
|
border: 3px solid var(--border-color);
|
||||||
|
border-style: dashed;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import {
|
||||||
QuotationStats,
|
QuotationStats,
|
||||||
} from './types';
|
} from './types';
|
||||||
import { PaginationResult } from 'src/types';
|
import { PaginationResult } from 'src/types';
|
||||||
|
import { AxiosInstance } from 'axios';
|
||||||
|
|
||||||
export const useQuotationStore = defineStore('quotation-store', () => {
|
export const useQuotationStore = defineStore('quotation-store', () => {
|
||||||
const data = ref<Quotation[]>([]);
|
const data = ref<Quotation[]>([]);
|
||||||
|
|
@ -25,7 +26,7 @@ export const useQuotationStore = defineStore('quotation-store', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
async function getQuotationStats() {
|
async function getQuotationStats() {
|
||||||
const res = await api.get<QuotationStats>(`/quotation/stats`);
|
const res = await api.get<QuotationStats>('/quotation/stats');
|
||||||
if (res.status < 400) {
|
if (res.status < 400) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
|
@ -128,6 +129,61 @@ export const useQuotationStore = defineStore('quotation-store', () => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function managePaymentFile(api: AxiosInstance) {
|
||||||
|
return {
|
||||||
|
listFile: async (opts: { quotationId: string; paymentId: string }) => {
|
||||||
|
const res = await api.get<string[]>(`/${base}/${opts.quotationId}/file`);
|
||||||
|
if (res.status >= 400) return false;
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
getFile: async (opts: {
|
||||||
|
group: T;
|
||||||
|
parentId: string;
|
||||||
|
fileId: string;
|
||||||
|
download?: boolean;
|
||||||
|
}) => {
|
||||||
|
const url = `/${base}/${opts.parentId}/file-${opts.group}/${opts.fileId}`;
|
||||||
|
const res = await api.get<string>(url);
|
||||||
|
if (opts.download) {
|
||||||
|
fetch(res.data)
|
||||||
|
.then(async (res) => await res.blob())
|
||||||
|
.then((blob) => {
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.download = opts.fileId;
|
||||||
|
a.href = window.URL.createObjectURL(blob);
|
||||||
|
a.click();
|
||||||
|
a.remove();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
putFile: async (opts: {
|
||||||
|
group: T;
|
||||||
|
parentId: string;
|
||||||
|
fileId: string;
|
||||||
|
file: File;
|
||||||
|
}) => {
|
||||||
|
const res = await api.put(
|
||||||
|
`/${base}/${opts.parentId}/file-${opts.group}/${opts.fileId}`,
|
||||||
|
opts.file,
|
||||||
|
{
|
||||||
|
headers: { 'Content-Type': opts.file.type },
|
||||||
|
onUploadProgress: (e) => console.log(e),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (res.status < 400) return true;
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
delFile: async (opts: { group: T; parentId: string; fileId: string }) => {
|
||||||
|
const res = await api.delete(
|
||||||
|
`/${base}/${opts.parentId}/file-${opts.group}/${opts.fileId}`,
|
||||||
|
);
|
||||||
|
if (res.status < 400) return true;
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export const useQuotationPayment = defineStore('quotation-payment', () => {
|
export const useQuotationPayment = defineStore('quotation-payment', () => {
|
||||||
async function getQuotationPayment(quotationId: string) {
|
async function getQuotationPayment(quotationId: string) {
|
||||||
const res = await api.get<
|
const res = await api.get<
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue