|
|
|
<template>
|
|
|
|
<BlogHeader />
|
|
|
|
<div id="article-create">
|
|
|
|
<h3>发表文章</h3>
|
|
|
|
<form id="image_form">
|
|
|
|
<div class="form-elem">
|
|
|
|
<span>文章标题图片:</span>
|
|
|
|
<input
|
|
|
|
v-on:change="onFileChange"
|
|
|
|
type="file"
|
|
|
|
id="file"
|
|
|
|
style="padding-bottom: 10px"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
<form>
|
|
|
|
<div class="form-elem">
|
|
|
|
<span>标题:</span>
|
|
|
|
<input v-model="title" type="text" placeholder="输入标题" />
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="form-elem">
|
|
|
|
<span>分类:</span>
|
|
|
|
<span v-for="category in categories" :key="category.id">
|
|
|
|
<!--样式也可以通过 :style 绑定-->
|
|
|
|
<button
|
|
|
|
class="category-btn"
|
|
|
|
:style="categoryStyle(category)"
|
|
|
|
@click.prevent="chooseCategory(category)"
|
|
|
|
>
|
|
|
|
{{ category.title }}
|
|
|
|
</button>
|
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="form-elem">
|
|
|
|
<span>标签:</span>
|
|
|
|
<input
|
|
|
|
v-model="tags"
|
|
|
|
type="text"
|
|
|
|
placeholder="输入标签,用逗号分隔"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="form-elem">
|
|
|
|
<div style="margin-bottom: 10px;">正文:</div>
|
|
|
|
<textarea
|
|
|
|
v-model="body"
|
|
|
|
placeholder="输入正文"
|
|
|
|
rows="20"
|
|
|
|
cols="100"
|
|
|
|
></textarea>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="form-elem">
|
|
|
|
<button v-on:click.prevent="submit">提交</button>
|
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
<BlogFooter />
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import BlogHeader from "@/components/BlogHeader.vue";
|
|
|
|
import BlogFooter from "@/components/BlogFooter.vue";
|
|
|
|
import authorization from "@/utils/authorization";
|
|
|
|
import $ from "jquery";
|
|
|
|
import { onMounted } from "@vue/runtime-core";
|
|
|
|
import { useRouter } from 'vue-router';
|
|
|
|
import { ref } from "vue";
|
|
|
|
export default {
|
|
|
|
name: "ArticleCreate",
|
|
|
|
components: { BlogHeader, BlogFooter },
|
|
|
|
setup() {
|
|
|
|
// 文章标题
|
|
|
|
let title = ref("");
|
|
|
|
// 文章正文
|
|
|
|
let body = ref("");
|
|
|
|
// 数据库中所有的分类
|
|
|
|
let categories = ref([]);
|
|
|
|
// 选定的分类
|
|
|
|
let selectedCategory = ref(null);
|
|
|
|
// 标签
|
|
|
|
let tags = ref("");
|
|
|
|
// 标题图 id
|
|
|
|
let avatarID = ref(null);
|
|
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
// 页面初始化时获取所有分类
|
|
|
|
$.ajax({
|
|
|
|
url: "http://127.0.0.1:6789/api/category",
|
|
|
|
type: "GET",
|
|
|
|
success(resp) {
|
|
|
|
categories.value = resp;
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// 根据分类是否被选中,按钮的颜色发生变化
|
|
|
|
const categoryStyle = (category) => {
|
|
|
|
if (
|
|
|
|
selectedCategory.value !== null &&
|
|
|
|
category.id === selectedCategory.value.id
|
|
|
|
) {
|
|
|
|
return {
|
|
|
|
backgroundColor: "black",
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
backgroundColor: "lightgrey",
|
|
|
|
color: "black",
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
// 选取分类
|
|
|
|
const chooseCategory = (category) => {
|
|
|
|
// 如果点击已选取的分类,则将 selectedCategory 置空
|
|
|
|
if (
|
|
|
|
selectedCategory.value !== null &&
|
|
|
|
selectedCategory.value.id === category.id
|
|
|
|
) {
|
|
|
|
selectedCategory.value = null;
|
|
|
|
} else {
|
|
|
|
selectedCategory.value = category;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const onFileChange = (e) => {
|
|
|
|
// 将二进制文件数据添加到提交数据中
|
|
|
|
const file = e.target.files[0];
|
|
|
|
let formData = new FormData();
|
|
|
|
formData.append("content", file);
|
|
|
|
|
|
|
|
$.ajax({
|
|
|
|
url: "http://127.0.0.1:6789/api/avatar/",
|
|
|
|
type: "POST",
|
|
|
|
data: formData,
|
|
|
|
processData: false,
|
|
|
|
contentType: false,
|
|
|
|
headers: {
|
|
|
|
"Authorization":
|
|
|
|
"Bearer " + localStorage.getItem("access_blog"),
|
|
|
|
},
|
|
|
|
success(resp) {
|
|
|
|
avatarID.value = resp.id;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
// 点击提交按钮
|
|
|
|
const submit = () => {
|
|
|
|
// 前面封装的验证函数又用上了
|
|
|
|
authorization().then((response) => {
|
|
|
|
if (response[0]) {
|
|
|
|
// 需要传给后端的数据字典
|
|
|
|
let data = {
|
|
|
|
title: title.value,
|
|
|
|
body: body.value,
|
|
|
|
};
|
|
|
|
|
|
|
|
// 添加分类
|
|
|
|
if (selectedCategory.value) {
|
|
|
|
data.category_id = selectedCategory.value.id;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 标签预处理
|
|
|
|
data.tags = tags.value
|
|
|
|
// 用逗号分隔标签
|
|
|
|
.split(/[,,]/)
|
|
|
|
// 剔除标签首尾空格
|
|
|
|
.map((x) => x.trim())
|
|
|
|
// 剔除长度为零的无效标签
|
|
|
|
.filter((x) => x.charAt(0) !== "");
|
|
|
|
|
|
|
|
data.avatar_id = avatarID.value;
|
|
|
|
|
|
|
|
// 将发表文章请求发送至接口
|
|
|
|
// 成功后前往详情页面
|
|
|
|
const token = localStorage.getItem("access_blog");
|
|
|
|
$.ajax({
|
|
|
|
url: "http://127.0.0.1:6789/api/article/",
|
|
|
|
type: "POST",
|
|
|
|
data: JSON.stringify(data),
|
|
|
|
contentType: 'application/json',
|
|
|
|
dataType: 'json',
|
|
|
|
headers: {
|
|
|
|
Authorization: "Bearer " + token,
|
|
|
|
},
|
|
|
|
success(resp) {
|
|
|
|
router.push({
|
|
|
|
name: "detail",
|
|
|
|
params: { id: resp.id },
|
|
|
|
});
|
|
|
|
},
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
window.alert("令牌过期,请重新登录。");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
categories,
|
|
|
|
title,
|
|
|
|
body,
|
|
|
|
avatarID,
|
|
|
|
tags,
|
|
|
|
selectedCategory,
|
|
|
|
categoryStyle,
|
|
|
|
chooseCategory,
|
|
|
|
onFileChange,
|
|
|
|
submit,
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
.category-btn {
|
|
|
|
margin-right: 10px;
|
|
|
|
}
|
|
|
|
#article-create {
|
|
|
|
text-align: center;
|
|
|
|
font-size: large;
|
|
|
|
}
|
|
|
|
form {
|
|
|
|
text-align: left;
|
|
|
|
padding-left: 100px;
|
|
|
|
padding-right: 10px;
|
|
|
|
padding-bottom: 100px;
|
|
|
|
}
|
|
|
|
|
|
|
|
#image_form {
|
|
|
|
text-align: left;
|
|
|
|
padding-left: 100px;
|
|
|
|
padding-right: 10px;
|
|
|
|
padding-bottom: 0px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.form-elem {
|
|
|
|
padding: 10px;
|
|
|
|
}
|
|
|
|
|
|
|
|
input {
|
|
|
|
height: 25px;
|
|
|
|
padding-left: 10px;
|
|
|
|
width: 50%;
|
|
|
|
}
|
|
|
|
button {
|
|
|
|
height: 35px;
|
|
|
|
cursor: pointer;
|
|
|
|
border: none;
|
|
|
|
outline: none;
|
|
|
|
margin: 0 auto;
|
|
|
|
background-color: steelblue;
|
|
|
|
color: whitesmoke;
|
|
|
|
border-radius: 5px;
|
|
|
|
width: 50px;
|
|
|
|
}
|
|
|
|
</style>
|