feat: 开发中...
This commit is contained in:
@@ -1,9 +1,12 @@
|
|||||||
package cn.hamster3.application.blog.entity;
|
package cn.hamster3.application.blog.entity;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
import org.hibernate.validator.constraints.Length;
|
||||||
import org.springframework.data.annotation.CreatedBy;
|
import org.springframework.data.annotation.CreatedBy;
|
||||||
import org.springframework.data.annotation.CreatedDate;
|
import org.springframework.data.annotation.CreatedDate;
|
||||||
import org.springframework.data.annotation.LastModifiedBy;
|
import org.springframework.data.annotation.LastModifiedBy;
|
||||||
@@ -24,12 +27,15 @@ public class BlogEntity {
|
|||||||
@Column(name = "id", nullable = false, updatable = false)
|
@Column(name = "id", nullable = false, updatable = false)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
@Length(max = 128, message = "标题长度不能超过 128 个字符!")
|
||||||
@Column(name = "title", nullable = false, length = 128)
|
@Column(name = "title", nullable = false, length = 128)
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
@Column(name = "abstracts", nullable = false, length = 512)
|
@Length(max = 1024, message = "摘要长度不能超过 1024 个字符!")
|
||||||
|
@Column(name = "abstracts", nullable = false, length = 1024)
|
||||||
private String abstracts;
|
private String abstracts;
|
||||||
|
|
||||||
|
@NotBlank(message = "博客文章内容不能为空!")
|
||||||
@ToString.Exclude
|
@ToString.Exclude
|
||||||
@Lob
|
@Lob
|
||||||
@Basic(fetch = FetchType.LAZY)
|
@Basic(fetch = FetchType.LAZY)
|
||||||
@@ -42,6 +48,7 @@ public class BlogEntity {
|
|||||||
@Column(name = "publish", nullable = false)
|
@Column(name = "publish", nullable = false)
|
||||||
private Boolean publish = false;
|
private Boolean publish = false;
|
||||||
|
|
||||||
|
@NotNull(message = "标签不能为 null")
|
||||||
@Setter
|
@Setter
|
||||||
@ElementCollection
|
@ElementCollection
|
||||||
@Column(name = "tag")
|
@Column(name = "tag")
|
||||||
|
@@ -1,11 +1,9 @@
|
|||||||
package cn.hamster3.application.blog.vo.blog;
|
package cn.hamster3.application.blog.vo.blog;
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.hibernate.validator.constraints.Length;
|
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -13,20 +11,16 @@ import java.util.Set;
|
|||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class BlogUpdateRequireVO {
|
public class BlogUpdateRequireVO {
|
||||||
@Length(max = 32, message = "标题长度不能超过 32 个字符!")
|
|
||||||
@NotBlank(message = "标题不能为空!")
|
@NotBlank(message = "标题不能为空!")
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
@Length(max = 512, message = "摘要长度不能超过 512 个字符!")
|
|
||||||
private String abstracts;
|
private String abstracts;
|
||||||
|
|
||||||
@NotBlank(message = "博客文章内容不能为空!")
|
|
||||||
private String content;
|
private String content;
|
||||||
|
|
||||||
private Boolean top;
|
private Boolean top;
|
||||||
|
|
||||||
private Boolean publish;
|
private Boolean publish;
|
||||||
|
|
||||||
@NotNull(message = "标签不能为 null")
|
|
||||||
private Set<String> tags;
|
private Set<String> tags;
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,7 @@ spring:
|
|||||||
ddl-auto: update
|
ddl-auto: update
|
||||||
# open-in-view: true
|
# open-in-view: true
|
||||||
show-ddl: true
|
show-ddl: true
|
||||||
show-sql: true
|
# show-sql: true
|
||||||
autoconfigure:
|
autoconfigure:
|
||||||
exclude:
|
exclude:
|
||||||
# - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
|
# - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
|
||||||
|
@@ -43,6 +43,9 @@ onMounted(() => {
|
|||||||
.app-container {
|
.app-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
max-width: 1280px;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-header {
|
.app-header {
|
||||||
|
@@ -26,7 +26,7 @@ export const api = {
|
|||||||
console.log("current user info: ", vo.content);
|
console.log("current user info: ", vo.content);
|
||||||
} else {
|
} else {
|
||||||
globalStore.currentUserInfo = undefined;
|
globalStore.currentUserInfo = undefined;
|
||||||
console.warn("ckeck current user info failed!");
|
console.warn("ckeck current user info failed!", vo);
|
||||||
}
|
}
|
||||||
globalStore.save();
|
globalStore.save();
|
||||||
});
|
});
|
||||||
|
@@ -11,6 +11,10 @@ function showBlog() {
|
|||||||
router.push("/blog/" + props.blog.id + "/read/");
|
router.push("/blog/" + props.blog.id + "/read/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showTags(tag: string) {
|
||||||
|
console.log("show tag blogs: " + tag);
|
||||||
|
}
|
||||||
|
|
||||||
function showCreator() {
|
function showCreator() {
|
||||||
console.log("showCreator");
|
console.log("showCreator");
|
||||||
}
|
}
|
||||||
@@ -24,26 +28,49 @@ function showUpdater() {
|
|||||||
<el-card class="blog-card">
|
<el-card class="blog-card">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="blog-card-header">
|
<div class="blog-card-header">
|
||||||
<p @click="showBlog" class="blog-card-title">{{ blog.title }}</p>
|
<h1 @click="showBlog" class="blog-card-title">{{ blog.title }}</h1>
|
||||||
<div>
|
<div style="flex-grow: 1"></div>
|
||||||
|
<div @click="showCreator" class="blog-card-creater">
|
||||||
<p>
|
<p>
|
||||||
<el-avatar :size="24" src="/favicon.ico" />
|
<el-avatar
|
||||||
{{ blog.creator?.nickname }}
|
:size="24"
|
||||||
|
src="/favicon.ico"
|
||||||
|
style="vertical-align: middle"
|
||||||
|
/>
|
||||||
|
{{ blog.creator.nickname }}
|
||||||
</p>
|
</p>
|
||||||
<p @click="showCreator" class="blog-card-creater">
|
<p>
|
||||||
{{ " 发表于:" + blog.updateTime?.toLocaleString() }}
|
{{ " 首次发表于:" + blog.updateTime.toLocaleString() }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="blog-card-body">
|
<div class="blog-card-body">
|
||||||
<div class="blog-card-abstract" v-html="blog.abstracts"></div>
|
<div class="blog-card-abstract" v-html="blog.abstracts"></div>
|
||||||
<div class="blog-card-footer">
|
</div>
|
||||||
<div @click="showUpdater">
|
<div class="blog-card-footer">
|
||||||
<p>
|
<el-tag
|
||||||
{{ " 最后修改于:" + blog.updateTime?.toLocaleString() }}
|
style="margin-left: 5px"
|
||||||
</p>
|
v-for="tag in blog.tags"
|
||||||
</div>
|
type="info"
|
||||||
|
size="large"
|
||||||
|
@click="showTags(tag)"
|
||||||
|
>
|
||||||
|
{{ tag }}
|
||||||
|
</el-tag>
|
||||||
|
<div style="flex-grow: 1"></div>
|
||||||
|
<div @click="showUpdater" class="blog-card-updater">
|
||||||
|
<p>
|
||||||
|
<el-avatar
|
||||||
|
:size="24"
|
||||||
|
src="/favicon.ico"
|
||||||
|
style="vertical-align: middle"
|
||||||
|
/>
|
||||||
|
{{ blog.updater.nickname }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{{ " 最后修改于:" + blog.updateTime?.toLocaleString() }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -52,40 +79,51 @@ function showUpdater() {
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
.blog-card {
|
.blog-card {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.blog-card-header {
|
.blog-card-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.blog-card-header :hover {
|
.blog-card-header :hover {
|
||||||
|
cursor: pointer;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.blog-card-title {
|
.blog-card-title {
|
||||||
font-size: x-large;
|
font-size: x-large;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.blog-card-creater {
|
.blog-card-creater {
|
||||||
font-size: medium;
|
text-align: right;
|
||||||
|
font-size: small;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.blog-card-abstract {
|
.blog-card-abstract {
|
||||||
font-size: medium;
|
font-size: medium;
|
||||||
margin-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.blog-card-footer {
|
.blog-card-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
border: 1px solid #ccc;
|
border-top: 1px solid #ccc;
|
||||||
border-bottom-width: 0;
|
|
||||||
border-left-width: 0;
|
|
||||||
border-right-width: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.blog-card-footer :hover {
|
.blog-card-footer :hover {
|
||||||
|
cursor: pointer;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.blog-card-updater {
|
||||||
|
text-align: right;
|
||||||
|
font-size: small;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -56,7 +56,7 @@ function onSelectMenu(index: string) {
|
|||||||
{{ customMenu.text }}
|
{{ customMenu.text }}
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
|
|
||||||
<div class="flex-grow" />
|
<div style="flex-grow: 1" />
|
||||||
|
|
||||||
<el-menu-item index="/login" v-if="!globalStore.currentUserInfo?.id">
|
<el-menu-item index="/login" v-if="!globalStore.currentUserInfo?.id">
|
||||||
登录
|
登录
|
||||||
@@ -78,8 +78,4 @@ function onSelectMenu(index: string) {
|
|||||||
</el-menu>
|
</el-menu>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
.flex-grow {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
216
blog-frontend/src/components/manage/BlogManageComponent.vue
Normal file
216
blog-frontend/src/components/manage/BlogManageComponent.vue
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
|
||||||
|
import type { BlogInfoResponseVO } from "@/swagger";
|
||||||
|
|
||||||
|
import { api } from "@/api";
|
||||||
|
import router from "@/router";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
let pageIndex = ref(0);
|
||||||
|
let pageSize = 2;
|
||||||
|
let pageCount = 100;
|
||||||
|
const blogs = ref<Array<BlogInfoResponseVO>>();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
changePage(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
function editBlog(blogID: number) {
|
||||||
|
router.push("/blog/" + blogID + "/edit/");
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteBlog(blogID: number) {
|
||||||
|
api.BlogController.removeBlog(blogID).then((resp) => {
|
||||||
|
const vo = resp.data;
|
||||||
|
if (vo.code === 200) {
|
||||||
|
ElMessage({
|
||||||
|
type: "success",
|
||||||
|
message: "删除博客成功!",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ElMessage({
|
||||||
|
type: "error",
|
||||||
|
message: "删除博客失败:" + vo.msg,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showBlog(blogID: number) {
|
||||||
|
router.push("/blog/" + blogID + "/read/");
|
||||||
|
}
|
||||||
|
|
||||||
|
function showTags(tag: string) {
|
||||||
|
console.log("show tag blogs: " + tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showCreator() {
|
||||||
|
console.log("showCreator");
|
||||||
|
}
|
||||||
|
|
||||||
|
function showUpdater() {
|
||||||
|
console.log("showUpdater");
|
||||||
|
}
|
||||||
|
|
||||||
|
function changePage(newPage: number) {
|
||||||
|
api.BlogController.getBlogInfoList(newPage - 1, pageSize).then((resp) => {
|
||||||
|
const vo = resp.data;
|
||||||
|
const page = vo.content;
|
||||||
|
for (let item of page?.elements ?? []) {
|
||||||
|
item.createTime = new Date(item?.createTime ?? 0);
|
||||||
|
item.updateTime = new Date(item?.updateTime ?? 0);
|
||||||
|
}
|
||||||
|
blogs.value = page?.elements;
|
||||||
|
pageCount = page?.totalPage;
|
||||||
|
pageIndex.value = newPage;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="blog-container">
|
||||||
|
<div class="blog-card-container">
|
||||||
|
<el-card class="blog-card" v-for="blog in blogs">
|
||||||
|
<template #header>
|
||||||
|
<div class="blog-card-header">
|
||||||
|
<p @click="showBlog(blog.id)" class="blog-card-title">
|
||||||
|
{{ blog.title }}
|
||||||
|
</p>
|
||||||
|
<div style="flex-grow: 1"></div>
|
||||||
|
<div @click="showUpdater" class="blog-card-updater">
|
||||||
|
<p>
|
||||||
|
<el-avatar
|
||||||
|
:size="24"
|
||||||
|
src="/favicon.ico"
|
||||||
|
style="vertical-align: middle"
|
||||||
|
/>
|
||||||
|
{{ blog.updater.nickname }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{{ " 最后修改于:" + blog.updateTime?.toLocaleString() }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div @click="showCreator" class="blog-card-creater">
|
||||||
|
<p>
|
||||||
|
<el-avatar
|
||||||
|
:size="24"
|
||||||
|
src="/favicon.ico"
|
||||||
|
style="vertical-align: middle"
|
||||||
|
/>
|
||||||
|
{{ blog.creator.nickname }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{{ " 首次发表于:" + blog.updateTime.toLocaleString() }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="blog-card-body">
|
||||||
|
<div class="blog-card-abstract" v-html="blog.abstracts"></div>
|
||||||
|
</div>
|
||||||
|
<div class="blog-card-footer">
|
||||||
|
<el-tag
|
||||||
|
style="margin-left: 5px"
|
||||||
|
v-for="tag in blog.tags"
|
||||||
|
type="info"
|
||||||
|
size="large"
|
||||||
|
@click="showTags(tag)"
|
||||||
|
>
|
||||||
|
{{ tag }}
|
||||||
|
</el-tag>
|
||||||
|
<div style="flex-grow: 1"></div>
|
||||||
|
<div>
|
||||||
|
<el-button @click="editBlog(blog.id)" type="primary"
|
||||||
|
>编辑</el-button
|
||||||
|
>
|
||||||
|
<el-button @click="deleteBlog(blog.id)" type="danger"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex">
|
||||||
|
<div style="flex-grow: 1"></div>
|
||||||
|
<el-pagination
|
||||||
|
class="pagination"
|
||||||
|
background
|
||||||
|
layout="prev, pager, next"
|
||||||
|
:hide-on-single-page="false"
|
||||||
|
:current-page="pageIndex"
|
||||||
|
:page-count="pageCount"
|
||||||
|
@update:current-page="changePage"
|
||||||
|
/>
|
||||||
|
<div style="flex-grow: 1"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.blog-container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.blog-card-container {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.blog-card {
|
||||||
|
margin: 0 10px 10px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-card-header :hover {
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-card-title {
|
||||||
|
font-size: x-large;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-card-creater {
|
||||||
|
text-align: left;
|
||||||
|
font-size: small;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-card-updater {
|
||||||
|
text-align: left;
|
||||||
|
font-size: small;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-right: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-card-abstract {
|
||||||
|
font-size: medium;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-card-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-card-footer :hover {
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -35,6 +35,7 @@ function changeCustomCSS(cssText: string) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-input
|
<el-input
|
||||||
|
class="imput-line"
|
||||||
v-model="siteSetting.title"
|
v-model="siteSetting.title"
|
||||||
placeholder="网站标题"
|
placeholder="网站标题"
|
||||||
@change="changeSetting(siteSetting.keys.site.title, siteSetting.title)"
|
@change="changeSetting(siteSetting.keys.site.title, siteSetting.title)"
|
||||||
@@ -42,6 +43,7 @@ function changeCustomCSS(cssText: string) {
|
|||||||
maxlength="10"
|
maxlength="10"
|
||||||
/>
|
/>
|
||||||
<el-input
|
<el-input
|
||||||
|
class="imput-line"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
show-word-limit
|
show-word-limit
|
||||||
maxlength="1024"
|
maxlength="1024"
|
||||||
@@ -50,6 +52,7 @@ function changeCustomCSS(cssText: string) {
|
|||||||
@change="changeFooterHTML(siteSetting.footer)"
|
@change="changeFooterHTML(siteSetting.footer)"
|
||||||
/>
|
/>
|
||||||
<el-input
|
<el-input
|
||||||
|
class="imput-line"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
autosize
|
autosize
|
||||||
v-model="siteSetting.css"
|
v-model="siteSetting.css"
|
||||||
@@ -59,7 +62,7 @@ function changeCustomCSS(cssText: string) {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.el-input {
|
.imput-line {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -10,9 +10,10 @@ import type {
|
|||||||
IEditorConfig,
|
IEditorConfig,
|
||||||
} from "@wangeditor/editor";
|
} from "@wangeditor/editor";
|
||||||
|
|
||||||
import { api, globalStore } from "@/api";
|
|
||||||
import type { BlogInfoResponseVO, BlogUpdateRequireVO } from "@/swagger";
|
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
import { api } from "@/api";
|
||||||
|
import type { BlogUpdateRequireVO } from "@/swagger";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
|
|
||||||
const editorRef = shallowRef();
|
const editorRef = shallowRef();
|
||||||
@@ -24,7 +25,7 @@ const editBlog = reactive<BlogUpdateRequireVO>({
|
|||||||
content: "",
|
content: "",
|
||||||
tags: [],
|
tags: [],
|
||||||
});
|
});
|
||||||
let tags = ref<string>();
|
const tagInput = ref<string>("");
|
||||||
const blogID = parseInt(useRoute().params.id.toString());
|
const blogID = parseInt(useRoute().params.id.toString());
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -82,6 +83,29 @@ function cancelSave() {
|
|||||||
router.push("/blog/" + blogID + "/read/");
|
router.push("/blog/" + blogID + "/read/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addTag() {
|
||||||
|
if (tagInput.value.length === 0) {
|
||||||
|
ElMessage({
|
||||||
|
type: "warning",
|
||||||
|
message: "请输入标签名称!",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (editBlog.tags.includes(tagInput.value)) {
|
||||||
|
ElMessage({
|
||||||
|
type: "warning",
|
||||||
|
message: "该博文已拥有相同的标签名称!",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
editBlog.tags.push(tagInput.value);
|
||||||
|
tagInput.value = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeTag(index: number) {
|
||||||
|
editBlog.tags.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
function handleCreated(editor: IDomEditor) {
|
function handleCreated(editor: IDomEditor) {
|
||||||
editorRef.value = editor; // 记录 editor 实例,重要!
|
editorRef.value = editor; // 记录 editor 实例,重要!
|
||||||
}
|
}
|
||||||
@@ -122,11 +146,29 @@ function handleCreated(editor: IDomEditor) {
|
|||||||
maxlength="512"
|
maxlength="512"
|
||||||
show-word-limit
|
show-word-limit
|
||||||
type="textarea"
|
type="textarea"
|
||||||
|
autosize
|
||||||
v-model="editBlog.abstracts"
|
v-model="editBlog.abstracts"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="标签">
|
<el-form-item label="标签" style="display: flex">
|
||||||
<el-input placeholder="用 '|' 隔开" v-model="tags" />
|
<el-tag
|
||||||
|
style="margin-left: 5px"
|
||||||
|
v-for="(tag, index) in editBlog.tags"
|
||||||
|
:key="index"
|
||||||
|
closable
|
||||||
|
size="large"
|
||||||
|
@close="removeTag(index)"
|
||||||
|
>
|
||||||
|
{{ tag }}
|
||||||
|
</el-tag>
|
||||||
|
|
||||||
|
<div style="margin-left: 5px">
|
||||||
|
<el-input
|
||||||
|
style="margin: 0 5px 0 0; width: 100px"
|
||||||
|
v-model="tagInput"
|
||||||
|
/>
|
||||||
|
<el-button type="primary" @click="addTag">添加</el-button>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="是否置顶">
|
<el-form-item label="是否置顶">
|
||||||
<el-switch v-model="editBlog.top" />
|
<el-switch v-model="editBlog.top" />
|
||||||
|
@@ -29,12 +29,7 @@ function deleteBlog() {
|
|||||||
<el-container class="blog-container">
|
<el-container class="blog-container">
|
||||||
<el-header class="blog-header">
|
<el-header class="blog-header">
|
||||||
<el-row :gutter="20" style="height: 100%; padding: 0; margin: 0">
|
<el-row :gutter="20" style="height: 100%; padding: 0; margin: 0">
|
||||||
<el-col :span="4">
|
<el-col :span="4"> </el-col>
|
||||||
<div style="display: flex; width: 100% height: 100%">
|
|
||||||
<p>{{ blogInfo?.creator.nickname }}</p>
|
|
||||||
<div style="flex-grow: 1"></div>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="16">
|
<el-col :span="16">
|
||||||
<h1 class="blog-title">{{ blogInfo?.title }}</h1>
|
<h1 class="blog-title">{{ blogInfo?.title }}</h1>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -48,8 +43,8 @@ function deleteBlog() {
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-header>
|
</el-header>
|
||||||
<el-main class="blog-main">
|
<el-main class="blog-main">
|
||||||
<el-scrollbar class="blog-content">
|
<el-scrollbar class="blog-scrollbar">
|
||||||
<div v-html="blogInfo?.content"></div>
|
<div class="blog-content" v-html="blogInfo?.content"></div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</el-main>
|
</el-main>
|
||||||
</el-container>
|
</el-container>
|
||||||
@@ -69,24 +64,32 @@ function deleteBlog() {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.blog-author {
|
.blog-author {
|
||||||
font-size: x-large;
|
font-size: medium;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.blog-title {
|
.blog-title {
|
||||||
font-size: x-large;
|
font-size: x-large;
|
||||||
}
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
.blog-content {
|
text-overflow: ellipsis;
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.blog-main {
|
.blog-main {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.blog-scrollbar {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-content {
|
||||||
|
width: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -53,13 +53,10 @@ function load() {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
/* height: 50px; */
|
|
||||||
background: var(--el-color-primary-light-9);
|
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
color: var(--el-color-primary);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.infinite-list .infinite-list-item + .list-item {
|
.infinite-list .infinite-list-item {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -34,31 +34,47 @@ const onSubmit = () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-card class="login-card">
|
<div class="login-div">
|
||||||
<el-form :model="form" label-width="60px">
|
<div style="flex-grow: 1"></div>
|
||||||
<el-form-item label="邮箱">
|
<el-card class="login-card">
|
||||||
<el-input v-model="form.email" />
|
<el-form :model="form" label-width="60px">
|
||||||
</el-form-item>
|
<h1 class="card-title">用 户 登 录</h1>
|
||||||
<el-form-item label="密码">
|
<el-form-item label="邮箱">
|
||||||
<el-input v-model="form.password" type="password" show-password />
|
<el-input v-model="form.email" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item label="密码">
|
||||||
<el-button class="login-button" type="primary" @click="onSubmit"
|
<el-input v-model="form.password" type="password" show-password />
|
||||||
>登录</el-button
|
</el-form-item>
|
||||||
>
|
<el-form-item>
|
||||||
</el-form-item>
|
<el-button class="login-button" type="primary" @click="onSubmit"
|
||||||
</el-form>
|
>登录</el-button
|
||||||
</el-card>
|
>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
<div style="flex-grow: 1"></div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.login-div {
|
.login-div {
|
||||||
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-card {
|
.login-card {
|
||||||
width: 480px;
|
width: 480px;
|
||||||
margin: 0 auto;
|
max-width: 90%;
|
||||||
|
margin-bottom: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-button {
|
.login-button {
|
||||||
|
@@ -3,14 +3,20 @@ import { onMounted, ref } from "vue";
|
|||||||
|
|
||||||
import { globalStore } from "@/api";
|
import { globalStore } from "@/api";
|
||||||
import SiteManageComponent from "@/components/manage/SiteManageComponent.vue";
|
import SiteManageComponent from "@/components/manage/SiteManageComponent.vue";
|
||||||
|
import BlogManageComponent from "@/components/manage/BlogManageComponent.vue";
|
||||||
|
|
||||||
const activeName = ref<string>("site");
|
const activeName = ref<string>("site");
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (!globalStore.currentUserInfo?.id) {
|
setTimeout(() => {
|
||||||
location.pathname = "/";
|
console.log("check current user info");
|
||||||
console.log("not login!");
|
if (globalStore.currentUserInfo?.role === "ADMIN") {
|
||||||
}
|
console.log("current user is admin!");
|
||||||
|
} else {
|
||||||
|
location.pathname = "/";
|
||||||
|
console.warn("not admin user!");
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -19,7 +25,9 @@ onMounted(() => {
|
|||||||
<el-tab-pane label="网站设置" name="site">
|
<el-tab-pane label="网站设置" name="site">
|
||||||
<SiteManageComponent />
|
<SiteManageComponent />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="博文设置" name="third">Role</el-tab-pane>
|
<el-tab-pane label="博文设置" name="third">
|
||||||
|
<BlogManageComponent />
|
||||||
|
</el-tab-pane>
|
||||||
<el-tab-pane label="用户设置" name="user">Config</el-tab-pane>
|
<el-tab-pane label="用户设置" name="user">Config</el-tab-pane>
|
||||||
<el-tab-pane label="评论设置" name="test">Role</el-tab-pane>
|
<el-tab-pane label="评论设置" name="test">Role</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
@@ -28,8 +28,10 @@ const onSubmit = () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="register-div">
|
<div class="register-div">
|
||||||
<el-card>
|
<div style="flex-grow: 1"></div>
|
||||||
|
<el-card class="register-card">
|
||||||
<el-form :model="form" label-width="60px">
|
<el-form :model="form" label-width="60px">
|
||||||
|
<h1 class="card-title">用 户 注 册</h1>
|
||||||
<el-form-item label="邮箱">
|
<el-form-item label="邮箱">
|
||||||
<el-input v-model="form.email" />
|
<el-input v-model="form.email" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -46,17 +48,30 @@ const onSubmit = () => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
<div style="flex-grow: 1"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.register-div {
|
.register-div {
|
||||||
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-card {
|
.register-card {
|
||||||
width: 480px;
|
width: 480px;
|
||||||
margin: 0 auto;
|
max-width: 90%;
|
||||||
|
margin-bottom: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.register-button {
|
.register-button {
|
||||||
|
Reference in New Issue
Block a user