mirror of
https://gitee.com/blossom-editor/blossom.git
synced 2025-12-06 08:48:29 +08:00
pref: 专题收藏快捷操作与样式优化
This commit is contained in:
parent
4c4fcd3a1d
commit
67cb162184
@ -7,9 +7,9 @@ import com.blossom.backend.base.auth.annotation.AuthIgnore;
|
||||
import com.blossom.backend.config.BlConstants;
|
||||
import com.blossom.backend.server.article.draft.pojo.ArticleUpdTagReq;
|
||||
import com.blossom.backend.server.doc.DocService;
|
||||
import com.blossom.backend.server.doc.DocSortChecker;
|
||||
import com.blossom.backend.server.folder.pojo.*;
|
||||
import com.blossom.backend.server.utils.DocUtil;
|
||||
import com.blossom.common.base.enums.YesNo;
|
||||
import com.blossom.common.base.exception.XzException404;
|
||||
import com.blossom.common.base.pojo.DelReq;
|
||||
import com.blossom.common.base.pojo.R;
|
||||
@ -34,7 +34,6 @@ import java.util.Objects;
|
||||
public class FolderController {
|
||||
private final FolderService baseService;
|
||||
private final DocService docService;
|
||||
private final DocSortChecker docSortChecker;
|
||||
|
||||
/**
|
||||
* 查询专题列表 [OP]
|
||||
@ -47,21 +46,24 @@ public class FolderController {
|
||||
if (userId == null) {
|
||||
return R.ok(new ArrayList<>());
|
||||
}
|
||||
return R.ok(baseService.subjects(userId, null));
|
||||
return R.ok(baseService.subjects(userId, YesNo.YES));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询专题列表
|
||||
*
|
||||
* @param starStatus 公开状态,
|
||||
*/
|
||||
@GetMapping("/subjects")
|
||||
public R<List<FolderSubjectRes>> listSubject(@RequestParam("starStatus") Integer starStatus) {
|
||||
return R.ok(baseService.subjects(AuthContext.getUserId(), starStatus));
|
||||
return R.ok(baseService.subjects(AuthContext.getUserId(), YesNo.getValue(starStatus)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 星标目录
|
||||
* 星标文件夹
|
||||
*
|
||||
* @param req 目录对象
|
||||
* @param req 目录文件夹
|
||||
* @since 1.14.0
|
||||
*/
|
||||
@PostMapping("/star")
|
||||
public R<Long> star(@Validated @RequestBody FolderStarReq req) {
|
||||
|
||||
@ -12,6 +12,7 @@ import com.blossom.backend.server.folder.pojo.FolderSubjectRes;
|
||||
import com.blossom.backend.server.picture.PictureMapper;
|
||||
import com.blossom.backend.server.picture.pojo.PictureEntity;
|
||||
import com.blossom.backend.server.utils.DocUtil;
|
||||
import com.blossom.common.base.enums.YesNo;
|
||||
import com.blossom.common.base.exception.XzException400;
|
||||
import com.blossom.common.base.exception.XzException404;
|
||||
import com.blossom.common.base.exception.XzException500;
|
||||
@ -19,10 +20,10 @@ import com.blossom.common.base.util.DateUtils;
|
||||
import com.blossom.common.base.util.PrimaryKeyUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@ -51,17 +52,16 @@ public class FolderService extends ServiceImpl<FolderMapper, FolderEntity> {
|
||||
* <p>4. 相同专题的所有文件夹ID归为一组.
|
||||
* <p>5. 通过文件夹ID获取到专题下的所有文章, 从而统计文章的总字数, 修改时间, 创建时间等.
|
||||
* <p>6. 如果文章包含 TOC 标签, 则该文章为专题的目录, 专题的默认跳转会跳转至该目录
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param starStatus 公开状态
|
||||
*/
|
||||
public List<FolderSubjectRes> subjects(Long userId, @Nullable Integer starStatus) {
|
||||
public List<FolderSubjectRes> subjects(Long userId, @NotNull YesNo starStatus) {
|
||||
// 1. 查询所有专题
|
||||
FolderEntity where = new FolderEntity();
|
||||
where.setTags(TagEnum.subject.name());
|
||||
where.setUserId(userId);
|
||||
if (null != starStatus && (starStatus.equals(1) || starStatus.equals(0))) {
|
||||
where.setStarStatus(starStatus);
|
||||
} else {
|
||||
where.setStarStatus(0);
|
||||
}
|
||||
where.setStarStatus(starStatus.getValue());
|
||||
List<FolderEntity> allOpenSubject = baseMapper.listAll(where);
|
||||
if (CollUtil.isEmpty(allOpenSubject)) {
|
||||
return new ArrayList<>();
|
||||
@ -204,9 +204,6 @@ public class FolderService extends ServiceImpl<FolderMapper, FolderEntity> {
|
||||
*/
|
||||
private void updateStorePath(FolderEntity folder) {
|
||||
// 处理文件夹的存储地址
|
||||
XzException404.throwBy(folder.getId() == null, "ID不得为空");
|
||||
XzException400.throwBy(folder.getId().equals(folder.getPid()), "上级文件夹不能是自己");
|
||||
// 如果
|
||||
if (StrUtil.isNotBlank(folder.getStorePath())) {
|
||||
final FolderEntity oldFolder = selectById(folder.getId());
|
||||
// 获取所有子文件夹
|
||||
|
||||
@ -109,19 +109,4 @@ public class FolderEntity extends AbstractPOJO implements Serializable {
|
||||
private List<Long> pids;
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Long.hashCode(this.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof FolderEntity) {
|
||||
return this.id.equals(((FolderEntity)obj).getId());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -148,7 +148,7 @@ public class DocUtil {
|
||||
tree.setS(folder.getSort());
|
||||
tree.setN(folder.getName());
|
||||
tree.setSp(folder.getStorePath());
|
||||
tree.setStar(0);
|
||||
tree.setStar(folder.getStarStatus());
|
||||
tree.setTy(folder.getType());
|
||||
tree.setIcon(folder.getIcon());
|
||||
if (StrUtil.isBlank(folder.getTags())) {
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
fontWeight: props.weight
|
||||
}">
|
||||
<!-- {{ !!slots.default }}| -->
|
||||
<span v-if="props.icon" :class="['tag-iconbl iconbl', props.icon, !!slots.default ? 'tag-icon-margin' : '']" />
|
||||
<span v-if="props.icon" :class="['tag-iconbl iconbl', props.icon]" />
|
||||
<span class="tag-content">
|
||||
<slot />
|
||||
</span>
|
||||
@ -16,10 +16,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useSlots } from 'vue'
|
||||
|
||||
const slots = useSlots()
|
||||
|
||||
const props = defineProps({
|
||||
/**
|
||||
* background-color
|
||||
@ -54,7 +50,7 @@ const props = defineProps({
|
||||
<style scoped lang="scss">
|
||||
.tag-root {
|
||||
@include flex(row, center, center);
|
||||
@include themeShadow(2px 2px 3px 0 #bbbbbb, 1px 2px 3px #0F0F0F);
|
||||
@include themeShadow(2px 1px 3px 0 #bbbbbb, 1px 1px 3px #0f0f0f);
|
||||
border-radius: 4px;
|
||||
padding: 1px 4px;
|
||||
margin: 3px;
|
||||
@ -67,10 +63,6 @@ const props = defineProps({
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tag-icon-margin {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.tag-content {
|
||||
line-height: 12px;
|
||||
}
|
||||
|
||||
@ -225,6 +225,7 @@ import { Document } from '@element-plus/icons-vue'
|
||||
import { provideKeyDocTree, getCDocsByPid, getDocById } from '@renderer/views/doc/doc'
|
||||
import { useUserStore } from '@renderer/stores/user'
|
||||
import {
|
||||
folderStarApi,
|
||||
folderInfoApi,
|
||||
folderAddApi,
|
||||
folderUpdApi,
|
||||
@ -239,7 +240,6 @@ import {
|
||||
import { isNotBlank, isNull } from '@renderer/assets/utils/obj'
|
||||
import { openExtenal, openNewIconWindow } from '@renderer/assets/utils/electron'
|
||||
import Notify from '@renderer/scripts/notify'
|
||||
import {folderStarApi} from "../../api/blossom";
|
||||
|
||||
//#region --------------------------------------------------< 基本信息 >--------------------------------------------------
|
||||
const userStore = useUserStore()
|
||||
|
||||
@ -65,9 +65,7 @@
|
||||
<template #default="{ node, data }">
|
||||
<div class="menu-item-wrapper" @click.right="handleClickRightMenu($event, data)">
|
||||
<div :class="[viewStyle.isShowSubjectStyle ? (data.t?.includes('subject') ? 'subject-title' : 'doc-title') : 'doc-title']">
|
||||
<bl-tag v-if="isShowSort" class="sort" :bgColor="getColor(node)">
|
||||
{{ data.s }}
|
||||
</bl-tag>
|
||||
<div v-if="isShowSort" class="sort-tag" :style="{ backgroundColor: getColor(node) }">{{ data.s }}</div>
|
||||
<div class="doc-name">
|
||||
<img class="menu-icon-img" v-if="isShowImg(data, viewStyle)" :src="data.icon" />
|
||||
<svg v-else-if="isShowSvg(data, viewStyle)" class="icon menu-icon" aria-hidden="true">
|
||||
@ -83,7 +81,7 @@
|
||||
<div v-else class="name-wrapper" :style="{ maxWidth: isNotBlank(data.icon) ? 'calc(100% - 25px)' : '100%' }">
|
||||
{{ data.n }}
|
||||
</div>
|
||||
<bl-tag v-for="tag in tags(data, viewStyle)" style="margin-top: 5px" :bg-color="tag.bgColor" :icon="tag.icon">
|
||||
<bl-tag v-for="tag in tags(data, viewStyle)" style="margin-top: 4px" :bg-color="tag.bgColor" :color="tag.color" :icon="tag.icon">
|
||||
{{ tag.content }}
|
||||
</bl-tag>
|
||||
</div>
|
||||
@ -124,8 +122,8 @@
|
||||
<div class="tree-menu-level2" :style="rMenuLevel2">
|
||||
<div v-if="curDoc.o === 0" @click="open(1)"><span class="iconbl bl-a-cloudupload-line"></span>公开</div>
|
||||
<div v-if="curDoc.o === 1" @click="open(0)"><span class="iconbl bl-a-clouddownload-line"></span>取消公开</div>
|
||||
<div v-if="curDoc.star === 0 && curDoc.ty === 3" @click="star(1)"><span class="iconbl bl-star-fill"></span>收藏</div>
|
||||
<div v-if="curDoc.star === 1 && curDoc.ty === 3" @click="star(0)"><span class="iconbl bl-star-line"></span>取消收藏</div>
|
||||
<div v-if="curDoc.star === 0" @click="star(1)"><span class="iconbl bl-star-fill"></span>收藏</div>
|
||||
<div v-if="curDoc.star === 1" @click="star(0)"><span class="iconbl bl-star-line"></span>取消收藏</div>
|
||||
<div v-if="curDoc.ty === 3 && !curDoc.t.includes('toc')" @click="addArticleTag('toc')">
|
||||
<span class="iconbl bl-list-ordered"></span>设为专题目录
|
||||
</div>
|
||||
@ -272,6 +270,7 @@ import {
|
||||
articleDownloadHtmlApi,
|
||||
articleOpenApi,
|
||||
articleStarApi,
|
||||
folderStarApi,
|
||||
folderAddApi,
|
||||
folderUpdTagApi,
|
||||
folderDelApi,
|
||||
@ -930,10 +929,17 @@ const open = (openStatus: 0 | 1) => {
|
||||
* 收藏/取消收藏
|
||||
*/
|
||||
const star = (starStatus: 0 | 1) => {
|
||||
articleStarApi({ id: curDoc.value.i, starStatus: starStatus }).then(() => {
|
||||
curDoc.value.star = starStatus
|
||||
Notify.success(starStatus === 0 ? '取消 Star 成功' : 'Star 成功')
|
||||
})
|
||||
if (curDoc.value.ty === 3) {
|
||||
articleStarApi({ id: curDoc.value.i, starStatus: starStatus }).then(() => {
|
||||
curDoc.value.star = starStatus
|
||||
Notify.success(starStatus === 0 ? '取消 Star 成功' : 'Star 成功')
|
||||
})
|
||||
} else if (curDoc.value.ty === 1) {
|
||||
folderStarApi({ id: curDoc.value.i, starStatus: starStatus }).then(() => {
|
||||
curDoc.value.star = starStatus
|
||||
Notify.success(starStatus === 0 ? '取消文件夹 Star 成功' : '文件夹 Star 成功')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -31,14 +31,6 @@ $icon-size: 17px;
|
||||
line-height: 23px;
|
||||
}
|
||||
}
|
||||
|
||||
.sort {
|
||||
position: absolute;
|
||||
padding: 0 2px;
|
||||
right: 2px;
|
||||
top: 2px;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
|
||||
// 专题样式, 包括边框和文字样式
|
||||
@ -76,11 +68,18 @@ $icon-size: 17px;
|
||||
min-width: calc(100% - 25px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sort {
|
||||
position: absolute;
|
||||
right: 1px;
|
||||
}
|
||||
.sort-tag {
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 0 2px;
|
||||
margin-top: 3px;
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: 2px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
// 在左侧显示
|
||||
|
||||
@ -27,6 +27,9 @@ export const tags = (doc: DocTree, viewStyle: { isShowArticleTocTag: boolean; is
|
||||
icons.unshift({ bgColor: 'var(--bl-tag-color-open)', icon: 'bl-cloud-line' })
|
||||
}
|
||||
}
|
||||
if (doc.ty === 1 && doc.star === 1) {
|
||||
icons.unshift({ bgColor: 'rgb(220 192 36)', color: '#6a5b00', icon: 'bl-star-line' })
|
||||
}
|
||||
return icons
|
||||
}
|
||||
|
||||
@ -35,14 +38,16 @@ export const tags = (doc: DocTree, viewStyle: { isShowArticleTocTag: boolean; is
|
||||
*/
|
||||
export const tagLins = (doc: DocTree) => {
|
||||
let lines: string[] = []
|
||||
if (doc.star === 1) {
|
||||
lines.push('star-line')
|
||||
}
|
||||
if (doc.o === 1 && doc.ty === 3) {
|
||||
lines.push('open-line')
|
||||
}
|
||||
if (doc.vd === 1) {
|
||||
lines.push('sync-line')
|
||||
if (doc.ty === 3) {
|
||||
if (doc.star === 1) {
|
||||
lines.push('star-line')
|
||||
}
|
||||
if (doc.o === 1 && doc.ty === 3) {
|
||||
lines.push('open-line')
|
||||
}
|
||||
if (doc.vd === 1) {
|
||||
lines.push('sync-line')
|
||||
}
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
@ -106,7 +106,8 @@
|
||||
|
||||
.doc-tree {
|
||||
@include box(100%, 100%);
|
||||
padding-left: 5px;
|
||||
padding-left: 6px;
|
||||
padding-right: 2px;
|
||||
// --el-transition-duration: .1s; // 折叠展开的动画效果
|
||||
|
||||
.menu-divider {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<bl-row class="container-name">收藏/关注</bl-row>
|
||||
<bl-row class="container-name">文章收藏</bl-row>
|
||||
<bl-row class="container-sub-name" just="space-between">
|
||||
Article Star
|
||||
<span v-if="configViewStyle.isHomeStarCard" class="iconbl bl-array-line container-operator" @click="showStarCard(false)" />
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<bl-row class="container-name">专题</bl-row>
|
||||
<bl-row class="container-name">专题收藏</bl-row>
|
||||
<bl-row class="container-sub-name" just="space-between">
|
||||
<span>Article Subjects</span>
|
||||
<span>Subject Star</span>
|
||||
<span v-if="configViewStyle.isHomeSubjectCard" class="iconbl bl-array-line container-operator" @click="showSubjectCard(false)" />
|
||||
<span v-else class="iconbl bl-article-line container-operator" @click="showSubjectCard(true)" />
|
||||
</bl-row>
|
||||
|
||||
@ -61,9 +61,7 @@
|
||||
<div v-if="data.ty === 11" class="menu-divider"></div>
|
||||
<div v-else class="menu-item-wrapper" @click.right="handleClickRightMenu($event, data)">
|
||||
<div class="doc-title">
|
||||
<bl-tag v-if="isShowSort && data.ty === 2" class="sort" :bgColor="getColor(node)">
|
||||
{{ data.s }}
|
||||
</bl-tag>
|
||||
<div v-if="isShowSort" class="sort-tag" :style="{ backgroundColor: getColor(node) }">{{ data.s }}</div>
|
||||
<div class="doc-name">
|
||||
<img class="menu-icon-img" v-if="isShowImg(data, viewStyle)" :src="data.icon" />
|
||||
<svg v-else-if="isShowSvg(data, viewStyle)" class="icon menu-icon" aria-hidden="true">
|
||||
@ -79,7 +77,7 @@
|
||||
<div v-else class="name-wrapper" :style="{ maxWidth: isNotBlank(data.icon) ? 'calc(100% - 25px)' : '100%' }">
|
||||
{{ data.n }}
|
||||
</div>
|
||||
<bl-tag v-for="tag in tags(data, viewStyle)" style="margin-top: 5px" :bg-color="tag.bgColor" :icon="tag.icon">
|
||||
<bl-tag v-for="tag in tags(data, viewStyle)" style="margin-top: 4px" :bg-color="tag.bgColor" :icon="tag.icon">
|
||||
{{ tag.content }}
|
||||
</bl-tag>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user