feat: 更多的博客配置项

This commit is contained in:
xiaozzzi
2024-04-10 20:44:00 +08:00
parent b1d7721edc
commit 7d14414605
12 changed files with 342 additions and 23 deletions

View File

@@ -39,10 +39,57 @@ public enum UserParamEnum {
*/
WEB_BLOG_LINKS(false, 0, ""),
/**
* 博客端专题特殊形式, 0:false;1:是
* 博客端专题特殊形式
* 0:否;1:是
*
* @since 1.13.0
*/
WEB_BLOG_SUBJECT_TITLE(false, 0, "0"),
/**
* 是否在文章内容的顶部显示文章的标题
* 0:否;1:是
*
* @since 1.15.0
*/
WEB_BLOG_SHOW_ARTICLE_NAME(false, 0, "1"),
/**
* 博客主题色
*
* @since 1.15.0
*/
WEB_BLOG_COLOR(false, 0, "rgb(104, 104, 104)"),
// ----------< 博客水印 >----------
/**
* 启用博客水印
* 0:否;1:是
*
* @since 1.15.0
*/
WEB_BLOG_WATERMARK_ENABLED(false, 0, "0"),
/**
* 水印内容
*
* @since 1.15.0
*/
WEB_BLOG_WATERMARK_CONTENT(false, 0, ""),
/**
* 水印字体大小
*
* @since 1.15.0
*/
WEB_BLOG_WATERMARK_FONTSIZE(false, 0, "15"),
/**
* 水印颜色
*
* @since 1.15.0
*/
WEB_BLOG_WATERMARK_COLOR(false, 0, "rgba(157, 157, 157, 0.2)"),
/**
* 水印密集度
*
* @since 1.15.0
*/
WEB_BLOG_WATERMARK_GAP(false, 0, "100"),
;
/**

View File

@@ -3,6 +3,7 @@ package com.blossom.backend.base.paramu.pojo;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 修改参数
@@ -21,6 +22,7 @@ public class UserParamUpdReq {
/**
* 参数值
*/
@NotNull(message = "参数值为必填项")
private String paramValue;
/**

View File

@@ -97,7 +97,14 @@ export const DEFAULT_USER_INFO = {
WEB_GONG_WANG_AN_BEI: '',
WEB_BLOG_URL_ERROR_TIP_SHOW: 1,
WEB_BLOG_LINKS: '',
WEB_BLOG_SUBJECT_TITLE: false
WEB_BLOG_SUBJECT_TITLE: false,
WEB_BLOG_COLOR: '',
WEB_BLOG_SHOW_ARTICLE_NAME: true,
WEB_BLOG_WATERMARK_ENABLED: false,
WEB_BLOG_WATERMARK_CONTENT: '',
WEB_BLOG_WATERMARK_FONTSIZE: 15,
WEB_BLOG_WATERMARK_COLOR: '',
WEB_BLOG_WATERMARK_GAP: 100
}
}

View File

@@ -220,6 +220,7 @@ const fold = () => {
.chart-container {
@include box(100%, calc(100% - 315px));
height: 100%;
overflow-x: hidden;
overflow-y: scroll;
}

View File

@@ -4,24 +4,24 @@
<el-tab-pane label="客户端配置" name="client">
<div class="tab-content"><ConfigClient></ConfigClient></div>
</el-tab-pane>
<el-tab-pane label="服务器配置" name="server" :lazy="true" v-if="userStore.userinfo.type === 1">
<el-tab-pane label="服务器配置" name="server" :lazy="true" v-if="userStore.userinfo.type === 1 && userStore.isLogin">
<div class="tab-content"><ConfigServer ref="ConfigServerRef"></ConfigServer></div>
</el-tab-pane>
<el-tab-pane label="博客配置" name="blog" :lazy="true">
<el-tab-pane label="博客配置" name="blog" :lazy="true" v-if="userStore.isLogin">
<div class="tab-content"><ConfigBlog ref="ConfigBlogRef"></ConfigBlog></div>
</el-tab-pane>
<el-tab-pane label="修改个人信息" name="userinfo" :lazy="true">
<el-tab-pane label="修改个人信息" name="userinfo" :lazy="true" v-if="userStore.isLogin">
<div class="tab-content"><ConfigUserinfo ref="ConfigUserinfoRef"></ConfigUserinfo></div>
</el-tab-pane>
<el-tab-pane label="修改登录密码" name="password" :lazy="true">
<el-tab-pane label="修改登录密码" name="password" :lazy="true" v-if="userStore.isLogin">
<div class="tab-content"><ConfigUpdPwd></ConfigUpdPwd></div>
</el-tab-pane>
<el-tab-pane label="添加使用账号" name="adduser" :lazy="true" v-if="userStore.userinfo.type === 1">
<el-tab-pane label="添加使用账号" name="adduser" :lazy="true" v-if="userStore.userinfo.type === 1 && userStore.isLogin">
<div class="tab-content">
<ConfigAddUser></ConfigAddUser>
</div>
</el-tab-pane>
<el-tab-pane label="实时访问流量" name="flow" v-if="userStore.isLogin && userStore.userinfo.type === 1" :lazy="true">
<el-tab-pane label="实时访问流量" name="flow" :lazy="true" v-if="userStore.isLogin && userStore.userinfo.type === 1 && userStore.isLogin">
<SentinelResources></SentinelResources>
</el-tab-pane>
</el-tabs>

View File

@@ -25,6 +25,30 @@
</div>
</el-form-item>
<el-divider></el-divider>
<el-form-item label="博客主题色">
<bl-row class="colors">
<el-input
size="default"
v-model="userParamForm.WEB_BLOG_COLOR"
:style="{
width: '180px',
marginRight: '15px',
'--el-input-text-color': userParamForm.WEB_BLOG_COLOR,
'--el-input-border-color': userParamForm.WEB_BLOG_COLOR
}"></el-input>
<el-color-picker
size="default"
popper-class="theme-color-picker"
v-model="userParamForm.WEB_BLOG_COLOR"
color-format="rgb"
@change="changeBlogColor" />
<div class="color-item" v-for="color in colors" :key="color" :style="{ backgroundColor: color }" @click="changeBlogColor(color)"></div>
</bl-row>
<div class="conf-tip">博客主题色主要影响专题样式颜色以及文章中的链接颜色</div>
</el-form-item>
<el-form-item label="博客名称">
<el-input size="default" v-model="userParamForm.WEB_LOGO_NAME" @change="(cur: any) => updParam('WEB_LOGO_NAME', cur)"></el-input>
<div class="conf-tip">博客左上角名称以及在浏览器标签中的名称</div>
@@ -35,6 +59,17 @@
<div class="conf-tip">博客左上角 Logo 的访问地址以及在浏览器标签中的 Logo</div>
</el-form-item>
<el-form-item label="是否显示文章标题">
<bl-row>
<el-switch
v-model="userParamForm.WEB_BLOG_SHOW_ARTICLE_NAME"
size="default"
style="margin-right: 10px"
@change="(cur: boolean) => updParam('WEB_BLOG_SHOW_ARTICLE_NAME', cur ? '1' : '0')" />
</bl-row>
<div class="conf-tip">是否在文章内容的顶部显示文章的标题</div>
</el-form-item>
<el-form-item label="开启专题特殊样式">
<bl-row>
<el-switch
@@ -46,19 +81,83 @@
<div class="conf-tip">是否在博客文档列表中以特殊的样式显示专题</div>
</el-form-item>
<el-form-item label="自定义信息">
<el-form-item label="开启文章水印">
<bl-row>
<el-switch
size="default"
v-model="userParamForm.WEB_BLOG_WATERMARK_ENABLED"
@change="(cur: boolean) => updParam('WEB_BLOG_WATERMARK_ENABLED', cur ? '1' : '0')" />
</bl-row>
<div class="conf-tip">是否开启博客文章背景文字水印</div>
<div class="conf-watermark" v-if="userParamForm.WEB_BLOG_WATERMARK_ENABLED">
<bl-row>
<bl-row width="60%">
<div class="label">水印内容</div>
<el-input
size="default"
v-model="userParamForm.WEB_BLOG_WATERMARK_CONTENT"
@change="(cur: any) => updParam('WEB_BLOG_WATERMARK_CONTENT', cur)"></el-input>
</bl-row>
<bl-row width="40%">
<div class="label">水印大小</div>
<el-input-number
size="default"
v-model="userParamForm.WEB_BLOG_WATERMARK_FONTSIZE"
@change="(cur: any) => updParam('WEB_BLOG_WATERMARK_FONTSIZE', cur.toString())"></el-input-number>
</bl-row>
</bl-row>
<bl-row style="margin-top: 10px">
<bl-row width="60%">
<div class="label">水印颜色</div>
<el-input
size="default"
style="width: calc(100% - 120px); margin-right: 8px"
v-model="userParamForm.WEB_BLOG_WATERMARK_COLOR"
@change="(cur: any) => updParam('WEB_BLOG_WATERMARK_COLOR', cur)">
<template #suffix>
<el-tooltip effect="light" placement="top" transition="none">
<template #content> 使用透明颜色会有更好的显示效果<br />: rgba(157, 157, 157, 0.2)</template>
<span class="iconbl bl-admonish-line"></span>
</el-tooltip>
</template>
</el-input>
<el-tooltip effect="light" placement="top" transition="none">
<template #content> 使用透明颜色会有更好的效果<br />: rgba(157, 157, 157, 0.2)</template>
<el-color-picker
size="default"
popper-class="theme-color-picker"
v-model="userParamForm.WEB_BLOG_WATERMARK_COLOR"
color-format="rgba"
show-alpha
@change="changeWatermarkColor" />
</el-tooltip>
</bl-row>
<bl-row width="40%">
<div class="label">密集程度</div>
<el-input-number
size="default"
v-model="userParamForm.WEB_BLOG_WATERMARK_GAP"
:step="10"
@change="(cur: any) => updParam('WEB_BLOG_WATERMARK_GAP', cur.toString())"></el-input-number>
</bl-row>
</bl-row>
</div>
</el-form-item>
<el-form-item label="ICP备案号">
<el-input size="default" v-model="userParamForm.WEB_IPC_BEI_AN_HAO" @change="(cur: any) => updParam('WEB_IPC_BEI_AN_HAO', cur)"></el-input>
<div class="conf-tip">如果博客作为你的域名首页你可能需要配置 ICP 备案号该内容会跳转至中国大陆ICP/IP地址/域名信息备案管理系统</div>
</el-form-item>
<el-form-item label="首页自定义信息">
<el-input
size="default"
type="textarea"
:rows="5"
v-model="userParamForm.WEB_GONG_WANG_AN_BEI"
@change="(cur: any) => updParam('WEB_GONG_WANG_AN_BEI', cur)"></el-input>
<div class="conf-tip">自定义信息可填写 HTML 内容</div>
</el-form-item>
<el-form-item label="ICP备案号">
<el-input size="default" v-model="userParamForm.WEB_IPC_BEI_AN_HAO" @change="(cur: any) => updParam('WEB_IPC_BEI_AN_HAO', cur)"></el-input>
<div class="conf-tip">如果博客作为你的域名首页你可能需要配置 ICP 备案号该内容会跳转至中国大陆ICP/IP地址/域名信息备案管理系统</div>
<div class="conf-tip">首页底部的自定义信息可填写 HTML 内容也可在此自定义备案信息即跳转地址等信息</div>
</el-form-item>
<el-form-item label="外部链接">
@@ -98,18 +197,57 @@ const userParamForm = ref({
WEB_GONG_WANG_AN_BEI: '',
WEB_BLOG_URL_ERROR_TIP_SHOW: '',
WEB_BLOG_LINKS: '',
WEB_BLOG_SUBJECT_TITLE: false
WEB_BLOG_SUBJECT_TITLE: false,
WEB_BLOG_COLOR: '',
WEB_BLOG_SHOW_ARTICLE_NAME: true,
WEB_BLOG_WATERMARK_ENABLED: false,
WEB_BLOG_WATERMARK_CONTENT: '',
WEB_BLOG_WATERMARK_FONTSIZE: 15,
WEB_BLOG_WATERMARK_COLOR: '',
WEB_BLOG_WATERMARK_GAP: 100
})
const colors = ['rgb(136, 118, 87)', 'rgb(119, 150, 73)', 'rgb(128, 164, 146)', 'rgb(110, 155, 197)', 'rgb(97, 94, 168)', 'rgb(104, 104, 104)']
const changeBlogColor = (color: string) => {
if (!color) {
userParamForm.value.WEB_BLOG_COLOR = 'rgb(104, 104, 104)'
} else {
userParamForm.value.WEB_BLOG_COLOR = color
}
updParam('WEB_BLOG_COLOR', userParamForm.value.WEB_BLOG_COLOR)
}
const changeWatermarkColor = (color: string) => {
if (!color) {
userParamForm.value.WEB_BLOG_WATERMARK_COLOR = 'rgba(157, 157, 157, 0.2)'
} else {
userParamForm.value.WEB_BLOG_WATERMARK_COLOR = color
}
updParam('WEB_BLOG_WATERMARK_COLOR', userParamForm.value.WEB_BLOG_WATERMARK_COLOR)
}
/**
* 获取参数列表
*/
const getParamList = () => {
userParamListApi().then((resp) => {
userParamForm.value = { ...resp.data, ...{ WEB_BLOG_SUBJECT_TITLE: resp.data.WEB_BLOG_SUBJECT_TITLE === '1' } }
userParamForm.value = {
...resp.data,
...{
WEB_BLOG_SUBJECT_TITLE: resp.data.WEB_BLOG_SUBJECT_TITLE === '1',
WEB_BLOG_SHOW_ARTICLE_NAME: resp.data.WEB_BLOG_SHOW_ARTICLE_NAME === '1',
WEB_BLOG_WATERMARK_ENABLED: resp.data.WEB_BLOG_WATERMARK_ENABLED === '1',
WEB_BLOG_WATERMARK_FONTSIZE: Number(resp.data.WEB_BLOG_WATERMARK_FONTSIZE),
WEB_BLOG_WATERMARK_GAP: Number(resp.data.WEB_BLOG_WATERMARK_GAP)
}
}
})
}
/**
* 刷新参数
*/
const refreshParam = () => {
userParamRefreshApi().then((_) => {
Notify.success('', '刷新成功')
@@ -118,6 +256,12 @@ const refreshParam = () => {
})
}
/**
* 修改参数
*
* @param paramName 参数名
* @param paramValue 参数值
*/
const updParam = (paramName: string, paramValue: string) => {
userParamUpdApi({ paramName: paramName, paramValue: paramValue }).then((_resp) => {
userStore.getUserinfo()
@@ -130,6 +274,9 @@ const toBlog = () => {
openExtenal(url)
}
/**
* 获取连接配置模板
*/
const genWebLinksTemplate = () => {
if (isNotBlank(userParamForm.value.WEB_BLOG_LINKS)) {
Notify.info('你需要将内容清空后再生成模板', '提示')
@@ -165,4 +312,32 @@ defineExpose({ reload })
white-space: pre;
color: var(--bl-text-color-light);
}
.colors {
align-content: flex-start;
flex-wrap: wrap;
.el-color-picker--small {
margin: 0 10px 10px 0;
}
.color-item {
@include box(28px, 28px);
margin: 0 0 0 15px;
border-radius: 4px;
position: relative;
transition: transform 0.3s;
cursor: pointer;
text-align: center;
&:hover {
transform: scale(1.1);
}
}
}
.theme-color-picker {
z-index: 3001 !important;
margin: 0 10px 10px 0;
}
</style>

View File

@@ -69,4 +69,31 @@
font-style: italic;
}
}
.conf-watermark {
@include box(100%, auto);
color: var(--bl-text-color);
border: 1px solid var(--el-border-color);
background-color: var(--bl-bg-color);
border-radius: 4px;
padding: 20px;
margin-bottom: 20px;
.label {
min-width: 50px;
margin: 0 10px;
&:first-child {
margin-left: 0;
}
}
.el-input {
width: calc(100% - 80px);
}
.el-input-number {
width: 130px;
}
}
}

View File

@@ -5,7 +5,7 @@
</template>
<script setup lang="ts">
import { onMounted } from 'vue'
import { onMounted, type StyleHTMLAttributes } from 'vue'
import { useUserStore } from '@/stores/user'
import { ElConfigProvider } from 'element-plus'
import { isNotBlank } from './assets/utils/obj'
@@ -15,6 +15,9 @@ const userStore = useUserStore()
onMounted(async () => {
await userStore.getUserinfoOpen()
initCustomTheme()
console.log(userStore.userParams.WEB_BLOG_SHOW_ARTICLE_NAME);
// 优先使用后台配置的博客名称, 否则使用默认
if (isNotBlank(userStore.userParams.WEB_LOGO_NAME)) {
@@ -32,4 +35,42 @@ onMounted(async () => {
document.getElementsByTagName('head')[0].appendChild(link)
}
})
const THEME_STYLE_TAG_ID = 'blossom-blog-theme-css'
/**
* 初始化样式
*/
const initCustomTheme = () => {
const rgb = userStore.userParams.WEB_BLOG_COLOR
console.log(rgb)
if (!rgb.toLowerCase().startsWith('rgb(')) {
return
}
const prefix = rgb.substring(4, rgb.length - 1)
let text = `:root {
--el-color-primary: ${rgb};
--el-color-primary-dark: ${rgb};
--el-color-primary-dark-2: rgba(${prefix}, 0.8);
--el-color-primary-light-1: rgba(${prefix}, 0.9);
--el-color-primary-light-2: rgba(${prefix}, 0.8);
--el-color-primary-light-3: rgba(${prefix}, 0.7);
--el-color-primary-light-4: rgba(${prefix}, 0.6);
--el-color-primary-light-5: rgba(${prefix}, 0.5);
--el-color-primary-light-6: rgba(${prefix}, 0.4);
--el-color-primary-light-7: rgba(${prefix}, 0.3);
--el-color-primary-light-8: rgba(${prefix}, 0.2);
--el-color-primary-light-9: rgba(${prefix}, 0.1);
}`
let themeStyleTag = document.createElement('style') as unknown as StyleHTMLAttributes
themeStyleTag.type = 'text/css'
themeStyleTag.id = THEME_STYLE_TAG_ID
themeStyleTag.innerHTML = text
document
.getElementsByTagName('head')
.item(0)!
.appendChild(themeStyleTag as Node)
// }
}
</script>

View File

@@ -46,7 +46,14 @@ const DEFAULT_USER_INFO = {
WEB_GONG_WANG_AN_BEI: '',
WEB_BLOG_URL_ERROR_TIP_SHOW: 1,
WEB_BLOG_LINKS: '',
WEB_BLOG_SUBJECT_TITLE: '1'
WEB_BLOG_SUBJECT_TITLE: '1',
WEB_BLOG_SHOW_ARTICLE_NAME: '1',
WEB_BLOG_COLOR: 'rgb(104, 104, 104)',
WEB_BLOG_WATERMARK_ENABLED: '0',
WEB_BLOG_WATERMARK_CONTENT: '',
WEB_BLOG_WATERMARK_FONTSIZE: 15,
WEB_BLOG_WATERMARK_COLOR: '',
WEB_BLOG_WATERMARK_GAP: 100
}
}

View File

@@ -50,14 +50,24 @@
</div>
<div class="doc-content-container" ref="PreviewRef" :style="{ fontSize: getFontSize() }">
<div class="article-name">{{ article.name }}</div>
<div class="bl-preview" :style="{ fontSize: getFontSize() }" v-html="article.html"></div>
<div class="article-name" v-if="userStore.userParams.WEB_BLOG_SHOW_ARTICLE_NAME === '1'">{{ article.name }}</div>
<el-watermark
:font="{
color: userStore.userParams.WEB_BLOG_WATERMARK_COLOR,
fontSize: userStore.userParams.WEB_BLOG_WATERMARK_FONTSIZE,
textBaseline: 'hanging'
}"
:content="article.id > 0 && userStore.userParams.WEB_BLOG_WATERMARK_ENABLED === '1' ? userStore.userParams.WEB_BLOG_WATERMARK_CONTENT : ''"
:gap="[userStore.userParams.WEB_BLOG_WATERMARK_GAP, userStore.userParams.WEB_BLOG_WATERMARK_GAP]">
<div class="bl-preview" :style="{ fontSize: getFontSize() }" v-html="article.html"></div>
</el-watermark>
</div>
<div class="toc-container" :style="tocStyle">
<div class="viewer-toc">
<div v-if="article.id != 0">
<div class="toc-subtitle" style="font-size: 15px">{{ article.name }}</div>
<div class="toc-subtitle" style="font-size: 15px">{{ article.name }}</div>
<div class="toc-subtitle">
<span class="iconbl bl-pen-line"></span> {{ article.words }} | <span class="iconbl bl-read-line"></span> {{ article.uv }} |
<span class="iconbl bl-like-line"></span> {{ article.likes }}

View File

@@ -17,6 +17,7 @@
border-bottom: 1px solid #e5e5e5;
text-align: left;
position: relative;
word-break: break-all;
font-size: 2em;
}

View File

@@ -25,9 +25,9 @@
}
.toc-subtitle {
width: 100%;
@include flex(row, flex-start, center);
@include font(12px);
width: 100%;
color: #ababab;
overflow: hidden;
white-space: nowrap;
@@ -53,6 +53,7 @@
&:hover {
font-weight: bold;
color: var(--el-color-primary);
}
}