mirror of
https://gitee.com/blossom-editor/blossom.git
synced 2025-12-07 17:28:27 +08:00
Merge branch 'blossom-editor:dev' into dev
This commit is contained in:
commit
ab4b4a25b7
@ -56,7 +56,8 @@ docker compose -f docker/compose/blossom-mysql8.yaml up -d
|
|||||||
Join QQ group, communicate with us and discuss problems.
|
Join QQ group, communicate with us and discuss problems.
|
||||||
|
|
||||||
- Group 1:522359970 (It is full)
|
- Group 1:522359970 (It is full)
|
||||||
- Group 2:921906098
|
- Group 2:921906098 (It is full)
|
||||||
|
- Group 3:749721525
|
||||||
|
|
||||||
You can also contact with us by the issue , We will definitely try our best to reply to you.
|
You can also contact with us by the issue , We will definitely try our best to reply to you.
|
||||||
We also welcome everyone to participate in the development and discussion of Blossom.
|
We also welcome everyone to participate in the development and discussion of Blossom.
|
||||||
@ -64,6 +65,7 @@ We also welcome everyone to participate in the development and discussion of Blo
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./doc/imgs/qq1.png" height="400">
|
<img src="./doc/imgs/qq1.png" height="400">
|
||||||
<img src="./doc/imgs/qq2.png" height="400">
|
<img src="./doc/imgs/qq2.png" height="400">
|
||||||
|
<img src="./doc/imgs/qq3.png" height="400">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
# 🤝 Sponsor Blossom
|
# 🤝 Sponsor Blossom
|
||||||
|
|||||||
@ -58,11 +58,13 @@ docker compose -f docker/compose/blossom-mysql8.yaml up -d
|
|||||||
加入群聊进行沟通,反馈问题。
|
加入群聊进行沟通,反馈问题。
|
||||||
|
|
||||||
- 1 群:522359970 (即将满)
|
- 1 群:522359970 (即将满)
|
||||||
- 2 群:921906098
|
- 2 群:921906098 (即将满)
|
||||||
|
- 3 群:749721525
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./doc/imgs/qq1.png" height="400">
|
<img src="./doc/imgs/qq1.png" height="400">
|
||||||
<img src="./doc/imgs/qq2.png" height="400">
|
<img src="./doc/imgs/qq2.png" height="400">
|
||||||
|
<img src="./doc/imgs/qq3.png" height="400">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
# 🤝 赞助 Blossom
|
# 🤝 赞助 Blossom
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import com.blossom.backend.server.utils.ArticleUtil;
|
|||||||
import com.blossom.common.base.enums.YesNo;
|
import com.blossom.common.base.enums.YesNo;
|
||||||
import com.blossom.common.base.exception.XzException500;
|
import com.blossom.common.base.exception.XzException500;
|
||||||
import com.blossom.common.base.util.DateUtils;
|
import com.blossom.common.base.util.DateUtils;
|
||||||
|
import com.blossom.common.base.util.PrimaryKeyUtil;
|
||||||
import com.blossom.common.base.util.SortUtil;
|
import com.blossom.common.base.util.SortUtil;
|
||||||
import com.blossom.common.iaas.IaasProperties;
|
import com.blossom.common.iaas.IaasProperties;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
@ -37,10 +38,7 @@ import org.springframework.stereotype.Component;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -164,12 +162,24 @@ public class ArticleBackupService {
|
|||||||
int idLen = String.valueOf(allContents.stream()
|
int idLen = String.valueOf(allContents.stream()
|
||||||
.map(ArticleEntity::getId).max(SortUtil.longSort).orElse((1L))).length();
|
.map(ArticleEntity::getId).max(SortUtil.longSort).orElse((1L))).length();
|
||||||
|
|
||||||
|
// 记录已经保存的文件
|
||||||
|
Set<String> exists = new HashSet<>();
|
||||||
|
|
||||||
backLogs.add("┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ↓↓ 文章列表 ↓↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
backLogs.add("┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ↓↓ 文章列表 ↓↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||||
backLogs.add("┃ 排序 [ID] [版本] [时间] 文章路径");
|
backLogs.add("┃ 排序 [ID] [版本] [时间] 文章路径");
|
||||||
backLogs.add("┠────────────────────────────────────────────────────────────────────────────");
|
backLogs.add("┠────────────────────────────────────────────────────────────────────────────");
|
||||||
for (DocTreeRes article : articles) {
|
for (DocTreeRes article : articles) {
|
||||||
|
String name = clearPath(article.getN());
|
||||||
|
// 处理文章或文件夹重名的情况
|
||||||
|
if (exists.contains(name)) {
|
||||||
|
name = name + "_" + article.getI();
|
||||||
|
if (exists.contains(name)) {
|
||||||
|
name = name + "_" + PrimaryKeyUtil.nextId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exists.add(name);
|
||||||
// 创建文章 file
|
// 创建文章 file
|
||||||
File file = new File(backupFile.getRootPath() + "/" + clearPath(article.getN()) + getArticleSuffix(type));
|
File file = new File(backupFile.getRootPath() + "/" + name + getArticleSuffix(type));
|
||||||
// 导出的文章正文
|
// 导出的文章正文
|
||||||
ArticleEntity articleDetail = markdowns.get(article.getI());
|
ArticleEntity articleDetail = markdowns.get(article.getI());
|
||||||
if (articleDetail == null) {
|
if (articleDetail == null) {
|
||||||
@ -305,7 +315,8 @@ public class ArticleBackupService {
|
|||||||
req.setArticleId(articleId);
|
req.setArticleId(articleId);
|
||||||
List<DocTreeRes> docs = docService.listTree(req);
|
List<DocTreeRes> docs = docService.listTree(req);
|
||||||
List<DocTreeRes> articles = new ArrayList<>();
|
List<DocTreeRes> articles = new ArrayList<>();
|
||||||
findArticle("", docs, articles);
|
Set<String> exists = new HashSet<>();
|
||||||
|
findArticle("", docs, articles, exists);
|
||||||
return articles;
|
return articles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,15 +326,20 @@ public class ArticleBackupService {
|
|||||||
* @param prefix 上级文件夹名称
|
* @param prefix 上级文件夹名称
|
||||||
* @param docs 文章树状列表
|
* @param docs 文章树状列表
|
||||||
* @param articles 拼接结果列表, 虽然是 DocTreeRes 对象, 但不是树状结构
|
* @param articles 拼接结果列表, 虽然是 DocTreeRes 对象, 但不是树状结构
|
||||||
|
* @param exists 判断文件夹是否重名
|
||||||
*/
|
*/
|
||||||
private void findArticle(String prefix, List<DocTreeRes> docs, List<DocTreeRes> articles) {
|
private void findArticle(String prefix, List<DocTreeRes> docs, List<DocTreeRes> articles, Set<String> exists) {
|
||||||
if (CollUtil.isEmpty(docs)) {
|
if (CollUtil.isEmpty(docs)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (DocTreeRes doc : docs) {
|
for (DocTreeRes doc : docs) {
|
||||||
|
if (exists.contains(doc.getN())) {
|
||||||
|
doc.setN(doc.getN() + "_" + doc.getI());
|
||||||
|
}
|
||||||
|
exists.add(doc.getN());
|
||||||
doc.setN(prefix + "/" + doc.getN());
|
doc.setN(prefix + "/" + doc.getN());
|
||||||
if (CollUtil.isNotEmpty(doc.getChildren())) {
|
if (CollUtil.isNotEmpty(doc.getChildren())) {
|
||||||
findArticle(doc.getN(), doc.getChildren(), articles);
|
findArticle(doc.getN(), doc.getChildren(), articles, exists);
|
||||||
}
|
}
|
||||||
if (doc.getTy().equals(DocTypeEnum.A.getType())) {
|
if (doc.getTy().equals(DocTypeEnum.A.getType())) {
|
||||||
articles.add(doc);
|
articles.add(doc);
|
||||||
@ -439,11 +455,13 @@ public class ArticleBackupService {
|
|||||||
private String userId;
|
private String userId;
|
||||||
/**
|
/**
|
||||||
* 备份日期 YYYYMMDD
|
* 备份日期 YYYYMMDD
|
||||||
|
*
|
||||||
* @mock 20230101
|
* @mock 20230101
|
||||||
*/
|
*/
|
||||||
private String date;
|
private String date;
|
||||||
/**
|
/**
|
||||||
* 备份时间 HHMMSS
|
* 备份时间 HHMMSS
|
||||||
|
*
|
||||||
* @mock 123001
|
* @mock 123001
|
||||||
*/
|
*/
|
||||||
private String time;
|
private String time;
|
||||||
@ -459,7 +477,6 @@ public class ArticleBackupService {
|
|||||||
* 备份包路径
|
* 备份包路径
|
||||||
*/
|
*/
|
||||||
private String path;
|
private String path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 本地文件
|
* 本地文件
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import com.blossom.common.base.exception.XzException400;
|
|||||||
import com.blossom.common.base.exception.XzException404;
|
import com.blossom.common.base.exception.XzException404;
|
||||||
import com.blossom.common.base.exception.XzException500;
|
import com.blossom.common.base.exception.XzException500;
|
||||||
import com.blossom.common.base.util.DateUtils;
|
import com.blossom.common.base.util.DateUtils;
|
||||||
|
import com.blossom.common.base.util.PrimaryKeyUtil;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -178,6 +179,7 @@ public class FolderService extends ServiceImpl<FolderMapper, FolderEntity> {
|
|||||||
folder.setStorePath(parentFolder.getStorePath());
|
folder.setStorePath(parentFolder.getStorePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
folder.setId(PrimaryKeyUtil.nextId());
|
||||||
baseMapper.insert(folder);
|
baseMapper.insert(folder);
|
||||||
return folder;
|
return folder;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,6 @@ public class FolderEntity extends AbstractPOJO implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* id
|
* id
|
||||||
*/
|
*/
|
||||||
@TableId(type = IdType.AUTO)
|
|
||||||
private Long id;
|
private Long id;
|
||||||
/**
|
/**
|
||||||
* 父id
|
* 父id
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package com.blossom.backend.server.utils;
|
package com.blossom.backend.server.utils;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.blossom.backend.server.article.draft.pojo.ArticleEntity;
|
import com.blossom.backend.server.article.draft.pojo.ArticleEntity;
|
||||||
import com.blossom.backend.server.doc.DocTypeEnum;
|
import com.blossom.backend.server.doc.DocTypeEnum;
|
||||||
@ -10,11 +9,7 @@ import com.blossom.backend.server.folder.pojo.FolderEntity;
|
|||||||
import com.blossom.common.base.enums.YesNo;
|
import com.blossom.common.base.enums.YesNo;
|
||||||
import com.blossom.common.base.util.SortUtil;
|
import com.blossom.common.base.util.SortUtil;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,14 +32,17 @@ public class DocUtil {
|
|||||||
* @return 树状菜单对象
|
* @return 树状菜单对象
|
||||||
*/
|
*/
|
||||||
public static List<DocTreeRes> treeWrap(List<DocTreeRes> list, boolean priorityType) {
|
public static List<DocTreeRes> treeWrap(List<DocTreeRes> list, boolean priorityType) {
|
||||||
// 将原始列表进行分组, 并排序每个分组的列表
|
// 将原始列表进行分组, 并排序每个分组的列表
|
||||||
Map<Long, List<DocTreeRes>> pidMapping = list.stream().collect(
|
Map<Long, List<DocTreeRes>> pidMapping = list.stream().collect(
|
||||||
Collectors.groupingBy(DocTreeRes::getP, HashMap::new,
|
Collectors.groupingBy(DocTreeRes::getP, HashMap::new,
|
||||||
Collectors.collectingAndThen(Collectors.toList(),
|
Collectors.collectingAndThen(Collectors.toList(),
|
||||||
item -> item.stream().sorted(Comparator.comparingInt(DocTreeRes::getS)).collect(Collectors.toList()))));
|
item -> item.stream().sorted(Comparator.comparingInt(DocTreeRes::getS)).collect(Collectors.toList()))));
|
||||||
// 免递归方式赋值子菜单
|
// 免递归方式赋值子菜单
|
||||||
list.parallelStream().forEach(item -> {
|
list.parallelStream().forEach(item -> {
|
||||||
if (!CollectionUtil.isEmpty(pidMapping.get(item.getI()))){
|
if(item.getTy().equals(DocTypeEnum.A.getType())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!CollUtil.isEmpty(pidMapping.get(item.getI()))){
|
||||||
item.setChildren(pidMapping.get(item.getI()));
|
item.setChildren(pidMapping.get(item.getI()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -29,6 +29,11 @@ export const cwTheme: any = {
|
|||||||
backgroundColor: 'var(--bl-editor-gutters-bg-color)',
|
backgroundColor: 'var(--bl-editor-gutters-bg-color)',
|
||||||
color: 'var(--el-color-primary)'
|
color: 'var(--el-color-primary)'
|
||||||
},
|
},
|
||||||
|
'.cm-panel.cm-search [name=close]': {
|
||||||
|
fontSize: '20px !important',
|
||||||
|
marginRight: '10px',
|
||||||
|
color: 'var(--el-color-primary)'
|
||||||
|
},
|
||||||
'.cm-panels-top': {
|
'.cm-panels-top': {
|
||||||
'z-index': '999',
|
'z-index': '999',
|
||||||
borderColor: 'var(--el-border-color)'
|
borderColor: 'var(--el-border-color)'
|
||||||
|
|||||||
@ -47,7 +47,7 @@ export const keymaps = {
|
|||||||
// https://codemirror.net/docs/ref/#commands.defaultKeymap
|
// https://codemirror.net/docs/ref/#commands.defaultKeymap
|
||||||
selectLine: isMac ? '⌃ L' : 'Alt + L',
|
selectLine: isMac ? '⌃ L' : 'Alt + L',
|
||||||
// https://codemirror.net/docs/ref/#search
|
// https://codemirror.net/docs/ref/#search
|
||||||
toLine: isMac ? '⌥ ⌘ G' : 'Alt + G',
|
toLine: isMac ? '⌥ ⌘ G' : 'Ctrl + Alt + G',
|
||||||
moveLineUp: isMac ? '⌥ ↑' : 'Alt + ↑',
|
moveLineUp: isMac ? '⌥ ↑' : 'Alt + ↑',
|
||||||
moveLineDown: isMac ? '⌥ ↓' : 'Alt + ↓',
|
moveLineDown: isMac ? '⌥ ↓' : 'Alt + ↓',
|
||||||
copyLineUp: isMac ? '⌥ ⇧ ↑' : 'Shift + Alt + ↑',
|
copyLineUp: isMac ? '⌥ ⇧ ↑' : 'Shift + Alt + ↑',
|
||||||
|
|||||||
@ -104,15 +104,14 @@ export const renderHeading = (text: string, level: number, raw: string) => {
|
|||||||
if (dom) {
|
if (dom) {
|
||||||
id += dom.body.innerText
|
id += dom.body.innerText
|
||||||
} else {
|
} else {
|
||||||
id += text
|
id += raw
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
id += text
|
id += raw
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
id += text
|
id += raw
|
||||||
}
|
}
|
||||||
|
|
||||||
return `<h${level} id="${id}">${text}</h${level}>`
|
return `<h${level} id="${id}">${text}</h${level}>`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -57,7 +57,7 @@
|
|||||||
<bl-col just="center" height="fit-content">
|
<bl-col just="center" height="fit-content">
|
||||||
<div class="blod" style="margin: 80px 0 10px 0">开发者列表</div>
|
<div class="blod" style="margin: 80px 0 10px 0">开发者列表</div>
|
||||||
<div class="developer">
|
<div class="developer">
|
||||||
<bl-row class="item" v-for="dever in developer" width="250px" height="70px">
|
<bl-row class="item" v-for="dever in developer" width="250px" height="70px" @click="toView(dever.github)">
|
||||||
<div>
|
<div>
|
||||||
<img :src="dever.avatar" />
|
<img :src="dever.avatar" />
|
||||||
</div>
|
</div>
|
||||||
@ -86,12 +86,15 @@
|
|||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</bl-row>
|
</bl-row>
|
||||||
|
|
||||||
|
<bl-row just="center" class="statement"> 本应用完全免费并开源全部源代码,如果你从付费渠道获取本应用,谨防上当受骗。 </bl-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import CONFIG from '@renderer/assets/constants/system'
|
import CONFIG from '@renderer/assets/constants/system'
|
||||||
import { openExtenal } from '@renderer/assets/utils/electron'
|
import { openExtenal } from '@renderer/assets/utils/electron'
|
||||||
|
import { toView } from '@renderer/assets/utils/util'
|
||||||
import { useUserStore } from '@renderer/stores/user'
|
import { useUserStore } from '@renderer/stores/user'
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
@ -105,8 +108,15 @@ const references = [
|
|||||||
const developer = [
|
const developer = [
|
||||||
{
|
{
|
||||||
name: '小贼贼子',
|
name: '小贼贼子',
|
||||||
desc: '一个后端程序员,也是一个半吊子前端。',
|
desc: '创建者',
|
||||||
|
github: 'https://github.com/xiaozzzi',
|
||||||
avatar: 'https://www.wangyunf.com/bl/pic/home/bl/img/U1/head/luban.png'
|
avatar: 'https://www.wangyunf.com/bl/pic/home/bl/img/U1/head/luban.png'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Tianjiu',
|
||||||
|
desc: '项目成员、英文译者',
|
||||||
|
github: 'https://github.com/T1anjiu',
|
||||||
|
avatar: 'https://www.wangyunf.com/bl/pic/home/bl/img/U1/pic/blosteam/T1anjiu.jpg'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -181,10 +191,11 @@ const getServerVersion = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.developer {
|
.developer {
|
||||||
width: 630px;
|
|
||||||
@include flex(row, flex-start, flex-start);
|
@include flex(row, flex-start, flex-start);
|
||||||
|
width: 630px;
|
||||||
align-content: flex-start;
|
align-content: flex-start;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
background-color: var(--bl-bg-color);
|
background-color: var(--bl-bg-color);
|
||||||
@ -199,6 +210,7 @@ const getServerVersion = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
|
font-size: 14px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,6 +220,7 @@ const getServerVersion = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.reference {
|
.reference {
|
||||||
width: 630px;
|
width: 630px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@ -217,5 +230,11 @@ const getServerVersion = () => {
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
color: #8b8b8b;
|
color: #8b8b8b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.statement {
|
||||||
|
font-size: 13px;
|
||||||
|
margin-top: 20px;
|
||||||
|
color: var(--bl-text-color-light);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
BIN
doc/imgs/qq3.png
Normal file
BIN
doc/imgs/qq3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 112 KiB |
Loading…
x
Reference in New Issue
Block a user