Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Q
quasar-web-base
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Nguyễn Hải Sơn
quasar-web-base
Commits
34d02d6c
Commit
34d02d6c
authored
May 13, 2021
by
Tình Trương
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update
parent
796d2d59
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
353 additions
and
168 deletions
+353
-168
configurations.example.ts
src/assets/configurations.example.ts
+3
-0
type.ts
src/assets/type.ts
+13
-0
index.vue
src/components/add-update-post/index.vue
+217
-112
index.vue
src/pages/bai-viet/index.vue
+120
-56
No files found.
src/assets/configurations.example.ts
View file @
34d02d6c
...
...
@@ -73,4 +73,7 @@ export enum API_PATHS {
getPostCategory
=
'postCategory'
,
addPost
=
'post/add'
,
getListCategoryPost
=
'postCategory'
,
getLanguage
=
'language'
,
getDetailPost
=
'post/detail'
,
updatePost
=
'post/update'
,
}
src/assets/type.ts
View file @
34d02d6c
...
...
@@ -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
;
};
src/components/add-update-post/index.vue
View file @
34d02d6c
...
...
@@ -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
(
'v
n
'
);
tab
.
value
=
'vn'
;
const
tab
=
ref
(
'v
i
'
);
const
tabContent
=
ref
(
'vi'
)
;
return
{
contentRules
,
nameRules
,
imageRules
,
selectedFile
,
...
...
@@ -262,6 +366,7 @@ export default defineComponent({
uploadAvatar
,
deleteAvatar
,
tab
,
tabContent
,
};
},
emits
:
[
...
...
src/pages/bai-viet/index.vue
View file @
34d02d6c
...
...
@@ -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=
"
updateNew
Post"
@
savePostInfo=
"
confirmUpdate
Post"
/>
</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
<
Post
Detail
Type
[]
>>
;
}))
as
AxiosResponse
<
BaseResponseBody
<
Post
Add
Type
[]
>>
;
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
,
update
New
Post
,
updatePost
,
namePost
,
content
,
languageOptions
,
...
...
@@ -502,6 +563,9 @@ export default defineComponent({
callApiUploadAvatar
,
deleteAvatar
,
getpostCategory
,
getLanguage
,
configImg
,
confirmUpdatePost
,
};
},
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment