|
@@ -1,48 +1,51 @@
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
import { computed, onMounted, ref } from 'vue'
|
|
import { computed, onMounted, ref } from 'vue'
|
|
-import BetterSelect from '@/components/BetterSelect.vue'
|
|
|
|
|
|
+import CateSelect from '@/components/CateSelect.vue'
|
|
import TagCloud from '@/components/TagCloud.vue'
|
|
import TagCloud from '@/components/TagCloud.vue'
|
|
-import type { Tag } from '@/models'
|
|
|
|
|
|
+import type { PostBody, Tag } from '@/models'
|
|
import { api } from '@/utils/axios.ts'
|
|
import { api } from '@/utils/axios.ts'
|
|
|
|
+import { codeIcon, diaryIcon, othersIcon, writeIcon } from '@/assets/icons.ts'
|
|
|
|
+import { router } from '@/router'
|
|
|
|
|
|
const editorConfig = {
|
|
const editorConfig = {
|
|
leftToolbar: 'undo redo | image',
|
|
leftToolbar: 'undo redo | image',
|
|
rightToolbar: 'preview fullscreen',
|
|
rightToolbar: 'preview fullscreen',
|
|
}
|
|
}
|
|
|
|
|
|
-const tags = ref<Tag[] | null>(null);
|
|
|
|
|
|
+const tags = ref<Tag[] | null>(null)
|
|
|
|
|
|
function freshData() {
|
|
function freshData() {
|
|
- api.tagList().then(res => {
|
|
|
|
- tags.value = res.data;
|
|
|
|
- });
|
|
|
|
|
|
+ api.tagList().then((res) => {
|
|
|
|
+ tags.value = res.data
|
|
|
|
+ })
|
|
}
|
|
}
|
|
|
|
|
|
-const activeTags = ref<string[]>([]);
|
|
|
|
|
|
+const activeTags = ref<string[]>([])
|
|
|
|
|
|
const tagsView = computed<Tag[] | null>(() => {
|
|
const tagsView = computed<Tag[] | null>(() => {
|
|
- if (!tags.value) return null;
|
|
|
|
- return tags.value.map(e => {
|
|
|
|
- if (activeTags.value.includes(e.name)) return e;
|
|
|
|
- else return {
|
|
|
|
- color: "#888888",
|
|
|
|
- id: e.id,
|
|
|
|
- name: e.name
|
|
|
|
- }
|
|
|
|
|
|
+ if (!tags.value) return null
|
|
|
|
+ return tags.value.map((e) => {
|
|
|
|
+ if (activeTags.value.includes(e.name)) return e
|
|
|
|
+ else
|
|
|
|
+ return {
|
|
|
|
+ color: '#888888',
|
|
|
|
+ id: e.id,
|
|
|
|
+ name: e.name,
|
|
|
|
+ }
|
|
})
|
|
})
|
|
-});
|
|
|
|
|
|
+})
|
|
|
|
|
|
const handleSelectTag = (tag: Tag) => {
|
|
const handleSelectTag = (tag: Tag) => {
|
|
if (activeTags.value.includes(tag.name)) {
|
|
if (activeTags.value.includes(tag.name)) {
|
|
- activeTags.value = activeTags.value.filter(e => e != tag.name)
|
|
|
|
|
|
+ activeTags.value = activeTags.value.filter((e) => e != tag.name)
|
|
} else {
|
|
} else {
|
|
activeTags.value.push(tag.name)
|
|
activeTags.value.push(tag.name)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
- freshData();
|
|
|
|
-});
|
|
|
|
|
|
+ freshData()
|
|
|
|
+})
|
|
|
|
|
|
const title = ref('')
|
|
const title = ref('')
|
|
|
|
|
|
@@ -57,27 +60,61 @@ print('Hello, World!')
|
|
|
|
|
|
`)
|
|
`)
|
|
|
|
|
|
-const selected = ref('')
|
|
|
|
|
|
+const selectedCate = ref('其他')
|
|
|
|
+
|
|
|
|
+onMounted(() => {
|
|
|
|
+ let defaultCate = router.currentRoute.value.query['cate'];
|
|
|
|
+ if (Array.isArray(defaultCate) && defaultCate.length) {
|
|
|
|
+ defaultCate = defaultCate[0]
|
|
|
|
+ }
|
|
|
|
+ if (typeof defaultCate == "string" && cateOptions.map(e => e.value).includes(defaultCate)) {
|
|
|
|
+ selectedCate.value = defaultCate;
|
|
|
|
+ }
|
|
|
|
+})
|
|
|
|
|
|
-const options = [
|
|
|
|
- {label: "技术", value: "技术"},
|
|
|
|
- {label: "日志", value: "日志"},
|
|
|
|
- {label: "随笔", value: "随笔"},
|
|
|
|
- {label: "其他", value: "其他"},
|
|
|
|
|
|
+const cateOptions = [
|
|
|
|
+ { label: '技术', value: '技术', svg: codeIcon },
|
|
|
|
+ { label: '日志', value: '日志', svg: diaryIcon },
|
|
|
|
+ { label: '随笔', value: '随笔', svg: writeIcon },
|
|
|
|
+ { label: '其他', value: '其他', svg: othersIcon },
|
|
]
|
|
]
|
|
|
|
|
|
-const newTags = ref<string[]>([]);
|
|
|
|
|
|
+const newTags = ref<string[]>([])
|
|
|
|
+
|
|
|
|
+const validContent = computed(() => {
|
|
|
|
+ return text.value.length > 0 && title.value.length > 0 && selectedCate.value.length > 0
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+function buildPost(): PostBody | undefined {
|
|
|
|
+ if (!validContent.value) {
|
|
|
|
+ return undefined;
|
|
|
|
+ }
|
|
|
|
+ return {
|
|
|
|
+ content: text.value,
|
|
|
|
+ tags: [...activeTags.value, ...newTags.value],
|
|
|
|
+ title: title.value,
|
|
|
|
+ cate: selectedCate.value,
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
|
|
+function handleSubmit() {
|
|
|
|
+ const postBody = buildPost();
|
|
|
|
+ if (postBody) {
|
|
|
|
+ api.postPush(postBody)
|
|
|
|
+ }
|
|
|
|
+}
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<template>
|
|
<template>
|
|
<div>
|
|
<div>
|
|
<div class="post-item" style="padding: 12px 30px; overflow: hidden">
|
|
<div class="post-item" style="padding: 12px 30px; overflow: hidden">
|
|
- <div>
|
|
|
|
- <input class="p-input" type="text" placeholder="博文标题" v-model="title" />
|
|
|
|
- </div>
|
|
|
|
- <div style="display: flex; align-items: center; gap: 12px">
|
|
|
|
- <better-select :options="options" v-model="selected" placeholder="类型" width="64px"/>
|
|
|
|
|
|
+ <div style="display: flex; align-items: end; padding-bottom: 12px">
|
|
|
|
+ <cate-select
|
|
|
|
+ :options="cateOptions"
|
|
|
|
+ v-model="selectedCate"
|
|
|
|
+ placeholder="类型"
|
|
|
|
+ />
|
|
|
|
+ <input style="margin-bottom: 0" class="p-input" type="text" placeholder="博文标题" v-model="title" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="post-item" style="padding: 0; overflow: hidden">
|
|
<div class="post-item" style="padding: 0; overflow: hidden">
|
|
@@ -90,28 +127,26 @@ const newTags = ref<string[]>([]);
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="post-item" style="padding: 12px 30px 24px 30px">
|
|
<div class="post-item" style="padding: 12px 30px 24px 30px">
|
|
- <h1>
|
|
|
|
- 这篇文章是关于什么的?做个收纳吧~
|
|
|
|
- </h1>
|
|
|
|
- <TagCloud v-if="tagsView" :tags="tagsView" :on-click="handleSelectTag" v-model:new-tags="newTags" :addable="true"/>
|
|
|
|
|
|
+ <h1>这篇文章是关于什么的?做个收纳吧~</h1>
|
|
|
|
+ <TagCloud
|
|
|
|
+ v-if="tagsView"
|
|
|
|
+ :tags="tagsView"
|
|
|
|
+ :on-click="handleSelectTag"
|
|
|
|
+ v-model:new-tags="newTags"
|
|
|
|
+ :addable="true"
|
|
|
|
+ />
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="post-item footer" style="padding: 0 30px">
|
|
<div class="post-item footer" style="padding: 0 30px">
|
|
- <div class="p-button">
|
|
|
|
- 保存草稿
|
|
|
|
- </div>
|
|
|
|
- <div class="p-button-success">
|
|
|
|
- 发布博文
|
|
|
|
- </div>
|
|
|
|
|
|
+ <div class="p-button">保存草稿</div>
|
|
|
|
+ <div :class="validContent ? ['p-button-success'] : ['p-button-disabled']" @click="handleSubmit">发布博文</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<style scoped>
|
|
<style scoped>
|
|
-
|
|
|
|
.footer {
|
|
.footer {
|
|
display: flex;
|
|
display: flex;
|
|
justify-content: end;
|
|
justify-content: end;
|
|
}
|
|
}
|
|
-
|
|
|
|
</style>
|
|
</style>
|