rewrite write page

This commit is contained in:
simple321vip
2022-10-28 00:52:28 +08:00
parent 6fc98d832b
commit 2e2dbbbf72
3 changed files with 383 additions and 181 deletions
+31
View File
@@ -0,0 +1,31 @@
import { MockMethod } from 'vite-plugin-mock'
export default [
{
url: '/auth/api/v1/author/blog/content/0001',
method: 'get',
response: ({ body, query }) => {
return {
content: "asdasdasdasdsadasdasdasdasdas"
}
}
},
{
url: '/auth/api/v1/author/blog/content/0002',
method: 'get',
response: ({ body, query }) => {
return {
content: "wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"
}
}
},
{
url: '/auth/api/v1/author/blog/content',
method: 'POST',
response: ({ body, query }) => {
return {
content: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
}
},
] as MockMethod[]
+101 -2
View File
@@ -4,11 +4,11 @@ export default [
{ {
url: '/auth/api/v1/author/blog/list', url: '/auth/api/v1/author/blog/list',
method: 'get', method: 'get',
response: () => { response: ({ body, query }) => {
return [ return [
{ {
btId: "001", btId: "001",
btName: "your world", btName: "your world---",
blog_list: [ blog_list: [
{ {
bid: "0001", bid: "0001",
@@ -48,6 +48,27 @@ export default [
], ],
order: 1 order: 1
}, },
{
btId: "003",
btName: "my world",
blog_list: [
{
bid: "0003",
title: "three",
content: "nothing",
btId: "002",
order: 0,
},
{
bid: "0004",
title: "two",
content: "anything",
btId: "002",
order: 1,
},
],
order: 2
},
] ]
} }
}, },
@@ -100,5 +121,83 @@ export default [
}, },
] ]
} }
},
{
url: '/auth/api/v1/author/blog_type',
method: 'put',
response: () => {
return {
btId: "001",
btName: "your world---",
blog_list: [
{
bid: "0001",
title: "one",
content: "nothing",
btId: "001",
order: 0,
},
],
order: 2,
} }
}
},
{
url: '/auth/api/v1/author/blog_type',
method: 'post',
response: () => {
return {
}
}
},
{
url: '/auth/api/v1/author/blog_type',
method: 'delete',
response: ({ body, query }) => {
return [
{
btId: "001",
btName: "your world---",
blog_list: [
{
bid: "0001",
title: "one",
content: "nothing",
btId: "001",
order: 0,
},
{
bid: "0002",
title: "two",
content: "anything",
btId: "001",
order: 1,
},
],
order: 0
},
{
btId: "002",
btName: "my world",
blog_list: [
{
bid: "0003",
title: "three",
content: "nothing",
btId: "002",
order: 0,
},
{
bid: "0004",
title: "two",
content: "anything",
btId: "002",
order: 1,
},
],
order: 1
},
]
}
},
] as MockMethod[] ] as MockMethod[]
+248 -176
View File
@@ -1,7 +1,18 @@
<template> <template>
<div class="blog_editer" v-if="isReady"> <div class="blog_editer" v-if="isReady">
<div class="bt_section" :style="btWholeStyle">
<el-button class="bt-input" @click="contentDialogVisible = true">增加一个分类</el-button>
<div class="side_bar">
<el-button class="operate_button" v-if="collapsible[0] == 1" :icon="CaretRight" @click="collapsible[0] = 0"
size="small" />
<el-button class="operate_button" v-if="collapsible[0] == 0" :icon="CaretLeft" @click="collapsible[0] = 1"
size="small" />
</div>
<div class="bt_section" :style="btWholeStyle" v-show="collapsible[0] == 0">
<div class="item_header">
<el-button class="item_header_button" @click="blogTypeCreateDialogVisible = true">增加一个分类</el-button>
</div>
<draggable :list="blogTypes" ghost-class="ghost" handle=".move" animation="300" :force-fallback="true" itemKey="" <draggable :list="blogTypes" ghost-class="ghost" handle=".move" animation="300" :force-fallback="true" itemKey=""
filter=".forbid" chosen-class="chosenClass" :fallback-class="true" :fallback-on-body="true" filter=".forbid" chosen-class="chosenClass" :fallback-class="true" :fallback-on-body="true"
:touch-start-threshold="50" :fallback-tolerance="50" @start="onStart" @end="onEnd" group="group1" :touch-start-threshold="50" :fallback-tolerance="50" @start="onStart" @end="onEnd" group="group1"
@@ -9,17 +20,27 @@
<template #item="{ element }"> <template #item="{ element }">
<div class="item"> <div class="item">
<label class="move"></label> <label class="move"></label>
<el-button class="bt-input" @click="onclickTypeTab(element.order)">{{ element.btName }}</el-button> <p class="bt-input" @click="onclickTypeTab(element.order)">{{ element.btName }}</p>
<el-icon v-show="checkedBlogIndex == element.order"> <div>
<Setting /> <el-button class="operate_button" :icon="Setting" size="small" v-show="checkedBlogIndex == element.order"
</el-icon> @click="handleCreateBlogType()" />
</div>
</div> </div>
</template> </template>
</draggable> </draggable>
</div> </div>
<div class="b_section" :style="bWholeStyle">
<el-button class="bt-input" :disabled="isclicked" @click="insertBlog">增加一个博客</el-button>
<div class="side_bar">
<el-button class="operate_button" v-if="collapsible[1] == 1" :icon="CaretRight" @click="collapsible[1] = 0"
size="small" />
<el-button class="operate_button" v-if="collapsible[1] == 0" :icon="CaretLeft" @click="collapsible[1] = 1"
size="small" />
</div>
<div class="b_section" :style="bWholeStyle" v-show="collapsible[1] == 0">
<div class="item_header">
<el-button class="item_header_button" :disabled="isclicked" @click="insertBlog">增加一个博客</el-button>
</div>
<draggable :list="blogTypes[checkedBlogIndex].blogs" ghost-class="ghost" handle=".move" animation="300" <draggable :list="blogTypes[checkedBlogIndex].blogs" ghost-class="ghost" handle=".move" animation="300"
:force-fallback="true" itemKey="" filter=".forbid" chosen-class="chosenClass" :fallback-class="true" :force-fallback="true" itemKey="" filter=".forbid" chosen-class="chosenClass" :fallback-class="true"
:fallback-on-body="true" :touch-start-threshold="50" :fallback-tolerance="50" @start="onStart" @end="onEnd" :fallback-on-body="true" :touch-start-threshold="50" :fallback-tolerance="50" @start="onStart" @end="onEnd"
@@ -27,14 +48,17 @@
<template #item="{ element }"> <template #item="{ element }">
<div class="item"> <div class="item">
<label class="move"></label> <label class="move"></label>
<el-button class="bt-input" @click="onclickBlogTab(element)">{{ element.title }}</el-button> <p class="bt-input" @click="onclickBlogTab(element)">{{ element.title }}</p>
<el-icon v-show="checkedBlogIndex == element.order"> <div>
<Setting /> <el-button class="operate_button" v-show="checkedIndex == element.order" :icon="Edit" size="small"
</el-icon> @click="deleteDialogVisible = true" />
</div>
</div> </div>
</template> </template>
</draggable> </draggable>
</div> </div>
<div class="c_section"> <div class="c_section">
<div class="title_style"> <div class="title_style">
<el-input v-model="blogTypes[checkedBlogIndex].blogs[checkedIndex].title" @keyup.enter.native="saveTitle" <el-input v-model="blogTypes[checkedBlogIndex].blogs[checkedIndex].title" @keyup.enter.native="saveTitle"
@@ -50,36 +74,35 @@
:style="{ height: innerHeight }" /> :style="{ height: innerHeight }" />
</div> </div>
</div> </div>
<el-dialog v-model="dialogVisible" title="修改博客分类名称" width="30%">
<el-input v-model="(blogTypes[checkedBlogIndex] as BlogType).btName"></el-input> <!-- create blogtype dialog -->
<template #footer> <el-dialog v-model="blogTypeCreateDialogVisible" title="新的博客分类" width="30%">
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="saveType">确认</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="contentDialogVisible" title="新的博客分类" width="30%">
<el-input v-model="btName"> <el-input v-model="btName">
</el-input> </el-input>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="contentDialogVisible = false">取消</el-button> <el-button @click="blogTypeCreateDialogVisible = false">取消</el-button>
<el-button type="primary" @click="insertBlogType">确认</el-button> <el-button type="primary" @click="insertBlogType">确认</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
<el-dialog v-model="btdeleteDialogVisible" title="删除博客分类" width="30%">
你正在对 {{ blogTypes[checkedBlogIndex].btName }} <!-- edit and delete blogtype dialog -->
<el-input v-model="btName" :placeholder="'请输入<' + blogTypes[checkedBlogIndex].btName + '>'"> <el-dialog v-model="blogTypeEditDialogVisible" title="博客分类 Setting" width="30%">
你正在对 {{ blogTypes[checkedBlogIndex].btName }}进行操作
<div style="display: flex; margin: 10px">
<el-button type="primary" @click="saveBlogType()">修改</el-button>
<el-input v-model="btName">
</el-input> </el-input>
<template #footer> </div>
<span class="dialog-footer"> <div style="display: flex; margin: 10px">
<el-button @click="btdeleteDialogVisible = false">取消</el-button> <el-button type="danger" @click="deleteBlogType()">删除</el-button>
<el-button type="primary" @click="deleteBlogType">确认</el-button> <el-input v-model="deleteBtName" :placeholder="'请输入 ' + blogTypes[checkedBlogIndex].btName + ' 进行删除'">
</span> </el-input>
</template> </div>
</el-dialog> </el-dialog>
<!-- delete blog dialog -->
<el-dialog v-model="deleteDialogVisible" title="删除博客" width="30%"> <el-dialog v-model="deleteDialogVisible" title="删除博客" width="30%">
你正在对 {{ blogTypes[checkedBlogIndex].blogs[checkedIndex].title }} 你正在对 {{ blogTypes[checkedBlogIndex].blogs[checkedIndex].title }}
<el-input v-model="btName" :placeholder="'请输入<删除>'"> <el-input v-model="btName" :placeholder="'请输入<删除>'">
@@ -98,7 +121,7 @@
import { onMounted, reactive, ref, watch } from 'vue' import { onMounted, reactive, ref, watch } from 'vue'
import $moment from "moment" import $moment from "moment"
import MdEditor from 'md-editor-v3' import MdEditor from 'md-editor-v3'
import { Edit } from "@element-plus/icons-vue" import { Edit, CaretRight, CaretLeft, Setting } from "@element-plus/icons-vue"
import 'md-editor-v3/lib/style.css' import 'md-editor-v3/lib/style.css'
import { import {
updateBtName, updateBtName,
@@ -132,9 +155,8 @@ type BlogType = {
order: number order: number
} }
const blogTypes = reactive<BlogType[]>([]) const blogTypes = reactive<BlogType[]>([])
const dialogVisible = ref(false) const blogTypeCreateDialogVisible = ref(false)
const contentDialogVisible = ref(false) const blogTypeEditDialogVisible = ref(false)
const btdeleteDialogVisible = ref(false)
const deleteDialogVisible = ref(false) const deleteDialogVisible = ref(false)
let checkedIndex = ref<number>(0) let checkedIndex = ref<number>(0)
@@ -143,6 +165,9 @@ let isclicked = ref(false)
let isReady = ref(false) let isReady = ref(false)
let updated = ref(false) let updated = ref(false)
let startTime = reactive($moment()); let startTime = reactive($moment());
// tmp btName for create, edit, delete
let btName = ref("")
let deleteBtName = ref("")
/* /*
draggable 对CSS样式没有什么要求万物皆可拖拽 draggable 对CSS样式没有什么要求万物皆可拖拽
@@ -160,25 +185,6 @@ const state = reactive({
}) })
// 関数定義 // 関数定義
//拖拽开始的事件
const onStart = () => {
console.log("开始拖拽");
};
//拖拽结束的事件
const onEnd = () => {
blogTypes.forEach((blogType, index) => {
blogType.order = index
})
sortBlogType()
}
const onMove = (e: any) => {
//不允许停靠
if (e.relatedContext.element.disabledPark == true) return false;
return true;
}
/** /**
* Blog一覧取得 * Blog一覧取得
*/ */
@@ -210,7 +216,7 @@ const getTestData = async () => {
}) })
isReady.value = true isReady.value = true
checkedBlogIndex.value = blogTypes[0].order checkedBlogIndex.value = blogTypes[0].order
checkedIndex.value = blogTypes.values().next().value.blogs.keys().next().value checkedIndex.value = 0
// TODO 需要优化部分 // TODO 需要优化部分
/** /**
* 延迟执行一秒 * 延迟执行一秒
@@ -233,27 +239,26 @@ const getTestData = async () => {
/** /**
* BlogTypeを選べる * BlogTypeを選べる
* @param key * @param order
*/ */
const onclickTypeTab = (order: number) => { const onclickTypeTab = (order: number) => {
checkedBlogIndex.value = order checkedBlogIndex.value = order
const bid = blogTypes[order].blogs.values().next().value.bid const bid = blogTypes[order].blogs[0].bid
// getContent(bid).then(response => { getContent(bid).then(response => {
// (blogTypes[order].blogs.get(bid) as Blog).content = response.data.content blogTypes[order].blogs[0].content = response.data.content
// checkedBlogIndex.value = order checkedBlogIndex.value = order
// checkedIndex.value = bid checkedIndex.value = 0
// })
}
const onclickBlogTab = (blog: Blog) => {
getContent(blog.bid).then(response => {
blogTypes[checkedBlogIndex.value].blogs[checkedIndex.value].content = response.data.content
}) })
} }
const handleEditBtName = (bt: BlogType) => { const onclickBlogTab = (blog: Blog) => {
dialogVisible.value = true checkedIndex.value = blog.order
getContent(blog.bid).then(response => {
blogTypes[checkedBlogIndex.value].blogs[checkedIndex.value].content = response.data.content
checkedIndex.value = blog.order
}).catch(() => {
checkedIndex.value = blog.order
})
} }
/** /**
@@ -276,18 +281,7 @@ const saveContent = () => {
}) })
} }
/**
* btName modify
*/
const saveType = () => {
const query = {
btId: checkedBlogIndex.value,
btName: (blogTypes[checkedBlogIndex.value] as BlogType).btName
}
updateBtName(query).then(response => {
dialogVisible.value = false
})
}
/** /**
* Blogタイトル修正 * Blogタイトル修正
@@ -350,14 +344,29 @@ const deleteBlog = () => {
blogTypes[checkedBlogIndex.value].blogs.splice(checkedIndex.value, 1) blogTypes[checkedBlogIndex.value].blogs.splice(checkedIndex.value, 1)
deleteDialogVisible.value = false deleteDialogVisible.value = false
} }
}) deleteDialogVisible.value = false
btName.value = "" btName.value = ""
}).catch(() => {
deleteDialogVisible.value = false
btName.value = ""
})
} }
} }
// Blogタイプ新規作成用、作成後、リセットする const handleCreateBlogType = () => {
let btName = ref("") btName.value = blogTypes[checkedBlogIndex.value].btName
blogTypeEditDialogVisible.value = true
}
/**
* create blogType
*/
const insertBlogType = () => { const insertBlogType = () => {
if (btName.value == "") {
blogTypeCreateDialogVisible.value = false
return
}
const data = { const data = {
btName: btName.value, btName: btName.value,
order: blogTypes.length order: blogTypes.length
@@ -383,32 +392,74 @@ const insertBlogType = () => {
blog_type.blogs.push(blog) blog_type.blogs.push(blog)
}) })
blogTypes.push(blog_type) blogTypes.push(blog_type)
checkedBlogIndex.value = response.data.btId checkedBlogIndex.value = response.data.order
checkedIndex.value = blog_type.blogs.keys().next().value checkedIndex.value = blog_type.blogs[0].order
contentDialogVisible.value = false blogTypeCreateDialogVisible.value = false
btName.value = "" btName.value = ""
}) })
} }
/**
* edit blogType
*/
const saveBlogType = () => {
if (btName.value == "") {
blogTypeEditDialogVisible.value = false
return
}
const query = {
btId: blogTypes[checkedBlogIndex.value].btId,
btName: btName.value,
}
updateBtName(query).then(() => {
console.log(blogTypes)
blogTypes[checkedBlogIndex.value].btName = btName.value
blogTypeEditDialogVisible.value = false
btName.value = ""
}).catch(() => {
btName.value = ""
blogTypeEditDialogVisible.value = false
})
}
const deleteBlogType = () => { const deleteBlogType = () => {
if (btName.value == (blogTypes[checkedBlogIndex.value] as BlogType).btName) { if (deleteBtName.value == blogTypes[checkedBlogIndex.value].btName) {
const data = { const data = {
btId: checkedBlogIndex.value btId: checkedBlogIndex.value
} }
removeBlogType(data).then((response) => { removeBlogType(data).then((response) => {
if (response.status == 200) { blogTypes.length = 0
blogTypes.splice(checkedBlogIndex.value, 1) response.data.sort((x: any, y: any) => { x.order - y.order })
checkedBlogIndex.value = blogTypes.keys().next().value response.data.forEach((element: any) => {
checkedIndex.value = blogTypes.values().next().value.blogs.keys().next().value const blog_type: BlogType = {
} else { btId: element.btId,
btName: element.btName,
blogs: [],
order: element.order
} }
btdeleteDialogVisible.value = false element.blog_list.forEach((item: any) => {
const blog: Blog = {
bid: item.bid,
btId: item.btId,
btName: item.btName,
title: item.title,
blog_prex: item.blog_prex,
autosave_control: item.autosave_control,
content: item.content,
order: item.order
}
blog_type.blogs.push(blog)
})
blogTypes.push(blog_type)
})
checkedBlogIndex.value = 0
checkedIndex.value = 0
blogTypeEditDialogVisible.value = false
}) })
btName.value = ""
} else { } else {
blogTypeEditDialogVisible.value = false
} }
deleteBtName.value = ""
} }
const sortBlogType = () => { const sortBlogType = () => {
@@ -448,26 +499,65 @@ getTestData()
// サイズ調整部分 // サイズ調整部分
type WholeStyle = { //拖拽开始的事件
width: string, const onStart = () => {
height: string console.log("开始拖拽");
};
//拖拽结束的事件
const onEnd = () => {
blogTypes.forEach((blogType, index) => {
blogType.order = index
})
sortBlogType()
} }
let innerHeight = ref("")
const onMove = (e: any) => {
//不允许停靠
if (e.relatedContext.element.disabledPark == true) return false;
return true;
}
type WholeStyle = any
const btWholeStyle = reactive<WholeStyle>({} as WholeStyle) const btWholeStyle = reactive<WholeStyle>({} as WholeStyle)
let btWidth = 0.10 * window.innerWidth
btWholeStyle.width = btWidth + 'px'
btWholeStyle.height = window.innerHeight + 'px'
const bWholeStyle = reactive<WholeStyle>({} as WholeStyle) const bWholeStyle = reactive<WholeStyle>({} as WholeStyle)
let bWidth = 0.23 * window.innerWidth
bWholeStyle.width = bWidth + 'px'
const cWholeStyle = reactive<WholeStyle>({} as WholeStyle) const cWholeStyle = reactive<WholeStyle>({} as WholeStyle)
let contentWidth = 0.67 * window.innerWidth const collapsible = reactive([0, 0])
cWholeStyle.width = contentWidth + 'px' const whole_width = reactive([0.15, 0.15])
innerHeight.value = (window.innerHeight - 50) + 'px' let innerHeight = ref("")
// onMounted(() => { const selected_style = {
"background-color": "#EBEBEB"
}
const unselected_style = {
"background-color": "#FFFFFF"
}
const setup_size = () => {
btWholeStyle.width = whole_width[0] * window.innerWidth + 'px'
bWholeStyle.width = whole_width[1] * window.innerWidth + 'px'
cWholeStyle.width = ((1 - whole_width[0] - whole_width[1]) * window.innerWidth - 44) + 'px'
innerHeight.value = (window.innerHeight - 50) + 'px'
btWholeStyle.height = window.innerHeight + 'px'
}
setup_size()
watch(collapsible, async () => {
if (collapsible[0] == 0) {
whole_width[0] = 0.15
} else {
whole_width[0] = 0
}
if (collapsible[1] == 0) {
whole_width[1] = 0.15
} else {
whole_width[1] = 0
}
btWholeStyle.width = whole_width[0] * window.innerWidth + 'px'
bWholeStyle.width = whole_width[1] * window.innerWidth + 'px'
cWholeStyle.width = ((1 - whole_width[0] - whole_width[1]) * window.innerWidth - 44) + 'px'
})
// })
</script> </script>
<style scoped> <style scoped>
@@ -495,102 +585,84 @@ innerHeight.value = (window.innerHeight - 50) + 'px'
border-bottom: 1px solid royalblue; border-bottom: 1px solid royalblue;
} }
.el-dropdown {
margin-right: 5px;
}
.blog_editer { .blog_editer {
display: flex; display: flex;
} }
.tab_list { .item_header {
display: flex; display: flex;
flex-direction: column; align-items: center;
border-top: 1px solid royalblue;
border-bottom: 1px solid royalblue;
} }
.item_header_button {
border: 0px;
height: 50px;
.itxst {
width: 600px;
} }
.move { .side_bar {
cursor: move; display: flex;
} align-items: center;
justify-content: flex-start;
table.tb { width: 20px;
color: #333;
border: solid 1px #999;
font-size: 13px;
border-collapse: collapse;
min-width: 100px;
user-select: none;
}
table.tb th {
background: rgb(168 173 217);
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #999;
text-align: left;
}
table.tb th:nth-of-type(1) {
text-align: center;
}
table.tb td {
background: #d6c8c8;
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #999;
}
table.tb td:nth-of-type(1) {
text-align: center;
} }
.item { .item {
/* border: solid 1px rgb(221, 221, 221); */
padding: 0px; padding: 0px;
text-align: left; margin-top: 3px;
/* background-color: rgb(247, 246, 246); */ margin-bottom: 3px;
margin-bottom: 10px;
display: flex; display: flex;
height: 50px;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
/* min-height: 100px; */ justify-items: center;
user-select: none; user-select: none;
cursor: move; border: 0px;
border-bottom: 1px;
} }
.item>label { .item>label {
/* border-bottom: solid 1px rgb(221, 221, 221); */
background-color: lightslategrey;
color: #333; color: #333;
height: 50px; height: 50px;
width: 10px; width: 15px;
} }
.item>label:hover { .item>label:hover {
cursor: move; cursor: move;
} }
.item>div {
display: flex;
flex-direction: column;
align-items: flex-end;
border: 0px;
}
.operate_button {
border-color: #FFFFFF;
width: 20px;
border: 0px;
}
.bt-input { .bt-input {
margin-left: 0px; margin: 0px;
padding-left: 10px; border: 0px;
padding-left: 0px;
padding-right: 5px;
font-size: 15px; font-size: 15px;
overflow: hidden; overflow: hidden;
line-height: 50px;
height: 50px; height: 50px;
width: 100px; width: 100px;
border-radius: 0px; flex-grow: 1;
border-right: 0px; cursor: pointer;
border-left: 0px; white-space: nowrap;
/* border-top: 1px solid royalblue; text-overflow: ellipsis;
border-bottom: 1px solid royalblue; */ }
.bt-input:hover {
background-color: #EBEBEB;
} }
.item>p { .item>p {