Commit ce18b923 authored by Tình Trương's avatar Tình Trương

update

parent 21be3682
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
<q-item-label class="text-h6 text-weight-regular">{{ <q-item-label class="text-h6 text-weight-regular">{{
isUpdate isUpdate
? $t('banner.dialogLabel.title.addBanner') ? $t('banner.dialogLabel.title.addBanner')
: $t('field.dialogLabel.title.updateBanner') : $t('banner.dialogLabel.title.updateBanner')
}}</q-item-label> }}</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
......
<template>
<q-dialog
persistent
:model-value="isOpened"
@update:model-value="$emit('update:isOpened', $event)"
>
<q-card class="full-width" style="max-width: 50rem" bordered>
<q-form
greedy
@submit.prevent="
$emit('saveBankAccountInfo', {});
$emit('update:isOpened', false);
"
>
<q-card-section class="q-pa-none">
<q-item>
<q-item-section>
<q-item-label class="text-h6 text-weight-regular">{{
isUpdate
? $t('infoVAB.dialogLabel.title.addBankAccount')
: $t('infoVAB.dialogLabel.title.updateBankAccount')
}}</q-item-label>
</q-item-section>
</q-item>
</q-card-section>
<q-separator />
<q-card-section
class="overflow-auto"
style="max-height: calc(100vh - 10rem)"
>
<div class="row q-col-gutter-sm">
<div class="col-6">
<q-select
:model-value="bank"
@update:model-value="$emit('update:bank', $event)"
:label="$t('infoVAB.dialogLabel.infoVABLabels.bank')"
:options="bankOptions"
:rules="bankRules"
map-options
option-value="id"
option-label="name"
class="q-my-sm"
outlined
></q-select>
<q-select
:model-value="cardType"
@update:model-value="$emit('update:cardType', $event)"
:label="$t('infoVAB.dialogLabel.infoVABLabels.cardType')"
:options="cardTypeOptions"
:rules="cardTypeRules"
map-options
option-value="id"
option-label="name"
class="q-my-sm"
outlined
></q-select>
<q-input
:model-value="cardCode"
@update:model-value="$emit('update:cardCode', $event)"
:label="$t('infoVAB.dialogLabel.infoVABLabels.cardCode')"
type="text"
class="q-my-sm"
outlined
:rules="cardCodeRules"
clearable
></q-input>
</div>
<div class="col-6">
<q-input
:model-value="userCard"
@update:model-value="$emit('update:userCard', $event)"
:label="$t('infoVAB.dialogLabel.infoVABLabels.userCard')"
type="text"
class="q-my-sm"
outlined
:rules="userCardRules"
clearable
></q-input>
<q-input
:model-value="numberCard"
@update:model-value="$emit('update:numberCard', $event)"
:label="$t('infoVAB.dialogLabel.infoVABLabels.numberCard')"
type="number"
class="q-my-sm"
outlined
:rules="numberCardRules"
clearable
></q-input>
<div class="flex q-pt-sm">
<div class="flex flex-center text-body1 q-ml-xs">Mặc định</div>
<q-checkbox
:model-value="isDefault"
:true-value="1"
:false-value="2"
@update:model-value="$emit('update:isDefault', $event)"
/>
</div>
</div>
</div>
</q-card-section>
<q-card-actions align="right">
<div>
<q-btn
color="grey"
no-caps
style="width: 90px"
class="q-mr-sm"
:label="$t('infoVAB.crudActions.cancel')"
@click="$emit('update:isOpened', false)"
/>
<q-btn
type="submit"
color="primary"
no-caps
style="width: 90px"
:label="$t('infoVAB.crudActions.save')"
/>
</div>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { i18n } from 'src/boot/i18n';
export default defineComponent({
props: {
isOpened: {
type: Boolean,
required: true,
},
isUpdate: { type: Boolean, default: false },
bank: { type: Number, required: true },
bankOptions: { type: Array, required: true },
cardType: { type: Number, required: true },
cardTypeOptions: { type: Array, required: true },
cardCode: { type: String, required: true },
userCard: { type: String, required: true },
numberCard: { type: Number, required: true },
isDefault: { type: Number, required: true },
},
setup() {
const bankRules = [
(val?: number) =>
val !== undefined ||
i18n.global.t('infoVAB.validateMessages.requireBank'),
];
const cardTypeRules = [
(val?: number) =>
val !== undefined ||
i18n.global.t('infoVAB.validateMessages.requireCardType'),
];
const cardCodeRules = [
(val?: string) =>
(val && val.trim().length) ||
i18n.global.t('infoVAB.validateMessages.requireCardCode'),
];
const numberCardRules = [
(val?: string) =>
(val && val.trim().length) ||
i18n.global.t('infoVAB.validateMessages.requireNumberCard'),
];
const userCardRules = [
(val?: string) =>
(val && val.trim().length) ||
i18n.global.t('infoVAB.validateMessages.requireUserCard'),
];
return {
bankRules,
cardTypeRules,
cardCodeRules,
numberCardRules,
userCardRules,
};
},
emits: [
'update:isOpened',
'update:cardCode',
'update:bank',
'update:numberCard',
'update:userCard',
'update:cardType',
'update:isDefault',
'saveBankAccountInfo',
],
});
</script>
...@@ -790,4 +790,83 @@ export default { ...@@ -790,4 +790,83 @@ export default {
updateBannerAccess: 'Cập nhật banner thành công', updateBannerAccess: 'Cập nhật banner thành công',
}, },
}, },
//thông tin chung
infoVAB: {
title: 'Thông tin VAB',
uploadImg: 'Tải lên ảnh logo VAB',
titleBankAccount: 'Danh sách tài khoản ngân hàng thụ hưởng',
tableColumnsInfoVAB: {
stt: 'STT',
name: 'Tên công ty',
image: 'Logo',
website: 'Website',
phone: 'Số điện thoại',
email: 'Email',
address: 'Địa chỉ',
action: 'Chức năng',
//ds bankaccount
cardCode: 'Số tài khoản',
userCard: 'Chủ tài khoản',
numberCard: 'Số ghi trên thẻ',
bank: 'Ngân hàng',
cardType: 'Loại thẻ',
isDefault: 'Mặc định',
},
dialogLabel: {
title: {
updateInfoVAB: 'Cập nhật thông tin VAB',
//ngân hàng
addBankAccount: 'Thêm ngân hàng thụ hưởng',
updateBankAccount: 'Cập nhật ngân hàng thụ hưởng',
},
infoVABLabels: {
name: 'Tên công ty *',
website: 'Website *',
phone: 'Số điện thoại *',
email: 'Email *',
address: 'Địa chỉ *',
//ngân hàng
cardCode: 'Số tài khoản *',
numberCard: 'Số ghi trên thẻ *',
bank: 'Ngân hàng *',
cardType: 'Loại thẻ *',
userCard: 'Chủ tài khoản *',
},
},
toolTipMessage: {
updateInfoVAB: 'Cập nhật',
deleteInfoVAB: 'Xoá',
//ngân hàng
updateBankAccount: 'Cập nhật',
deleteBankAccount: 'Xóa ngân hàng',
},
crudActions: {
save: 'Lưu',
cancel: 'Đóng',
},
validateMessages: {
requireName: 'Vui lòng nhập Tên công ty',
requireWebsite: 'Vui lòng nhập Website',
requirePhone: 'Vui lòng nhập Số điện thoại',
requireEmail: 'Vui lòng nhập Email',
requireAddress: 'Vui lòng nhập Địa chỉ',
//ngân hàng
requireBank: 'Vui lòng chọn Ngân hàng',
requireCardType: 'Vui lòng chọn Loại thẻ',
requireCardCode: 'Vui lòng nhập Số tài khoản',
requireNumberCard: 'Vui lòng nhập Số ghi trên thẻ',
requireUserCard: 'Vui lòng nhập Chủ tài khoản',
},
confirmActionsTitle: {
confirmDeleteInfoVABTitle: 'Xác nhận',
confirmDeleteInfoVABCancelBtnLabel: 'Huỷ',
confirmDeleteInfoVABContent:
'Bạn có chắc chắn muốn xoá Thông tin VAB này không?',
},
actionMessages: {
deleteInfoVABAccess: 'Xoá thông tin VAB thành công',
updateInfoVABAccess: 'Cập nhật thông tin VAB thành công',
},
},
}; };
...@@ -129,14 +129,13 @@ ...@@ -129,14 +129,13 @@
<script lang="ts"> <script lang="ts">
import { i18n } from 'src/boot/i18n'; import { i18n } from 'src/boot/i18n';
import { defineComponent, onMounted, ref, Ref } from 'vue'; import { defineComponent, onMounted, ref, Ref } from 'vue';
import { API_PATHS } from 'src/assets/configurations';
import { AxiosResponse } from 'axios'; import { AxiosResponse } from 'axios';
import { api, BaseResponseBody } from 'src/boot/axios'; import { api, BaseResponseBody } from 'src/boot/axios';
import { BannerType, FileUploadType } from 'src/assets/type'; import { FileUploadType } from 'src/assets/type';
import { config } from 'src/assets/configurations'; import { config } from 'src/assets/configurations';
import { BannerStatus } from 'src/assets/enums'; import { BannerStatus } from 'src/assets/enums';
import AddUpdateBannerDialog from 'components/add-update-banner/index.vue'; import AddUpdateBannerDialog from 'components/add-update-banner/index.vue';
import { Dialog, Notify } from 'quasar'; import { Dialog } from 'quasar';
export type AvatarType = { export type AvatarType = {
file?: File; file?: File;
...@@ -233,7 +232,7 @@ export default defineComponent({ ...@@ -233,7 +232,7 @@ export default defineComponent({
const typeOptions: Ref<unknown[]> = ref([]); const typeOptions: Ref<unknown[]> = ref([]);
const locationOptions: Ref<unknown[]> = ref([]); const locationOptions: Ref<unknown[]> = ref([]);
const status: Ref<number> = ref(BannerStatus.active); const status: Ref<number> = ref(BannerStatus.active);
const bannerId: Ref<number | undefined> = ref(undefined); // const bannerId: Ref<number | undefined> = ref(undefined);
const nameBanner = ref(''); const nameBanner = ref('');
const avatarFile: Ref<File | null> = ref(null); const avatarFile: Ref<File | null> = ref(null);
const avatarUploaded: Ref<string> = ref(''); const avatarUploaded: Ref<string> = ref('');
...@@ -252,7 +251,7 @@ export default defineComponent({ ...@@ -252,7 +251,7 @@ export default defineComponent({
// } // }
}; };
const confirmDeleteBanner = (id: number) => { const confirmDeleteBanner = () => {
Dialog.create({ Dialog.create({
title: i18n.global.t( title: i18n.global.t(
'banner.confirmActionsTitle.confirmDeleteBannerTitle' 'banner.confirmActionsTitle.confirmDeleteBannerTitle'
...@@ -265,12 +264,12 @@ export default defineComponent({ ...@@ -265,12 +264,12 @@ export default defineComponent({
), ),
color: 'negative', color: 'negative',
}).onOk(() => { }).onOk(() => {
void deleteBanner(id); void deleteBanner();
}); });
}; };
//gói api xóa //gói api xóa
const deleteBanner = async (id: number) => { const deleteBanner = async () => {
// try { // try {
// const deleteResult = (await api({ // const deleteResult = (await api({
// url: API_PATHS.deleteBanner, // url: API_PATHS.deleteBanner,
...@@ -317,13 +316,13 @@ export default defineComponent({ ...@@ -317,13 +316,13 @@ export default defineComponent({
// } // }
}; };
const openUpdateBannerDialog = (id: number) => { const openUpdateBannerDialog = () => {
void getDetailBanner(id); void getDetailBanner();
updateBannerDialogIsOpened.value = true; updateBannerDialogIsOpened.value = true;
}; };
//gọi api detail //gọi api detail
const getDetailBanner = async (id: number) => { const getDetailBanner = async () => {
// try { // try {
// const response = (await api({ // const response = (await api({
// url: API_PATHS.getDetailBanner, // url: API_PATHS.getDetailBanner,
......
<template>
<div class="row q-col-gutter-sm flex-center q-mt-sm">
<div class="col-auto text-h6 text-weight-regular flex flex-center q-mr-md">
{{ $t('infoVAB.title') }}
<q-separator vertical spaced />
</div>
<q-space></q-space>
<div class="col-12 q-mt-sm">
<q-table
:rows="infoVABTableRows"
:columns="infoVABTableColumns"
row-key="infoVABName"
separator="cell"
:no-data-label="$t('emptyData')"
hide-pagination
class="sticky-header-table"
>
<template v-slot:body-cell-action="">
<q-td style="padding: 0" class="center">
<q-btn
flat
round
color="primary"
icon="mdi-account-edit-outline"
@click="openUpdateInfoVABDialog()"
>
<q-tooltip :offset="[20, 10]">{{
$t('infoVAB.toolTipMessage.updateInfoVAB')
}}</q-tooltip>
</q-btn>
</q-td>
</template>
<template v-slot:body-cell-image="image">
<q-td style="padding: auto; height: 100%" class="flex flex-center">
<q-img
style="width: 9rem"
fit="contain"
:ratio="16 / 9"
:src="configImg.API_IMAGE_ENDPOINT + image.row.image"
></q-img>
</q-td>
</template>
</q-table>
</div>
<UpdateInfoVABDialog
v-model:isOpened="updateInfoVABDialogIsOpened"
v-model:name="name"
v-model:image="image"
v-model:website="website"
v-model:phone="phone"
v-model:email="email"
v-model:address="address"
@SetAvatar="setAvatar($event)"
@deleteAvatar="deleteAvatar"
@saveInfoVAB="updateInfoVAB"
/>
</div>
</template>
<script lang="ts">
import { i18n } from 'src/boot/i18n';
import { defineComponent, onMounted, ref, Ref } from 'vue';
import { AxiosResponse } from 'axios';
import { api, BaseResponseBody } from 'src/boot/axios';
import { FileUploadType } from 'src/assets/type';
import { config } from 'src/assets/configurations';
import UpdateInfoVABDialog from 'components/update-info-vab/update-info-vab-dialog/index.vue';
export type AvatarType = {
file?: File;
url?: string | null;
};
export default defineComponent({
components: {
UpdateInfoVABDialog,
},
setup() {
const infoVABTableColumns = [
// {
// name: 'index',
// field: 'index',
// required: true,
// label: 'STT',
// align: 'center',
// sortable: false,
// },
{
name: 'name',
field: 'name',
required: true,
label: i18n.global.t('infoVAB.tableColumnsInfoVAB.name'),
headerStyle: 'text-align: center !important;',
align: 'left',
sortable: false,
},
{
name: 'image',
field: 'image',
required: true,
label: i18n.global.t('infoVAB.tableColumnsInfoVAB.image'),
headerStyle: 'text-align: center !important;',
align: 'center',
sortable: false,
},
{
name: 'website',
field: 'website',
required: true,
label: i18n.global.t('infoVAB.tableColumnsInfoVAB.website'),
headerStyle: 'text-align: center !important;',
align: 'left',
sortable: false,
},
{
name: 'phone',
field: 'phone',
required: true,
label: i18n.global.t('infoVAB.tableColumnsInfoVAB.phone'),
headerStyle: 'text-align: center !important;',
align: 'left',
sortable: false,
},
{
name: 'email',
field: 'email',
required: true,
label: i18n.global.t('infoVAB.tableColumnsInfoVAB.email'),
headerStyle: 'text-align: center !important;',
align: 'left',
sortable: false,
},
{
name: 'address',
field: 'address',
required: true,
label: i18n.global.t('infoVAB.tableColumnsInfoVAB.address'),
headerStyle: 'text-align: center !important;',
align: 'center',
sortable: false,
},
{
name: 'action',
field: 'action',
required: true,
label: i18n.global.t('infoVAB.tableColumnsInfoVAB.action'),
headerStyle: 'text-align: center !important;',
align: 'center',
sortable: false,
},
];
const infoVABTableRows: Ref<unknown[]> = ref([{ name: 'aaa' }]);
const updateInfoVABDialogIsOpened = ref(false);
const name = ref('');
const phone = ref('');
const email = ref('');
const address = ref('');
const website = ref('');
const image: Ref<string | null> = ref(null);
const infoVABId: Ref<number | undefined> = ref(undefined);
const avatarFile: Ref<File | null> = ref(null);
const avatarUploaded: Ref<string> = ref('');
//gọi api ds
const getListInfoVAB = async () => {
// const response = (await api({
// url: API_PATHS.getListBanner,
// method: 'GET',
// params: {
// name: nameBanner.value,
// },
// })) as AxiosResponse<BaseResponseBody<BannerType[]>>;
// if (response.data.error.code === config.API_RES_CODE.OK.code) {
// bannerTableRows.value = response.data.data;
// }
};
const openUpdateInfoVABDialog = () => {
void getDetailInfoVAB();
updateInfoVABDialogIsOpened.value = true;
};
//gọi api detail
const getDetailInfoVAB = async () => {
// try {
// const response = (await api({
// url: API_PATHS.getDetailBanner,
// method: 'GET',
// params: {
// id: id,
// },
// })) as AxiosResponse<BaseResponseBody<DetailBannerType>>;
// if (response.data.error.code === config.API_RES_CODE.OK.code) {
// bannerId.value = response.data.data.id;
// name.value = response.data.data.name;
// status.value = response.data.data.status;
// }
// } catch (error) {}
};
//gọi api update
const updateInfoVAB = async () => {
// const data = {
// id: bannerId.value,
// name: name.value,
// status: status.value,
// };
// const response = (await api({
// url: API_PATHS.updateBanner,
// method: 'POST',
// data,
// })) as AxiosResponse<BaseResponseBody<UpdateBannerType[]>>;
// if (response.data.error.code === config.API_RES_CODE.OK.code) {
// updateBannerDialogIsOpened.value = false;
// Notify.create({
// type: 'positive',
// message: i18n.global.t('banner.actionMessages.updateBannerAccess'),
// actions: [{ icon: 'close', color: 'white' }],
// });
// void getListBanner();
// }
};
const setAvatar = (value: { file?: File; url?: string }) => {
avatarFile.value = value.file as File;
image.value = value.url as string;
};
const callApiUploadAvatar = async (file: File) => {
try {
const bodyFormData = new FormData();
bodyFormData.append('file', file);
const response = (await api({
headers: { 'Content-Type': 'multipart/form-data' },
url: 'http://cms.vab.xteldev.com/file/upload/',
method: 'POST',
data: bodyFormData,
})) as AxiosResponse<BaseResponseBody<FileUploadType>>;
if (response.data.error.code === config.API_RES_CODE.OK.code) {
return response.data.data.fileName;
} else {
return '';
}
} catch (error) {
return '';
}
};
const deleteAvatar = () => {
image.value = null;
};
const configImg = config;
onMounted(() => {
void getListInfoVAB();
});
return {
updateInfoVABDialogIsOpened,
infoVABTableColumns,
infoVABTableRows,
getListInfoVAB,
name,
phone,
email,
address,
website,
infoVABId,
openUpdateInfoVABDialog,
getDetailInfoVAB,
updateInfoVAB,
image,
setAvatar,
callApiUploadAvatar,
deleteAvatar,
configImg,
avatarUploaded,
};
},
});
</script>
...@@ -15,6 +15,7 @@ export enum Pages { ...@@ -15,6 +15,7 @@ export enum Pages {
post = 'bai-viet', post = 'bai-viet',
postCategory = 'danh-muc-bai-viet', postCategory = 'danh-muc-bai-viet',
banner = 'banner', banner = 'banner',
infoVAB = 'thong-tin-chung',
} }
const routes: RouteRecordRaw[] = [ const routes: RouteRecordRaw[] = [
...@@ -92,6 +93,11 @@ const routes: RouteRecordRaw[] = [ ...@@ -92,6 +93,11 @@ const routes: RouteRecordRaw[] = [
component: () => import('pages/banner/index.vue'), component: () => import('pages/banner/index.vue'),
name: Pages.banner, name: Pages.banner,
}, },
{
path: 'thong-tin-chung',
component: () => import('pages/thong-tin-chung/index.vue'),
name: Pages.infoVAB,
},
], ],
}, },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment