create danh-muc-bai-viet page

parent ea171371
...@@ -72,4 +72,5 @@ export enum API_PATHS { ...@@ -72,4 +72,5 @@ export enum API_PATHS {
updateCustomer = 'customer/update', updateCustomer = 'customer/update',
getPostCategory = 'postCategory', getPostCategory = 'postCategory',
addPost = 'post/add', addPost = 'post/add',
getListCategoryPost = 'postCategory',
} }
import { i18n } from 'src/boot/i18n';
import { defineComponent, Ref, ref } from 'vue';
import UploadImage from 'components/upload-image/index.vue';
import { PostType } from 'src/assets/type';
export default defineComponent({
// name: 'ComponentName'
components: { UploadImage },
props: {
isOpenAddDialog: { type: Boolean, required: true },
},
setup(props, context) {
const name: Ref<string | null> = ref(null);
const title: Ref<string | null> = ref(null);
const image: Ref<string | null> = ref(null);
const status: Ref<number> = ref(1);
const nameRules = [
(val?: string) =>
(val && val.trim().length) ||
i18n.global.t('post.validateMessages.requireName'),
];
const file: Ref<File | string> = ref('');
const urlFileLocal: Ref<string> = ref('');
const keywordSearch: Ref<string | null> = ref(null);
const userTableColumnsPost = [
{
name: 'stt',
field: 'stt',
required: true,
label: i18n.global.t('postCategory.tableColumnsPost.stt'),
align: 'center',
sortable: false,
},
{
name: 'name',
field: 'name',
required: true,
label: i18n.global.t('postCategory.tableColumnsPost.name'),
align: 'center',
headerStyle: 'text-align: center !important;',
sortable: false,
},
{
name: 'createBy',
field: 'createBy',
required: true,
label: i18n.global.t('postCategory.tableColumnsPost.createBy'),
headerStyle: 'text-align: center !important;',
align: 'left',
sortable: false,
},
{
name: 'updateTime',
field: 'updateTime',
required: true,
label: i18n.global.t('postCategory.tableColumnsPost.updateTime'),
headerStyle: 'text-align: center !important;',
align: 'left',
sortable: false,
},
{
name: 'status',
field: 'status',
required: true,
label: i18n.global.t('postCategory.tableColumnsPost.status'),
align: 'center',
sortable: false,
},
{
name: 'action',
field: 'action',
required: true,
label: i18n.global.t('postCategory.tableColumnsPost.action'),
align: 'center',
sortable: false,
},
];
const userTableRowsPost: Ref<PostType[]> = ref([]);
const uploadImage = (value: FileList) => {
urlFileLocal.value = URL.createObjectURL(value[0]);
file.value = value[0];
image.value = urlFileLocal.value;
console.log(value, 'FileList');
};
const getListPosts = () => {
console.log('getListPosts');
};
return {
name,
title,
image,
status,
nameRules,
file,
urlFileLocal,
uploadImage,
userTableColumnsPost,
userTableRowsPost,
keywordSearch,
getListPosts,
};
},
emits: [
'update:isOpenAddDialog',
'click:closeBtnDialog',
'SetImage',
'deleteImage',
],
});
<template>
<q-dialog
persistent
:model-value="isOpenAddDialog"
@update:model-value="$emit('update:isOpenAddDialog', $event)"
>
<q-card class="full-width" style="max-width: 60rem" bordered>
<q-form greedy @submit.prevent>
<q-card-section class="q-pa-none">
<q-item>
<q-item-section>
<q-item-label class="text-h6 text-weight-regular">
{{ $t('postCategory.title.addPost') }}
</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)"
>
<q-input
v-model="name"
:label="$t('postCategory.labelInput.namePost')"
type="text"
class="q-my-sm"
outlined
:rules="nameRules"
></q-input>
<q-input
v-model="title"
:label="$t('postCategory.labelInput.description')"
type="text"
class="q-my-sm"
outlined
></q-input>
<div class="row">
<div class="col-6">
<q-card v-if="image" flat style="max-height: 200px">
<div align="center">
<q-img
:src="image"
style="max-height: 200px; aspect-ratio: 16/9"
>
</q-img>
</div>
</q-card>
<q-card v-else flat style="max-height: 200px" class="q-mt-md">
<div align="center">
<q-img
src="~/assets/default.jpeg"
style="max-height: 200px; aspect-ratio: 16/9"
>
</q-img>
</div>
</q-card>
<UploadImage
class="q-mt-xs"
:isBtn="true"
@selectedFile="uploadImage"
></UploadImage>
</div>
</div>
<div class="q-mt-md">
<span class="text-h6 text-weight-regular">{{
$t('customerRank.dialogLabel.fieldLabels.status')
}}</span
><q-toggle
v-model="status"
:true-value="1"
:false-value="2"
size="56px"
></q-toggle>
</div>
</q-card-section>
<q-card-section>
<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('postCategory.title.listPosts') }}
<q-separator vertical spaced />
</div>
<q-space></q-space>
<div class="col-2">
<q-input
v-model="keywordSearch"
dense
outlined
:label="$t('postCategory.tableColumnsPost.name')"
clearable
></q-input>
</div>
<div class="col-auto">
<q-btn
color="primary"
no-caps
:label="$t('crudActions.search')"
style="width: 100px"
@click="getListPosts"
>
</q-btn>
</div>
<div class="col-auto">
<q-btn
color="primary"
no-caps
:label="$t('crudActions.add')"
style="width: 100px"
>
</q-btn>
</div>
<div class="col-12 q-mt-sm">
<q-table
:rows="userTableRowsPost"
:columns="userTableColumnsPost"
:no-data-label="$t('emptyData')"
row-key="name"
separator="cell"
hide-pagination
>
<template v-slot:body-cell-stt="item">
<q-td style="padding: 0; height: 100%">
<div align="center">
{{ item.rowIndex + 1 }}
</div>
</q-td>
</template>
<template v-slot:body-cell-status="rowData">
<q-td>
<div align="center">
<q-chip
:color="rowData.value === 1 ? 'positive' : 'orange'"
text-color="white"
size="sm"
>
{{
rowData.value === 1
? $t('customer.statusLabel.active')
: $t('customer.statusLabel.inactive')
}}
</q-chip>
</div>
</q-td>
</template>
<template v-slot:body-cell-action>
<q-td style="padding: 0; height: 100%">
<div align="center">
<q-btn
flat
round
color="primary"
icon="mdi-delete-outline"
>
<q-tooltip :offset="[20, 10]">{{
$t('customer.toolTipMessage.deleteCustomer')
}}</q-tooltip>
</q-btn>
</div>
</q-td>
</template>
</q-table>
</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('post.crudActions.cancel')"
@click="$emit('click:closeBtnDialog')"
/>
<q-btn
type="submit"
color="primary"
no-caps
style="width: 90px"
:label="$t('post.crudActions.save')"
/>
</div>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
</template>
<script lang="ts" src="./AddPostCategory.ts"></script>
import { defineComponent } from 'vue';
export default defineComponent({
// name: 'ComponentName'
});
<template>
<div>My component</div>
</template>
<script lang="ts" src="./ListPostDialog.ts"></script>
import { defineComponent } from 'vue';
export default defineComponent({
// name: 'ComponentName'
});
<template>
<div>My component</div>
</template>
<script lang="ts" src="./UpdatePostCategory.ts"></script>
...@@ -687,4 +687,35 @@ export default { ...@@ -687,4 +687,35 @@ export default {
updatePostAccess: 'Cập nhật bài viết thành công', updatePostAccess: 'Cập nhật bài viết thành công',
}, },
}, },
// Danh mục bài viết
postCategory: {
title: {
postCategory: 'Danh sách danh mục bài viết',
addPost: 'Thêm mới danh mục bài viết',
editPost: 'Cập nhật danh mục bài viết',
listPosts: 'Danh sách bài viết',
},
tableColumnsPostCategory: {
stt: 'STT',
name: 'Tên danh mục',
image: 'Ảnh bìa',
title: 'Mô tả ngắn',
status: 'Trạng thái',
action: 'Chức năng',
},
tableColumnsPost: {
stt: 'STT',
name: 'Tên bài viết',
createBy: 'Người sửa gần nhất',
updateTime: 'Thời gian cập nhật gần nhất',
status: 'Trạng thái',
action: 'Chức năng',
},
labelInput: {
namePost: 'Tên danh mục',
description: 'Mô tả ngắn',
uploadImg: 'Tải lên ảnh bìa',
},
},
}; };
import { defineComponent } from 'vue' import { i18n } from 'src/boot/i18n';
import { defineComponent, onMounted, Ref, ref } from 'vue';
import { API_PATHS, config } from 'src/assets/configurations';
import { AxiosResponse } from 'axios';
import { api, BaseResponseBody } from 'src/boot/axios';
import { CategoryPostType } from 'src/assets/type';
import AddCategoryPostDialog from 'components/post-category/add-post-category/index.vue';
// import { Dialog, Notify } from 'quasar';
export default defineComponent({ export default defineComponent({
// name: 'PageName' components: {
}) AddCategoryPostDialog,
\ No newline at end of file },
setup() {
const configImg = config;
const keywordSearch: Ref<string | null> = ref(null);
const userTableColumnsCategoryPost = [
{
name: 'stt',
field: 'stt',
required: true,
label: i18n.global.t('postCategory.tableColumnsPostCategory.stt'),
align: 'center',
sortable: false,
},
{
name: 'name',
field: 'name',
required: true,
label: i18n.global.t('postCategory.tableColumnsPostCategory.name'),
align: 'center',
headerStyle: 'text-align: center !important;',
sortable: false,
},
{
name: 'image',
field: 'image',
required: true,
label: i18n.global.t('postCategory.tableColumnsPostCategory.image'),
headerStyle: 'text-align: center !important;',
align: 'left',
sortable: false,
},
{
name: 'title',
field: 'title',
required: true,
label: i18n.global.t('postCategory.tableColumnsPostCategory.title'),
headerStyle: 'text-align: center !important;',
align: 'left',
sortable: false,
},
{
name: 'status',
field: 'status',
required: true,
label: i18n.global.t('postCategory.tableColumnsPostCategory.status'),
align: 'center',
sortable: false,
},
{
name: 'action',
field: 'action',
required: true,
label: i18n.global.t('postCategory.tableColumnsPostCategory.action'),
align: 'center',
sortable: false,
},
];
const userTableRowsCategoryPost: Ref<CategoryPostType[]> = ref([]);
const isOpenAddDialog: Ref<boolean> = ref(false);
const getListCategoryPost = async () => {
try {
const response = (await api({
url: API_PATHS.getListCategoryPost,
method: 'GET',
params: {
name: keywordSearch.value,
},
})) as AxiosResponse<BaseResponseBody<CategoryPostType[]>>;
if (response.data.error.code === config.API_RES_CODE.OK.code) {
userTableRowsCategoryPost.value = response.data.data;
keywordSearch.value = null;
}
} catch (error) {}
};
onMounted(() => {
void getListCategoryPost();
});
return {
configImg,
keywordSearch,
userTableColumnsCategoryPost,
userTableRowsCategoryPost,
isOpenAddDialog,
getListCategoryPost,
};
},
});
<template> <template>
<div>CategoryPost</div> <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('postCategory.title.postCategory') }}
<q-separator vertical spaced />
</div>
<q-space></q-space>
<div class="col-2">
<q-input
v-model="keywordSearch"
dense
outlined
:label="$t('postCategory.tableColumnsPostCategory.name')"
clearable
></q-input>
</div>
<div class="col-auto">
<q-btn
color="primary"
no-caps
:label="$t('crudActions.search')"
style="width: 100px"
@click="getListCategoryPost"
>
</q-btn>
</div>
<div class="col-auto">
<q-btn
color="primary"
no-caps
:label="$t('crudActions.add')"
style="width: 100px"
@click="isOpenAddDialog = true"
>
</q-btn>
</div>
<div class="col-12 q-mt-sm">
<q-table
:rows="userTableRowsCategoryPost"
:columns="userTableColumnsCategoryPost"
:no-data-label="$t('emptyData')"
row-key="name"
separator="cell"
hide-pagination
class="sticky-header-table"
>
<template v-slot:body-cell-stt="item">
<q-td style="padding: 0; height: 100%">
<div align="center">
{{ item.rowIndex + 1 }}
</div>
</q-td>
</template>
<template v-slot:body-cell-image="image">
<q-td style="padding: 0; height: 100%" class="flex flex-center">
<q-img
style="width: 7rem; height: 5rem"
fit="contain"
:ratio="16 / 9"
:src="
image.row.image
? configImg.API_IMAGE_ENDPOINT + image.row.image
: image.row.image
"
></q-img>
</q-td>
</template>
<template v-slot:body-cell-status="rowData">
<q-td>
<div align="center">
<q-chip
:color="rowData.value === 1 ? 'positive' : 'orange'"
text-color="white"
size="sm"
>
{{
rowData.value === 1
? $t('customer.statusLabel.active')
: $t('customer.statusLabel.inactive')
}}
</q-chip>
</div>
</q-td>
</template>
<template v-slot:body-cell-action>
<q-td style="padding: 0; height: 100%">
<div align="center">
<q-btn flat round color="primary" icon="mdi-account-edit-outline">
<q-tooltip :offset="[20, 10]">{{
$t('customer.toolTipMessage.updateCustomerInfo')
}}</q-tooltip>
</q-btn>
<q-btn flat round color="primary" icon="mdi-delete-outline">
<q-tooltip :offset="[20, 10]">{{
$t('customer.toolTipMessage.deleteCustomer')
}}</q-tooltip>
</q-btn>
</div>
</q-td>
</template>
</q-table>
</div>
<AddCategoryPostDialog
v-model:is-open-add-dialog="isOpenAddDialog"
@click:closeBtnDialog="isOpenAddDialog = false"
/>
</div>
</template> </template>
<script lang="ts" src="./CategoryPost.ts"></script> <script lang="ts" src="./CategoryPost.ts"></script>
...@@ -20,6 +20,7 @@ export default defineComponent({ ...@@ -20,6 +20,7 @@ export default defineComponent({
Pagination, Pagination,
}, },
setup() { setup() {
const configImg = config;
const userTableColumnsArtist = [ const userTableColumnsArtist = [
{ {
required: true, required: true,
...@@ -272,6 +273,7 @@ export default defineComponent({ ...@@ -272,6 +273,7 @@ export default defineComponent({
void getWorkOptions(); void getWorkOptions();
}); });
return { return {
configImg,
userTableColumnsArtist, userTableColumnsArtist,
userTableRowsArtist, userTableRowsArtist,
getListArtists, getListArtists,
......
...@@ -85,7 +85,11 @@ ...@@ -85,7 +85,11 @@
style="width: 7rem; height: 5rem" style="width: 7rem; height: 5rem"
fit="contain" fit="contain"
:ratio="16 / 9" :ratio="16 / 9"
:src="`http://cms.vab.xteldev.com/file/upload/${avatar.row.avatar}`" :src="
avatar.row.avatar
? configImg.API_IMAGE_ENDPOINT + avatar.row.avatar
: avatar.row.avatar
"
></q-img> ></q-img>
</q-td> </q-td>
</template> </template>
......
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