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

update

parent 796d2d59
......@@ -73,4 +73,7 @@ export enum API_PATHS {
getPostCategory = 'postCategory',
addPost = 'post/add',
getListCategoryPost = 'postCategory',
getLanguage = 'language',
getDetailPost = 'post/detail',
updatePost = 'post/update',
}
......@@ -331,6 +331,7 @@ export type LanguageType = {
code: string;
name: string;
status: number;
isDefault?: number;
};
export type LangType = {
......@@ -373,3 +374,15 @@ export type PostCategoryDetailType = {
updateBy?: string;
updateTime?: string;
};
export type PostAddType = {
id: number;
image: string;
status: number;
langs: LangType[];
category: CategoryPostType;
createBy?: string;
createTime?: string;
updateBy?: string;
updateTime?: string;
};
......@@ -31,125 +31,235 @@
>
<div class="row q-col-gutter-sm">
<div class="col-12">
<div class="row q-mt-sm flex-center">
<div>
<q-card style="margin-bottom: 8px" v-if="image !== null">
<q-img
:src="image"
style="height: 268px; width: 350px"
@click="uploadAvatar"
>
</q-img>
<q-icon
name="mdi-close-circle"
color="red"
style="position: absolute; right: 0; font-size: 18px"
@click="deleteAvatar"
></q-icon>
</q-card>
<q-card v-else style="margin-bottom: 8px">
<q-img
src="~/assets/noavatar.png"
style="height: 268px; width: 350px"
></q-img>
</q-card>
<q-card @click="uploadAvatar">
<div align="center" class="flex flex-center q-py-xs">
<q-icon
name="mdi-plus-circle-outline"
:size="'xs'"
></q-icon>
<div class="q-mt-xs">
{{ $t('post.uploadImg') }}
</div>
</div>
<input
ref="upload"
hidden
type="file"
@change="selectedFile($event.target.files)"
accept="image/png, image/jpeg"
/>
</q-card>
</div>
</div>
<q-select
:model-value="category"
@update:model-value="$emit('update:category', $event)"
:label="$t('post.dialogLabel.postLabels.category')"
:rules="categoryRules"
:options="categoryOptions"
map-options
option-value="id"
option-label="name"
type="text"
class="q-my-sm"
outlined
></q-select>
<q-tabs
v-model="tab"
dense
class="text-grey"
active-color="primary"
indicator-color="primary"
align="justify"
align="left"
narrow-indicator
>
<q-tab
v-for="(info, index) in languageOptions"
:key="`${info.id}-${index}`"
:name="info.code"
:label="info.name"
:key="`${info.language.id}-${index}`"
:name="info.language.code"
:label="info.language.name"
no-caps
/>
</q-tabs>
<q-separator />
<q-tab-panels v-model="tab" animated>
<q-tab-panel
v-for="(info, index) in languageOptions"
:key="`${info.id}-${index}`"
:name="info.code"
:key="`${info.language.id}-${index}`"
:name="info.language.code"
>
<div class="row q-mt-sm flex-center">
<div>
<q-card style="margin-bottom: 8px" v-if="image !== null">
<q-img
:src="image"
style="height: 268px; width: 350px"
@click="uploadAvatar"
>
</q-img>
<q-icon
name="mdi-close-circle"
color="red"
style="position: absolute; right: 0; font-size: 18px"
@click="deleteAvatar"
></q-icon>
</q-card>
<q-card v-else style="margin-bottom: 8px">
<q-img
src="~/assets/noavatar.png"
style="height: 268px; width: 350px"
></q-img>
</q-card>
<q-input
v-model="info.name"
:label="$t('post.dialogLabel.postLabels.name')"
type="text"
class="q-my-sm"
outlined
:rules="nameRules"
clearable
></q-input>
</q-tab-panel>
</q-tab-panels>
<q-card @click="uploadAvatar">
<div align="center" class="flex flex-center q-py-xs">
<q-icon
name="mdi-plus-circle-outline"
:size="'xs'"
></q-icon>
<div class="q-mt-xs">
{{ $t('post.uploadImg') }}
</div>
</div>
<q-tabs
v-model="tabContent"
dense
class="text-grey"
active-color="primary"
indicator-color="primary"
align="left"
narrow-indicator
>
<q-tab
v-for="(info, index) in languageOptions"
:key="`${info.language.id}-${index}`"
:name="info.language.code"
:label="info.language.name"
no-caps
/>
</q-tabs>
<input
ref="upload"
hidden
type="file"
@change="selectedFile($event.target.files)"
accept="image/png, image/jpeg"
/>
</q-card>
</div>
</div>
<q-separator />
<div class="q-pt-md">
<q-input
:model-value="name"
@update:model-value="$emit('update:name', $event)"
:label="$t('post.dialogLabel.postLabels.name')"
type="text"
class="q-my-sm"
outlined
:rules="tab === 'vn' ? nameRules : []"
clearable
></q-input>
<q-select
:model-value="category"
@update:model-value="$emit('update:category', $event)"
:label="$t('post.dialogLabel.postLabels.category')"
:rules="tab === 'vn' ? categoryRules : []"
:options="categoryOptions"
map-options
option-value="id"
option-label="name"
type="text"
class="q-my-sm"
outlined
></q-select>
<q-input
:model-value="content"
@update:model-value="$emit('update:content', $event)"
:label="$t('post.dialogLabel.postLabels.content')"
:rules="tab === 'vn' ? contentRules : []"
type="textarea"
class="q-my-sm"
outlined
clearable
></q-input>
<div>
<span class="text-body1">{{
$t('post.dialogLabel.postLabels.status')
}}</span
><q-toggle
:model-value="status"
:true-value="1"
:false-value="2"
@update:model-value="$emit('update:status', $event)"
/>
</div>
</div>
<q-tab-panels v-model="tabContent" animated>
<q-tab-panel
v-for="(info, index) in languageOptions"
:key="`${info.language.id}-${index}`"
:name="info.language.code"
>
<q-editor
v-model="info.content"
ref="editorRef"
toolbar-text-color="white"
toolbar-toggle-color="yellow-8"
toolbar-bg="primary"
style="height: 100%"
:toolbar="[
[
{
label: $q.lang.editor.align,
icon: $q.iconSet.editor.align,
fixedLabel: true,
list: 'only-icons',
options: ['left', 'center', 'right', 'justify'],
},
],
[
'bold',
'italic',
'strike',
'underline',
'subscript',
'superscript',
],
['token', 'hr', 'link', 'custom_btn'],
['print', 'fullscreen'],
[
{
label: $q.lang.editor.formatting,
icon: $q.iconSet.editor.formatting,
list: 'no-icons',
options: [
'p',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'code',
],
},
{
label: $q.lang.editor.fontSize,
icon: $q.iconSet.editor.fontSize,
fixedLabel: true,
fixedIcon: true,
list: 'no-icons',
options: [
'size-1',
'size-2',
'size-3',
'size-4',
'size-5',
'size-6',
'size-7',
],
},
{
label: $q.lang.editor.defaultFont,
icon: $q.iconSet.editor.font,
fixedIcon: true,
list: 'no-icons',
options: [
'default_font',
'arial',
'arial_black',
'comic_sans',
'courier_new',
'impact',
'lucida_grande',
'times_new_roman',
'verdana',
],
},
'removeFormat',
],
['quote', 'unordered', 'ordered', 'outdent', 'indent'],
['undo', 'redo'],
['viewsource'],
]"
:fonts="{
arial: 'Arial',
arial_black: 'Arial Black',
comic_sans: 'Comic Sans MS',
courier_new: 'Courier New',
impact: 'Impact',
lucida_grande: 'Lucida Grande',
times_new_roman: 'Times New Roman',
verdana: 'Verdana',
}"
/>
</q-tab-panel>
</q-tab-panels>
<div>
<span class="text-body1">{{
$t('post.dialogLabel.postLabels.status')
}}</span
><q-toggle
:model-value="status"
:true-value="1"
:false-value="2"
@update:model-value="$emit('update:status', $event)"
/>
</div>
</div>
</div>
......@@ -182,11 +292,7 @@
<script lang="ts">
import { defineComponent, PropType, ref } from 'vue';
import { i18n } from 'src/boot/i18n';
// import UploadImage from '../../upload-image/index.vue';
export default defineComponent({
// components: {
// UploadImage,
// },
props: {
isOpened: {
type: Boolean,
......@@ -202,9 +308,15 @@ export default defineComponent({
languageOptions: {
type: Array as PropType<
{
id: number;
code: string;
name: string;
title: string;
content: string;
status: number;
language: {
id: number;
code: string;
name: string;
};
}[]
>,
required: true,
......@@ -212,14 +324,12 @@ export default defineComponent({
},
setup(_, context) {
const selectedFile = (value: FileList) => {
console.log(value, 'valueee image');
context.emit('SetAvatar', {
file: value[0],
url: URL.createObjectURL(value[0]),
});
};
const deleteAvatar = () => {
console.log('object');
context.emit('deleteAvatar');
};
const upload = ref(null);
......@@ -239,21 +349,15 @@ export default defineComponent({
(val && val.trim().length) ||
i18n.global.t('post.validateMessages.requireImage'),
];
const contentRules = [
(val?: string) =>
(val && val.trim().length) ||
i18n.global.t('post.validateMessages.requireContent'),
];
const nameRules = [
(val?: string) =>
(val && val.trim().length) ||
i18n.global.t('post.validateMessages.requireName'),
];
const tab = ref('vn');
tab.value = 'vn';
const tab = ref('vi');
const tabContent = ref('vi');
return {
contentRules,
nameRules,
imageRules,
selectedFile,
......@@ -262,6 +366,7 @@ export default defineComponent({
uploadAvatar,
deleteAvatar,
tab,
tabContent,
};
},
emits: [
......
......@@ -86,7 +86,7 @@
style="width: 9rem"
fit="contain"
:ratio="16 / 9"
:src="image.row.image"
:src="configImg.API_IMAGE_ENDPOINT + image.row.image"
></q-img>
</q-td>
</template>
......@@ -148,7 +148,7 @@
:categoryOptions="categoryOptions"
@SetAvatar="setAvatar($event)"
@deleteAvatar="deleteAvatar"
@savePostInfo="updateNewPost"
@savePostInfo="confirmUpdatePost"
/>
</div>
</template>
......@@ -165,7 +165,9 @@ import {
PostType,
FileUploadType,
CategoryPostType,
LanguageType,
PostDetailType,
PostAddType,
} from 'src/assets/type';
import { config } from 'src/assets/configurations';
import { PostStatus } from 'src/assets/enums';
......@@ -280,8 +282,8 @@ export default defineComponent({
const postTableRows: Ref<unknown[]> = ref([]);
const addPostDialogIsOpened = ref(false);
const updatePostDialogIsOpened = ref(false);
const category: Ref<number | undefined> = ref(undefined);
const categoryOptions: Ref<unknown[]> = ref([]);
const category: Ref<CategoryPostType | undefined> = ref();
const categoryOptions: Ref<CategoryPostType[]> = ref([]);
const name = ref('');
const content = ref('');
const image: Ref<string | null> = ref(null);
......@@ -289,11 +291,9 @@ export default defineComponent({
const postId: Ref<number | undefined> = ref(undefined);
const namePost = ref('');
const avatarFile: Ref<File | null> = ref(null);
const avatarUploaded: Ref<string | null> = ref(null);
const languageOptions = ref([
{ id: 1, code: 'vn', name: 'Tiếng Việt' },
{ id: 2, code: 'en', name: 'Tiếng Anh' },
]);
const avatarUploaded: Ref<string> = ref('');
const imageChange: Ref<string> = ref('');
const languageOptions: Ref<FromType> = ref([]);
const changePageSize = () => {
pageIndex.value = 1;
......@@ -353,26 +353,29 @@ export default defineComponent({
};
const openAddPostDialog = () => {
name.value = '';
category.value = undefined;
content.value = '';
image.value = null;
void getLanguage();
status.value = PostStatus.active;
image.value = null;
category.value = undefined;
addPostDialogIsOpened.value = true;
};
//gọi api add
const addNewPost = async () => {
avatarUploaded.value = await callApiUploadAvatar(
avatarFile.value as File
);
const data = {
image: image.value,
image: avatarUploaded.value,
status: status.value,
category: category.value,
category: { id: category.value?.id },
langs: languageOptions.value,
};
const response = (await api({
url: API_PATHS.addPost,
method: 'POST',
data,
})) as AxiosResponse<BaseResponseBody<PostDetailType[]>>;
})) as AxiosResponse<BaseResponseBody<PostAddType[]>>;
if (response.data.error.code === config.API_RES_CODE.OK.code) {
addPostDialogIsOpened.value = false;
Notify.create({
......@@ -391,46 +394,59 @@ export default defineComponent({
//gọi api detail
const getDetailPost = async (id: number) => {
// try {
// const response = (await api({
// url: API_PATHS.getDetailPost,
// method: 'GET',
// params: {
// id: id,
// },
// })) as AxiosResponse<BaseResponseBody<DetailPost>>;
// if (response.data.error.code === config.API_RES_CODE.OK.code) {
// postId.value = response.data.data.id;
// name.value = response.data.data.name;
// description.value = response.data.data.description;
// status.value = response.data.data.status;
// }
// } catch (error) {}
try {
const response = (await api({
url: API_PATHS.getDetailPost,
method: 'GET',
params: {
id: id,
},
})) as AxiosResponse<BaseResponseBody<PostDetailType>>;
if (response.data.error.code === config.API_RES_CODE.OK.code) {
postId.value = response.data.data.id;
image.value = config.API_IMAGE_ENDPOINT + response.data.data.image;
imageChange.value = response.data.data.image;
languageOptions.value = response.data.data.langs;
status.value = response.data.data.status;
category.value = response.data.data.category;
}
} catch (error) {}
};
//gọi api update
const updateNewPost = async () => {
// const data = {
// id: postId.value,
// name: name.value,
// description: description.value,
// status: status.value,
// };
// const response = (await api({
// // url: API_PATHS.updatePost,
// method: 'POST',
// data,
// })) as AxiosResponse<BaseResponseBody<[]>>;
// if (response.data.error.code === config.API_RES_CODE.OK.code) {
// updatePostDialogIsOpened.value = false;
// Notify.create({
// type: 'positive',
// message: i18n.global.t('post.actionMessages.updatePostAccess'),
// actions: [{ icon: 'close', color: 'white' }],
// });
// void getListPost();
// }
const confirmUpdatePost = async () => {
if (avatarFile.value) {
avatarUploaded.value = await callApiUploadAvatar(avatarFile.value);
void updatePost(avatarUploaded.value);
} else {
void updatePost(imageChange.value);
}
};
const updatePost = async (image: string) => {
const data = {
id: postId.value,
image,
status: status.value,
category: { id: category.value?.id },
langs: languageOptions.value,
};
const response = (await api({
url: API_PATHS.updatePost,
method: 'POST',
data,
})) as AxiosResponse<BaseResponseBody<PostDetailType[]>>;
if (response.data.error.code === config.API_RES_CODE.OK.code) {
updatePostDialogIsOpened.value = false;
Notify.create({
type: 'positive',
message: i18n.global.t('post.actionMessages.updatePostAccess'),
actions: [{ icon: 'close', color: 'white' }],
});
void getListPost();
}
};
const setAvatar = (value: { file?: File; url?: string }) => {
avatarFile.value = value.file as File;
image.value = value.url as string;
......@@ -442,19 +458,25 @@ export default defineComponent({
bodyFormData.append('file', file);
const response = (await api({
headers: { 'Content-Type': 'multipart/form-data' },
url: 'http://cms.vab.xteldev.com/file/upload',
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) {
avatarUploaded.value = response.data.data.fileName;
return response.data.data.fileName;
} else {
return '';
}
} catch (error) {}
} catch (error) {
return '';
}
};
const deleteAvatar = () => {
image.value = null;
};
const configImg = config;
//gọi api danh mục bv
const getpostCategory = async () => {
const response = (await api({
......@@ -467,6 +489,45 @@ export default defineComponent({
}
};
type FromType = {
name: string;
title: string;
content: string;
status: number;
language: {
id: number;
code: string;
name: string;
};
}[];
const getLanguage = async () => {
const response = (await api({
url: API_PATHS.getLanguage,
method: 'GET',
params: {},
})) as AxiosResponse<BaseResponseBody<LanguageType[]>>;
if (response.data.error.code === config.API_RES_CODE.OK.code) {
languageOptions.value = response.data.data.reduce(
(acc: FromType, info) => {
acc.push({
name: '',
title: '',
content: '',
status: 1,
language: {
id: info.id,
code: info.code,
name: info.name,
},
});
return acc;
},
[]
);
}
};
onMounted(() => {
void getListPost();
void getpostCategory();
......@@ -492,7 +553,7 @@ export default defineComponent({
deletePost,
openUpdatePostDialog,
getDetailPost,
updateNewPost,
updatePost,
namePost,
content,
languageOptions,
......@@ -502,6 +563,9 @@ export default defineComponent({
callApiUploadAvatar,
deleteAvatar,
getpostCategory,
getLanguage,
configImg,
confirmUpdatePost,
};
},
});
......
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