release 1.0.3 (#34)

release 1.0.3

Co-authored-by: guqing <1484563614@qq.com>
Co-authored-by: John Niang <johnniang@riseup.net>
pull/37/head v1.0.3
Ryan Wang 2019-07-09 21:31:03 +08:00 committed by GitHub
commit 5adb443353
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 359 additions and 45 deletions

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "halo-admin", "name": "halo-admin",
"version": "1.0.2", "version": "1.0.3",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@ -1,6 +1,6 @@
{ {
"name": "halo-admin", "name": "halo-admin",
"version": "1.0.2", "version": "1.0.3",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",

View File

@ -697,4 +697,15 @@ body {
p{ p{
margin-bottom: 0; margin-bottom: 0;
} }
}
.post-thum {
.img {
width: 100%;
cursor: pointer;
border-radius: 4px;
}
.post-thum-remove {
margin-top: 16px;
}
} }

View File

@ -260,7 +260,7 @@ export default {
this.editable = false this.editable = false
}, },
handleCopyNormalLink() { handleCopyNormalLink() {
const text = `${this.attachment.path}` const text = `${encodeURI(this.attachment.path)}`
this.$copyText(text) this.$copyText(text)
.then(message => { .then(message => {
console.log('copy', message) console.log('copy', message)
@ -272,7 +272,7 @@ export default {
}) })
}, },
handleCopyMarkdownLink() { handleCopyMarkdownLink() {
const text = `![${this.attachment.name}](${this.attachment.path})` const text = `![${this.attachment.name}](${encodeURI(this.attachment.path)})`
this.$copyText(text) this.$copyText(text)
.then(message => { .then(message => {
console.log('copy', message) console.log('copy', message)

View File

@ -47,8 +47,14 @@
@change="handlePaginationChange" @change="handlePaginationChange"
></a-pagination> ></a-pagination>
</div> </div>
<a-divider class="divider-transparent"/> <a-divider class="divider-transparent" />
<div class="bottom-control"> <div class="bottom-control">
<a-button
type="dashed"
style="marginRight: 8px"
v-if="isChooseAvatar"
@click="handleSelectGravatar"
>使用 Gravatar</a-button>
<a-button <a-button
@click="handleShowUploadModal" @click="handleShowUploadModal"
type="primary" type="primary"
@ -103,6 +109,11 @@ export default {
type: String, type: String,
required: false, required: false,
default: '选择附件' default: '选择附件'
},
isChooseAvatar: {
type: Boolean,
required: false,
default: false
} }
}, },
data() { data() {
@ -150,6 +161,9 @@ export default {
handleSelectAttachment(item) { handleSelectAttachment(item) {
this.$emit('listenToSelect', item) this.$emit('listenToSelect', item)
}, },
handleSelectGravatar() {
this.$emit('listenToSelectGravatar')
},
handlePaginationChange(page, pageSize) { handlePaginationChange(page, pageSize) {
this.pagination.page = page this.pagination.page = page
this.pagination.size = pageSize this.pagination.size = pageSize

View File

@ -127,7 +127,7 @@
target="_blank" target="_blank"
>{{ post.title }}</a> >{{ post.title }}</a>
<a <a
v-else v-if="type === 'sheets'"
slot="sheet" slot="sheet"
slot-scope="sheet" slot-scope="sheet"
:href="options.blog_url+'/s/'+sheet.url" :href="options.blog_url+'/s/'+sheet.url"
@ -408,7 +408,11 @@ export default {
this.selectComment = comment this.selectComment = comment
this.replyCommentVisible = true this.replyCommentVisible = true
this.replyComment.parentId = comment.id this.replyComment.parentId = comment.id
this.replyComment.postId = comment.post.id if (this.type === 'posts') {
this.replyComment.postId = comment.post.id
} else {
this.replyComment.postId = comment.sheet.id
}
}, },
handleCreateClick() { handleCreateClick() {
commentApi.create(this.type, this.replyComment).then(response => { commentApi.create(this.type, this.replyComment).then(response => {

View File

@ -202,24 +202,24 @@
</a-form-item> </a-form-item>
<!-- 日志图片上传 --> <!-- 日志图片上传 -->
<a-form-item v-show="showMoreOptions"> <!-- <a-form-item v-show="showMoreOptions">
<UploadPhoto <UploadPhoto
@success="handlerPhotoUploadSuccess" @success="handlerPhotoUploadSuccess"
:photoList="photoList" :photoList="photoList"
></UploadPhoto> ></UploadPhoto>
</a-form-item> </a-form-item> -->
<a-form-item> <a-form-item>
<a-button <a-button
type="primary" type="primary"
@click="handleCreateJournalClick" @click="handleCreateJournalClick"
>保存</a-button> >保存</a-button>
<a <!-- <a
href="javascript:;" href="javascript:;"
class="more-options-btn" class="more-options-btn"
type="default" type="default"
@click="handleUploadPhotoWallClick" @click="handleUploadPhotoWallClick"
>更多选项<a-icon type="down" /></a> >更多选项<a-icon type="down" /></a> -->
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-card> </a-card>
@ -508,4 +508,7 @@ export default {
margin-left: 15px; margin-left: 15px;
text-decoration: none; text-decoration: none;
} }
a {
text-decoration: none;
}
</style> </style>

View File

@ -427,9 +427,7 @@ export default {
this.themeConfiguration = response.data.data this.themeConfiguration = response.data.data
themeApi.fetchSettings(theme.id).then(response => { themeApi.fetchSettings(theme.id).then(response => {
this.themeSettings = response.data.data this.themeSettings = response.data.data
setTimeout(() => { setTimeout(() => {
this.visible = true
this.optionLoading = false this.optionLoading = false
}, 300) }, 300)
}) })

View File

@ -199,7 +199,6 @@ import FooterToolBar from '@/components/FooterToolbar'
import { mixin, mixinDevice } from '@/utils/mixin.js' import { mixin, mixinDevice } from '@/utils/mixin.js'
import { toolbars } from '@/core/const' import { toolbars } from '@/core/const'
import 'mavon-editor/dist/css/index.css' import 'mavon-editor/dist/css/index.css'
import tagApi from '@/api/tag'
import categoryApi from '@/api/category' import categoryApi from '@/api/category'
import postApi from '@/api/post' import postApi from '@/api/post'
import optionApi from '@/api/option' import optionApi from '@/api/option'
@ -226,7 +225,6 @@ export default {
postSettingVisible: false, postSettingVisible: false,
thumDrawerVisible: false, thumDrawerVisible: false,
categoryForm: false, categoryForm: false,
tags: [],
categories: [], categories: [],
selectedCategoryIds: [], selectedCategoryIds: [],
selectedTagIds: [], selectedTagIds: [],
@ -238,7 +236,6 @@ export default {
} }
}, },
created() { created() {
this.loadTags()
this.loadCategories() this.loadCategories()
this.loadOptions() this.loadOptions()
clearInterval(this.timer) clearInterval(this.timer)
@ -273,11 +270,6 @@ export default {
}) })
}, },
methods: { methods: {
loadTags() {
tagApi.listAll(true).then(response => {
this.tags = response.data.data
})
},
loadCategories() { loadCategories() {
categoryApi.listAll().then(response => { categoryApi.listAll().then(response => {
this.categories = response.data.data this.categories = response.data.data
@ -365,15 +357,4 @@ export default {
z-index: 1000; z-index: 1000;
min-height: 580px; min-height: 580px;
} }
.post-thum {
.img {
width: 100%;
cursor: pointer;
border-radius: 4px;
}
.post-thum-remove {
margin-top: 16px;
}
}
</style> </style>

View File

@ -128,12 +128,27 @@
:loading="postsLoading" :loading="postsLoading"
:pagination="false" :pagination="false"
> >
<ellipsis <!-- ellipsis内嵌a标签后文本会被置空
<ellipsis
:length="25" :length="25"
tooltip tooltip
slot="postTitle" slot="postTitle"
slot-scope="postTitle" slot-scope="text,record"
>{{ postTitle }}</ellipsis> >
{{ text }}
</ellipsis> -->
<span
slot="postTitle"
slot-scope="text,record"
class="post-title"
>
<a
:href="options.blog_url+'/archives/'+record.url"
target="_blank"
>
<a-tooltip placement="topLeft" :title="'点击预览 '+text">{{ text }}</a-tooltip>
</a>
</span>
<span <span
slot="status" slot="status"
slot-scope="statusProperty" slot-scope="statusProperty"
@ -209,6 +224,13 @@
> >
<a href="javascript:;">删除</a> <a href="javascript:;">删除</a>
</a-popconfirm> </a-popconfirm>
<a-divider type="vertical" />
<a
href="javascript:;"
@click="handlePostSettingsDrawer(post)"
>设置</a>
</span> </span>
</a-table> </a-table>
<div class="page-wrapper"> <div class="page-wrapper">
@ -223,16 +245,170 @@
</div> </div>
</div> </div>
</a-card> </a-card>
<a-drawer
title="文章设置"
:width="isMobile()?'100%':'460'"
placement="right"
closable
@close="onPostSettingsClose"
:visible="postSettingVisible"
>
<div class="post-setting-drawer-content">
<div :style="{ marginBottom: '16px' }">
<h3 class="post-setting-drawer-title">基本设置</h3>
<div class="post-setting-drawer-item">
<a-form layout="vertical">
<a-form-item label="文章标题:">
<a-input v-model="selectedPost.title" />
</a-form-item>
<a-form-item
label="文章路径:"
:help="options.blog_url+'/archives/' + (selectedPost.url ? selectedPost.url : '{auto_generate}')"
>
<a-input v-model="selectedPost.url" />
</a-form-item>
<a-form-item label="开启评论:">
<a-radio-group
v-model="selectedPost.disallowComment"
:defaultValue="false"
>
<a-radio :value="false">开启</a-radio>
<a-radio :value="true">关闭</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</div>
</div>
<a-divider />
<div :style="{ marginBottom: '16px' }">
<h3 class="post-setting-drawer-title">分类目录</h3>
<div class="post-setting-drawer-item">
<category-tree
v-model="selectedCategoryIds"
:categories="categories"
/>
<div>
<a-form layout="vertical">
<a-form-item v-if="categoryForm">
<category-select-tree
:categories="categories"
v-model="categoryToCreate.parentId"
/>
</a-form-item>
<a-form-item v-if="categoryForm">
<a-input
placeholder="分类名称"
v-model="categoryToCreate.name"
/>
</a-form-item>
<a-form-item v-if="categoryForm">
<a-input
placeholder="分类路径"
v-model="categoryToCreate.slugNames"
/>
</a-form-item>
<a-form-item>
<a-button
type="primary"
style="marginRight: 8px"
v-if="categoryForm"
@click="handlerCreateCategory"
>保存</a-button>
<a-button
type="dashed"
style="marginRight: 8px"
v-if="!categoryForm"
@click="toggleCategoryForm"
>新增</a-button>
<a-button
v-if="categoryForm"
@click="toggleCategoryForm"
>取消</a-button>
</a-form-item>
</a-form>
</div>
</div>
</div>
<a-divider />
<div :style="{ marginBottom: '16px' }">
<h3 class="post-setting-drawer-title">标签</h3>
<div class="post-setting-drawer-item">
<a-form layout="vertical">
<a-form-item>
<TagSelect v-model="selectedTagIds" />
</a-form-item>
</a-form>
</div>
</div>
<a-divider />
<div :style="{ marginBottom: '16px' }">
<h3 class="post-setting-drawer-title">摘要</h3>
<div class="post-setting-drawer-item">
<a-form layout="vertical">
<a-form-item>
<a-input
type="textarea"
:autosize="{ minRows: 5 }"
v-model="selectedPost.summary"
placeholder="不填写则会自动生成"
/>
</a-form-item>
</a-form>
</div>
</div>
<a-divider />
<div :style="{ marginBottom: '16px' }">
<h3 class="post-setting-drawer-title">缩略图</h3>
<div class="post-setting-drawer-item">
<div class="post-thum">
<img
class="img"
:src="selectedPost.thumbnail || '//i.loli.net/2019/05/05/5ccf007c0a01d.png'"
@click="()=>this.thumDrawerVisible=true"
>
<a-button
class="post-thum-remove"
type="dashed"
@click="handlerRemoveThumb"
>移除</a-button>
</div>
</div>
</div>
<a-divider class="divider-transparent" />
</div>
<AttachmentSelectDrawer
v-model="thumDrawerVisible"
@listenToSelect="handleSelectPostThumb"
:drawerWidth="460"
/>
<div class="bottom-control">
<a-button
@click="handleSavePostSettingsClick"
type="primary"
>保存</a-button>
</div>
</a-drawer>
</div> </div>
</template> </template>
<script> <script>
import categoryApi from '@/api/category' import categoryApi from '@/api/category'
import postApi from '@/api/post' import postApi from '@/api/post'
import optionApi from '@/api/option'
import { mixin, mixinDevice } from '@/utils/mixin.js'
import AttachmentSelectDrawer from '../attachment/components/AttachmentSelectDrawer'
import TagSelect from './components/TagSelect'
import CategoryTree from './components/CategoryTree'
const columns = [ const columns = [
{ {
title: '标题', title: '标题',
dataIndex: 'title', dataIndex: 'title',
width: '150px',
scopedSlots: { customRender: 'postTitle' } scopedSlots: { customRender: 'postTitle' }
}, },
{ {
@ -266,13 +442,18 @@ const columns = [
}, },
{ {
title: '操作', title: '操作',
width: '150px', width: '180px',
scopedSlots: { customRender: 'action' } scopedSlots: { customRender: 'action' }
} }
] ]
export default { export default {
name: 'PostList', name: 'PostList',
components: {}, components: {
AttachmentSelectDrawer,
TagSelect,
CategoryTree
},
mixins: [mixin, mixinDevice],
data() { data() {
return { return {
postStatus: postApi.postStatus, postStatus: postApi.postStatus,
@ -295,7 +476,16 @@ export default {
selectedRows: [], selectedRows: [],
categories: [], categories: [],
posts: [], posts: [],
postsLoading: false postsLoading: false,
postSettingVisible: false,
thumDrawerVisible: false,
selectedPost: {},
selectedCategoryIds: [],
selectedTagIds: [],
categoryForm: false,
categoryToCreate: {},
options: [],
keys: ['blog_url']
} }
}, },
computed: { computed: {
@ -309,6 +499,7 @@ export default {
created() { created() {
this.loadCategories() this.loadCategories()
this.loadPosts() this.loadPosts()
this.loadOptions()
}, },
methods: { methods: {
loadPosts() { loadPosts() {
@ -328,6 +519,11 @@ export default {
this.categories = response.data.data this.categories = response.data.data
}) })
}, },
loadOptions() {
optionApi.listAll(this.keys).then(response => {
this.options = response.data.data
})
},
handleEditClick(post) { handleEditClick(post) {
this.$router.push({ name: 'PostEdit', query: { postId: post.id } }) this.$router.push({ name: 'PostEdit', query: { postId: post.id } })
}, },
@ -412,7 +608,62 @@ export default {
this.loadPosts() this.loadPosts()
}) })
} }
},
//
handlePostSettingsDrawer(post) {
this.postSettingVisible = true
postApi.get(post.id).then(response => {
const post = response.data.data
this.selectedPost = post
this.selectedTagIds = post.tagIds
this.selectedCategoryIds = post.categoryIds
})
},
handleSelectPostThumb(data) {
this.selectedPost.thumbnail = data.path
this.thumDrawerVisible = false
},
handlerRemoveThumb() {
this.selectedPost.thumbnail = null
},
//
handleSavePostSettingsClick() {
this.selectedPost.categoryIds = this.selectedCategoryIds
this.selectedPost.tagIds = this.selectedTagIds
postApi.update(this.selectedPost.id, this.selectedPost, false).then(response => {
this.$log.debug('Updated post', response.data.data)
this.loadPosts()
this.$message.success('文章更新成功')
})
},
toggleCategoryForm() {
this.categoryForm = !this.categoryForm
},
handlerCreateCategory() {
categoryApi.create(this.categoryToCreate).then(response => {
this.loadCategories()
this.categoryToCreate = {}
})
},
//
onPostSettingsClose() {
this.postSettingVisible = false
this.selectedPost = {}
this.selectedTagIds = []
this.selectedCategoryIds = []
} }
} }
} }
</script> </script>
<style scoped>
a {
text-decoration: none;
}
.post-title {
max-width: 150px;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>

View File

@ -42,7 +42,14 @@ export default {
}, },
created() { created() {
this.loadTags() this.loadTags()
this.selectedTagNames = this.tagIds.map(tagId => this.tagIdMap[tagId].name) },
watch: {
tags(newValue, oldValue) {
// tags使
if (newValue) {
this.selectedTagNames = this.tagIds.map(tagId => this.tagIdMap[tagId].name)
}
}
}, },
computed: { computed: {
tagIdMap() { tagIdMap() {

View File

@ -96,6 +96,18 @@
:dataSource="formattedSheets" :dataSource="formattedSheets"
:pagination="false" :pagination="false"
> >
<span
slot="sheetTitle"
slot-scope="text,record"
class="sheet-title"
>
<a
:href="options.blog_url+'/s/'+record.url"
target="_blank"
>
<a-tooltip placement="topLeft" :title="'点击预览 '+text">{{ text }}</a-tooltip>
</a>
</span>
<span <span
slot="status" slot="status"
slot-scope="statusProperty" slot-scope="statusProperty"
@ -103,7 +115,6 @@
<a-badge :status="statusProperty.status" /> <a-badge :status="statusProperty.status" />
{{ statusProperty.text }} {{ statusProperty.text }}
</span> </span>
<span <span
slot="updateTime" slot="updateTime"
slot-scope="updateTime" slot-scope="updateTime"
@ -189,7 +200,8 @@ const internalColumns = [
const customColumns = [ const customColumns = [
{ {
title: '标题', title: '标题',
dataIndex: 'title' dataIndex: 'title',
scopedSlots: { customRender: 'sheetTitle' }
}, },
{ {
title: '状态', title: '状态',
@ -276,3 +288,15 @@ export default {
} }
} }
</script> </script>
<style scoped>
a{
text-decoration: none;
}
.sheet-title{
max-width: 300px;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>

View File

@ -41,7 +41,7 @@
> >
<a-list-item slot="renderItem" slot-scope="item, index" :key="index"> <a-list-item slot="renderItem" slot-scope="item, index" :key="index">
<!-- 日志图片集合 --> <!-- 日志图片集合 -->
<a-card <!-- <a-card
hoverable hoverable
v-for="(photo, photoIndex) in item.photos" v-for="(photo, photoIndex) in item.photos"
:key="photoIndex" :key="photoIndex"
@ -49,7 +49,7 @@
@click="handlerPhotoPreview(photo)" @click="handlerPhotoPreview(photo)"
> >
<img alt="example" :src="photo.thumbnail" slot="cover"> <img alt="example" :src="photo.thumbnail" slot="cover">
</a-card> </a-card> -->
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancelPreview"> <a-modal :visible="previewVisible" :footer="null" @cancel="handleCancelPreview">
<img <img
@ -126,7 +126,7 @@
<a-form-item> <a-form-item>
<a-input type="textarea" :autosize="{ minRows: 8 }" v-model="journal.content"/> <a-input type="textarea" :autosize="{ minRows: 8 }" v-model="journal.content"/>
</a-form-item> </a-form-item>
<a-form-item v-show="showMoreOptions"> <!-- <a-form-item v-show="showMoreOptions">
<UploadPhoto <UploadPhoto
@success="handlerPhotoUploadSuccess" @success="handlerPhotoUploadSuccess"
:photoList="photoList" :photoList="photoList"
@ -143,7 +143,7 @@
更多选项 更多选项
<a-icon type="down"/> <a-icon type="down"/>
</a> </a>
</a-form-item> </a-form-item> -->
</a-form> </a-form>
</a-modal> </a-modal>

View File

@ -136,9 +136,23 @@ export default {
avatar: '//cn.gravatar.com/avatar/08cf681fb7c6ad1b4fe70a8269c2103c?s=256&d=mm', avatar: '//cn.gravatar.com/avatar/08cf681fb7c6ad1b4fe70a8269c2103c?s=256&d=mm',
website: 'https://www.apkdv.com', website: 'https://www.apkdv.com',
github: 'https://github.com/appdev' github: 'https://github.com/appdev'
},
{
name: 'guqing',
avatar: '//cn.gravatar.com/avatar/ad062ba572c8b006bfd2cbfc43fdee5e?s=256&d=mm',
website: 'http://www.guqing.xyz',
github: 'https://github.com/guqing'
} }
], ],
steps: [ steps: [
{
date: '2019-07-09',
content: 'Halo v1.0.3 发布'
},
{
date: '2019-07-08',
content: 'Star 数达到 6500'
},
{ {
date: '2019-06-01', date: '2019-06-01',
content: '1.0 正式版发布' content: '1.0 正式版发布'

View File

@ -138,7 +138,9 @@
<AttachmentSelectDrawer <AttachmentSelectDrawer
v-model="attachmentDrawerVisible" v-model="attachmentDrawerVisible"
@listenToSelect="handleSelectAvatar" @listenToSelect="handleSelectAvatar"
@listenToSelectGravatar="handleSelectGravatar"
title="选择头像" title="选择头像"
isChooseAvatar
/> />
</div> </div>
</template> </template>
@ -149,6 +151,7 @@ import userApi from '@/api/user'
import adminApi from '@/api/admin' import adminApi from '@/api/admin'
import optionApi from '@/api/option' import optionApi from '@/api/option'
import { mapMutations } from 'vuex' import { mapMutations } from 'vuex'
import MD5 from 'md5.js'
export default { export default {
components: { components: {
@ -217,6 +220,10 @@ export default {
handleSelectAvatar(data) { handleSelectAvatar(data) {
this.user.avatar = data.path this.user.avatar = data.path
this.attachmentDrawerVisible = false this.attachmentDrawerVisible = false
},
handleSelectGravatar() {
this.user.avatar = '//cn.gravatar.com/avatar/' + new MD5().update(this.user.email).digest('hex') + '&d=mm'
this.attachmentDrawerVisible = false
} }
} }
} }