refactor: photo manage. (halo-dev/console#258)

pull/3445/head
Ryan Wang 2020-09-26 22:30:20 +08:00 committed by GitHub
parent 5557429910
commit 67a3cf0654
3 changed files with 292 additions and 265 deletions

View File

@ -66,7 +66,7 @@
prop="team" prop="team"
> >
<a-auto-complete <a-auto-complete
:dataSource="teams.data" :dataSource="computedTeams"
v-model="form.model.team" v-model="form.model.team"
allowClear allowClear
/> />
@ -307,6 +307,11 @@ export default {
isUpdateMode() { isUpdateMode() {
return !!this.form.model.id return !!this.form.model.id
}, },
computedTeams() {
return this.teams.data.filter((item) => {
return item !== ''
})
},
}, },
created() { created() {
this.handleListMenus() this.handleListMenus()

View File

@ -51,7 +51,7 @@
prop="team" prop="team"
> >
<a-auto-complete <a-auto-complete
:dataSource="teams" :dataSource="computedTeams"
v-model="form.model.team" v-model="form.model.team"
allowClear allowClear
/> />
@ -273,28 +273,28 @@ const columns = [
title: '名称', title: '名称',
dataIndex: 'name', dataIndex: 'name',
ellipsis: true, ellipsis: true,
scopedSlots: { customRender: 'name' } scopedSlots: { customRender: 'name' },
}, },
{ {
title: '网址', title: '网址',
dataIndex: 'url', dataIndex: 'url',
ellipsis: true, ellipsis: true,
scopedSlots: { customRender: 'url' } scopedSlots: { customRender: 'url' },
}, },
{ {
title: '分组', title: '分组',
ellipsis: true, ellipsis: true,
dataIndex: 'team' dataIndex: 'team',
}, },
{ {
title: '排序', title: '排序',
dataIndex: 'priority' dataIndex: 'priority',
}, },
{ {
title: '操作', title: '操作',
key: 'action', key: 'action',
scopedSlots: { customRender: 'action' } scopedSlots: { customRender: 'action' },
} },
] ]
export default { export default {
mixins: [mixin, mixinDevice], mixins: [mixin, mixinDevice],
@ -303,7 +303,7 @@ export default {
table: { table: {
columns, columns,
data: [], data: [],
loading: false loading: false,
}, },
form: { form: {
model: {}, model: {},
@ -312,23 +312,23 @@ export default {
rules: { rules: {
name: [ name: [
{ required: true, message: '* 友情链接名称不能为空', trigger: ['change'] }, { required: true, message: '* 友情链接名称不能为空', trigger: ['change'] },
{ max: 255, message: '* 友情链接名称的字符长度不能超过 255', trigger: ['change'] } { max: 255, message: '* 友情链接名称的字符长度不能超过 255', trigger: ['change'] },
], ],
url: [ url: [
{ required: true, message: '* 友情链接地址不能为空', trigger: ['change'] }, { required: true, message: '* 友情链接地址不能为空', trigger: ['change'] },
{ max: 1023, message: '* 友情链接地址的字符长度不能超过 1023', trigger: ['change'] }, { max: 1023, message: '* 友情链接地址的字符长度不能超过 1023', trigger: ['change'] },
{ type: 'url', message: '* 友情链接地址格式有误', trigger: ['change'] } { type: 'url', message: '* 友情链接地址格式有误', trigger: ['change'] },
], ],
logo: [{ max: 1023, message: '* 友情链接 Logo 的字符长度不能超过 1023', trigger: ['change'] }], logo: [{ max: 1023, message: '* 友情链接 Logo 的字符长度不能超过 1023', trigger: ['change'] }],
description: [{ max: 255, message: '* 友情链接描述的字符长度不能超过 255', trigger: ['change'] }], description: [{ max: 255, message: '* 友情链接描述的字符长度不能超过 255', trigger: ['change'] }],
team: [{ max: 255, message: '* 友情链接分组的字符长度 255', trigger: ['change'] }] team: [{ max: 255, message: '* 友情链接分组的字符长度 255', trigger: ['change'] }],
} },
}, },
optionsModal: { optionsModal: {
visible: false, visible: false,
data: [] data: [],
}, },
teams: [] teams: [],
} }
}, },
computed: { computed: {
@ -340,7 +340,12 @@ export default {
}, },
isUpdateMode() { isUpdateMode() {
return !!this.form.model.id return !!this.form.model.id
} },
computedTeams() {
return this.teams.filter((item) => {
return item !== ''
})
},
}, },
created() { created() {
this.handleListLinks() this.handleListLinks()
@ -353,7 +358,7 @@ export default {
this.table.loading = true this.table.loading = true
linkApi linkApi
.listAll() .listAll()
.then(response => { .then((response) => {
this.table.data = response.data.data this.table.data = response.data.data
}) })
.finally(() => { .finally(() => {
@ -363,19 +368,19 @@ export default {
}) })
}, },
handleListLinkTeams() { handleListLinkTeams() {
linkApi.listTeams().then(response => { linkApi.listTeams().then((response) => {
this.teams = response.data.data this.teams = response.data.data
}) })
}, },
handleListOptions() { handleListOptions() {
optionApi.listAll().then(response => { optionApi.listAll().then((response) => {
this.optionsModal.data = response.data.data this.optionsModal.data = response.data.data
}) })
}, },
handleDeleteLink(id) { handleDeleteLink(id) {
linkApi linkApi
.delete(id) .delete(id)
.then(response => { .then((response) => {
this.$message.success('删除成功!') this.$message.success('删除成功!')
}) })
.finally(() => { .finally(() => {
@ -384,13 +389,13 @@ export default {
}) })
}, },
handleParseUrl() { handleParseUrl() {
linkApi.getByParse(this.form.model.url).then(response => { linkApi.getByParse(this.form.model.url).then((response) => {
this.form.model = response.data.data this.form.model = response.data.data
}) })
}, },
handleCreateOrUpdateLink() { handleCreateOrUpdateLink() {
const _this = this const _this = this
_this.$refs.linkForm.validate(valid => { _this.$refs.linkForm.validate((valid) => {
if (valid) { if (valid) {
_this.form.saving = true _this.form.saving = true
if (_this.isUpdateMode) { if (_this.isUpdateMode) {
@ -432,7 +437,7 @@ export default {
handleSaveOptions() { handleSaveOptions() {
optionApi optionApi
.save(this.optionsModal.data) .save(this.optionsModal.data)
.then(response => { .then((response) => {
this.$message.success('保存成功!') this.$message.success('保存成功!')
this.optionsModal.visible = false this.optionsModal.visible = false
}) })
@ -440,7 +445,7 @@ export default {
this.handleListOptions() this.handleListOptions()
this.refreshOptionsCache() this.refreshOptionsCache()
}) })
} },
} },
} }
</script> </script>

View File

@ -21,7 +21,7 @@
:sm="24" :sm="24"
> >
<a-form-item label="关键词:"> <a-form-item label="关键词:">
<a-input v-model="queryParam.keyword" /> <a-input v-model="list.queryParam.keyword" />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col <a-col
@ -30,11 +30,11 @@
> >
<a-form-item label="分组:"> <a-form-item label="分组:">
<a-select <a-select
v-model="queryParam.team" v-model="list.queryParam.team"
@change="handleQuery()" @change="handleQuery()"
> >
<a-select-option <a-select-option
v-for="(item,index) in teams" v-for="(item,index) in computedTeams"
:key="index" :key="index"
:value="item" :value="item"
>{{ item }}</a-select-option> >{{ item }}</a-select-option>
@ -51,7 +51,7 @@
type="primary" type="primary"
@click="handleQuery()" @click="handleQuery()"
>查询</a-button> >查询</a-button>
<a-button @click="resetParam()"></a-button> <a-button @click="handleResetParam()"></a-button>
</a-space> </a-space>
</span> </span>
</a-col> </a-col>
@ -62,7 +62,7 @@
<a-button <a-button
type="primary" type="primary"
icon="plus" icon="plus"
@click="handleAddClick" @click="form.visible = true"
>添加</a-button> >添加</a-button>
</div> </div>
</a-card> </a-card>
@ -70,8 +70,8 @@
<a-col :span="24"> <a-col :span="24">
<a-list <a-list
:grid="{ gutter: 12, xs: 2, sm: 2, md: 4, lg: 6, xl: 6, xxl: 6 }" :grid="{ gutter: 12, xs: 2, sm: 2, md: 4, lg: 6, xl: 6, xxl: 6 }"
:dataSource="photos" :dataSource="list.data"
:loading="listLoading" :loading="list.loading"
> >
<a-list-item <a-list-item
slot="renderItem" slot="renderItem"
@ -81,7 +81,7 @@
<a-card <a-card
:bodyStyle="{ padding: 0 }" :bodyStyle="{ padding: 0 }"
hoverable hoverable
@click="showDrawer(item)" @click="handleOpenEditForm(item)"
> >
<div class="photo-thumb"> <div class="photo-thumb">
<img <img
@ -103,9 +103,9 @@
</a-row> </a-row>
<div class="page-wrapper"> <div class="page-wrapper">
<a-pagination <a-pagination
:current="pagination.page" :current="list.pagination.page"
:total="pagination.total" :total="list.pagination.total"
:defaultPageSize="pagination.size" :defaultPageSize="list.pagination.size"
:pageSizeOptions="['18', '36', '54','72','90','108']" :pageSizeOptions="['18', '36', '54','72','90','108']"
showSizeChanger showSizeChanger
@change="handlePaginationChange" @change="handlePaginationChange"
@ -150,167 +150,127 @@
</a-form> </a-form>
</a-modal> </a-modal>
<a-drawer <a-drawer
title="图片详情" :title="`图片${form.model.id?'修改':'添加'}`"
:width="isMobile()?'100%':'480'" :width="isMobile()?'100%':'480'"
closable closable
:visible="drawerVisible" :visible="form.visible"
destroyOnClose destroyOnClose
@close="onDrawerClose" @close="onDrawerClose"
> >
<a-row <a-form-model
type="flex" ref="photoForm"
align="middle" :model="form.model"
:rules="form.rules"
layout="vertical"
> >
<a-col :span="24"> <a-form-model-item
<div class="photo-detail-img"> prop="url"
label="图片地址:"
>
<div class="pb-2">
<img <img
:src="photo.url || '/images/placeholder.jpg'" :src="form.model.url || '/images/placeholder.jpg'"
@click="showThumbDrawer" @click="attachmentSelectDrawer.visible = true"
class="w-full" class="w-full cursor-pointer"
style="border-radius:4px"
> >
</div> </div>
</a-col> <a-input
<a-divider style="margin: 24px 0 12px 0;" /> v-model="form.model.url"
placeholder="点击封面图选择图片,或者输入外部链接"
<a-col :span="24"> />
<a-list itemLayout="horizontal"> </a-form-model-item>
<a-list-item> <a-form-model-item
<a-list-item-meta> prop="thumbnail"
<template label="缩略图地址:"
slot="description" >
v-if="editable" <a-input v-model="form.model.thumbnail" />
> </a-form-model-item>
<a-input v-model="photo.thumbnail" /> <a-form-model-item
</template> prop="name"
<template label="图片名称:"
slot="description" >
v-else <a-input v-model="form.model.name" />
>{{ photo.thumbnail }}</template> </a-form-model-item>
<span slot="title"> <a-form-model-item
缩略图地址 prop="takeTime"
</span> label="拍摄日期:"
</a-list-item-meta> >
</a-list-item> <a-date-picker
<a-list-item> showTime
<a-list-item-meta> :defaultValue="takeTimeDefaultValue"
<template format="YYYY-MM-DD HH:mm:ss"
slot="description" style="width:100%"
v-if="editable" @change="onTakeTimeChange"
> @ok="onTakeTimeSelect"
<a-input v-model="photo.name" /> />
</template> </a-form-model-item>
<template <a-form-model-item
slot="description" prop="location"
v-else label="拍摄地点:"
>{{ photo.name }}</template> >
<span slot="title"> <a-input v-model="form.model.location" />
图片名称 </a-form-model-item>
</span> <a-form-model-item
</a-list-item-meta> prop="team"
</a-list-item> label="分组:"
<a-list-item> >
<a-list-item-meta> <a-auto-complete
<template :dataSource="computedTeams"
slot="description" v-model="form.model.team"
v-if="editable" allowClear
> style="width:100%"
<a-date-picker />
v-model="photo.takeTime" </a-form-model-item>
style="width:100%" <a-form-model-item
/> prop="description"
</template> label="描述:"
<span >
slot="description" <a-input
v-else v-model="form.model.description"
>{{ photo.takeTime | moment }}</span> type="textarea"
<span slot="title">拍摄日期</span> :autoSize="{ minRows: 5 }"
</a-list-item-meta> />
</a-list-item> </a-form-model-item>
<a-list-item> </a-form-model>
<a-list-item-meta>
<template
slot="description"
v-if="editable"
>
<a-input v-model="photo.location" />
</template>
<span
slot="description"
v-else
>{{ photo.location || '无' }}</span>
<span slot="title">拍摄地点</span>
</a-list-item-meta>
</a-list-item>
<a-list-item>
<a-list-item-meta>
<template
slot="description"
v-if="editable"
>
<a-auto-complete
:dataSource="teams"
v-model="photo.team"
allowClear
style="width:100%"
/>
</template>
<span
slot="description"
v-else
>{{ photo.team || '无' }}</span>
<span slot="title">分组</span>
</a-list-item-meta>
</a-list-item>
<a-list-item>
<a-list-item-meta>
<template
slot="description"
v-if="editable"
>
<a-input
v-model="photo.description"
type="textarea"
:autoSize="{ minRows: 5 }"
/>
</template>
<span
slot="description"
v-else
>{{ photo.description || '无' }}</span>
<span slot="title">描述</span>
</a-list-item-meta>
</a-list-item>
</a-list>
</a-col>
</a-row>
<AttachmentSelectDrawer
v-model="thumDrawerVisible"
@listenToSelect="selectPhotoThumb"
:drawerWidth="480"
/>
<a-divider class="divider-transparent" /> <a-divider class="divider-transparent" />
<div class="bottom-control"> <div class="bottom-control">
<a-space> <a-space>
<a-button <ReactiveButton
type="dashed"
@click="editable = true"
v-if="!editable"
>编辑</a-button>
<a-button
type="primary"
@click="handleCreateOrUpdate" @click="handleCreateOrUpdate"
v-else @callback="handleCreateOrUpdateCallback"
>保存</a-button> :loading="form.saving"
:errored="form.saveErrored"
:text="`${form.model.id?'修改':'添加'}`"
:loadedText="`${form.model.id?'修改':'添加'}成功`"
:erroredText="`${form.model.id?'修改':'添加'}失败`"
></ReactiveButton>
<a-popconfirm <a-popconfirm
title="你确定要删除该图片?" title="你确定要删除该图片?"
okText="确定" okText="确定"
cancelText="取消" cancelText="取消"
@confirm="handleDeletePhoto" @confirm="handleDelete"
v-if="form.model.id"
> >
<a-button type="danger">删除</a-button> <ReactiveButton
type="danger"
@click="() => {}"
@callback="handleDeleteCallback"
:loading="form.deleting"
:errored="form.deleteErrored"
text="删除"
loadedText="删除成功"
erroredText="删除失败"
></ReactiveButton>
</a-popconfirm> </a-popconfirm>
</a-space> </a-space>
</div> </div>
<AttachmentSelectDrawer
v-model="attachmentSelectDrawer.visible"
@listenToSelect="handleAttachmentSelected"
:drawerWidth="480"
/>
</a-drawer> </a-drawer>
</div> </div>
</template> </template>
@ -320,33 +280,51 @@ import { mapActions } from 'vuex'
import { mixin, mixinDevice } from '@/utils/mixin.js' import { mixin, mixinDevice } from '@/utils/mixin.js'
import photoApi from '@/api/photo' import photoApi from '@/api/photo'
import optionApi from '@/api/option' import optionApi from '@/api/option'
import { datetimeFormat } from '@/utils/datetime'
export default { export default {
mixins: [mixin, mixinDevice], mixins: [mixin, mixinDevice],
data() { data() {
return { return {
drawerVisible: false, list: {
listLoading: true, data: [],
thumDrawerVisible: false, loading: false,
pagination: {
page: 1,
size: 18,
sort: null,
total: 1,
},
queryParam: {
page: 0,
size: 18,
sort: null,
keyword: null,
team: null,
},
},
form: {
model: {},
visible: false,
rules: {
url: [{ required: true, message: '* 图片地址不能为空', trigger: ['change'] }],
thumbnail: [{ required: true, message: '* 缩略图地址不能为空', trigger: ['change'] }],
name: [{ required: true, message: '* 图片名称不能为空', trigger: ['change'] }],
},
saving: false,
saveErrored: false,
deleting: false,
deleteErrored: false,
},
attachmentSelectDrawer: {
visible: false,
},
optionFormVisible: false, optionFormVisible: false,
photo: {},
photos: [],
teams: [], teams: [],
editable: false, options: [],
pagination: {
page: 1,
size: 18,
sort: null,
total: 1
},
queryParam: {
page: 0,
size: 18,
sort: null,
keyword: null,
team: null
},
options: []
} }
}, },
created() { created() {
@ -354,112 +332,145 @@ export default {
this.hanldeListPhotoTeams() this.hanldeListPhotoTeams()
this.hanldeListOptions() this.hanldeListOptions()
}, },
computed: {
takeTimeDefaultValue() {
if (this.form.model.takeTime) {
var date = new Date(this.form.model.takeTime)
return datetimeFormat(date, 'YYYY-MM-DD HH:mm:ss')
}
return datetimeFormat(new Date(), 'YYYY-MM-DD HH:mm:ss')
},
computedTeams() {
return this.teams.filter((item) => {
return item !== ''
})
},
},
methods: { methods: {
...mapActions(['refreshOptionsCache']), ...mapActions(['refreshOptionsCache']),
hanldeListPhotos() { hanldeListPhotos() {
this.listLoading = true this.list.loading = true
this.queryParam.page = this.pagination.page - 1 this.list.queryParam.page = this.list.pagination.page - 1
this.queryParam.size = this.pagination.size this.list.queryParam.size = this.list.pagination.size
this.queryParam.sort = this.pagination.sort this.list.queryParam.sort = this.list.pagination.sort
photoApi photoApi
.query(this.queryParam) .query(this.list.queryParam)
.then(response => { .then((response) => {
this.photos = response.data.data.content this.list.data = response.data.data.content
this.pagination.total = response.data.data.total this.list.pagination.total = response.data.data.total
}) })
.finally(() => { .finally(() => {
setTimeout(() => { setTimeout(() => {
this.listLoading = false this.list.loading = false
}, 200) }, 200)
}) })
}, },
handleQuery() {
this.handlePaginationChange(1, this.list.pagination.size)
},
hanldeListOptions() { hanldeListOptions() {
optionApi.listAll().then(response => { optionApi.listAll().then((response) => {
this.options = response.data.data this.options = response.data.data
}) })
}, },
handleQuery() {
this.handlePaginationChange(1, this.pagination.size)
},
hanldeListPhotoTeams() { hanldeListPhotoTeams() {
photoApi.listTeams().then(response => { photoApi.listTeams().then((response) => {
this.teams = response.data.data this.teams = response.data.data
}) })
}, },
handleCreateOrUpdate() { handleCreateOrUpdate() {
if (this.photo.id) { const _this = this
photoApi _this.$refs.photoForm.validate((valid) => {
.update(this.photo.id, this.photo) if (valid) {
.then(response => { _this.form.saving = true
this.$message.success('照片更新成功!') if (_this.form.model.id) {
}) photoApi
.finally(() => { .update(_this.form.model.id, _this.form.model)
this.hanldeListPhotos() .catch(() => {
this.hanldeListPhotoTeams() _this.form.saveErrored = true
}) })
} else { .finally(() => {
photoApi setTimeout(() => {
.create(this.photo) _this.form.saving = false
.then(response => { }, 400)
this.photo = response.data.data })
this.$message.success('照片添加成功!') } else {
}) photoApi
.finally(() => { .create(_this.form.model)
this.hanldeListPhotos() .catch(() => {
this.hanldeListPhotoTeams() _this.form.saveErrored = true
}) })
} .finally(() => {
this.editable = false setTimeout(() => {
_this.form.saving = false
}, 400)
})
}
}
})
}, },
showDrawer(photo) { handleCreateOrUpdateCallback() {
this.photo = photo if (this.form.saveErrored) {
this.drawerVisible = true this.form.saveErrored = false
} else {
this.form.model = {}
this.form.visible = false
this.hanldeListPhotos()
this.hanldeListPhotoTeams()
}
},
handleOpenEditForm(photo) {
this.form.model = photo
this.form.visible = true
}, },
handlePaginationChange(page, size) { handlePaginationChange(page, size) {
this.$log.debug(`Current: ${page}, PageSize: ${size}`) this.$log.debug(`Current: ${page}, PageSize: ${size}`)
this.pagination.page = page this.list.pagination.page = page
this.pagination.size = size this.list.pagination.size = size
this.hanldeListPhotos() this.hanldeListPhotos()
}, },
handleAddClick() { handleDelete() {
this.editable = true this.form.deleting = true
this.drawerVisible = true
},
handleDeletePhoto() {
photoApi photoApi
.delete(this.photo.id) .delete(this.form.model.id)
.then(response => { .catch(() => {
this.$message.success('删除成功!') this.form.deleteErrored = true
this.onDrawerClose()
}) })
.finally(() => { .finally(() => {
this.hanldeListPhotos() setTimeout(() => {
this.hanldeListPhotoTeams() this.form.deleting = false
}, 400)
}) })
}, },
showThumbDrawer() { handleDeleteCallback() {
this.thumDrawerVisible = true if (this.form.deleteErrored) {
this.form.deleteErrored = false
} else {
this.form.model = {}
this.form.visible = false
this.hanldeListPhotos()
this.hanldeListPhotoTeams()
}
}, },
selectPhotoThumb(data) { handleAttachmentSelected(data) {
this.photo.url = encodeURI(data.path) this.form.model.url = encodeURI(data.path)
this.photo.thumbnail = encodeURI(data.thumbPath) this.form.model.thumbnail = encodeURI(data.thumbPath)
this.thumDrawerVisible = false this.attachmentSelectDrawer.visible = false
}, },
resetParam() { handleResetParam() {
this.queryParam.keyword = null this.list.queryParam.keyword = null
this.queryParam.team = null this.list.queryParam.team = null
this.handlePaginationChange(1, this.pagination.size) this.handlePaginationChange(1, this.list.pagination.size)
this.hanldeListPhotoTeams() this.hanldeListPhotoTeams()
}, },
onDrawerClose() { onDrawerClose() {
this.drawerVisible = false this.form.visible = false
this.photo = {} this.form.model = {}
this.editable = false
}, },
handleSaveOptions() { handleSaveOptions() {
optionApi optionApi
.save(this.options) .save(this.options)
.then(response => { .then((response) => {
this.$message.success('保存成功!') this.$message.success('保存成功!')
this.optionFormVisible = false this.optionFormVisible = false
}) })
@ -467,7 +478,13 @@ export default {
this.hanldeListOptions() this.hanldeListOptions()
this.refreshOptionsCache() this.refreshOptionsCache()
}) })
} },
} onTakeTimeChange(value, dateString) {
this.form.model.takeTime = value.valueOf()
},
onTakeTimeSelect(value) {
this.form.model.takeTime = value.valueOf()
},
},
} }
</script> </script>