mirror of
https://gitee.com/blossom-editor/blossom.git
synced 2025-12-06 16:58:26 +08:00
Merge branch 'refctor-param' into dev
This commit is contained in:
commit
281d55b0ee
@ -80,7 +80,7 @@ docker compose -f docker/compose/blossom-mysql8.yaml up -d
|
||||
| Mr_tg000 | Lucky | egil | Glimpse |
|
||||
| 支付宝用户-\*\*衡 | 支付宝用户-\*\*福 | 支付宝用户-\*\*盼 | 何其正 |
|
||||
| -A 明 | | | |
|
||||
|
||||
wweeesssssssssssssswwwweewwweesssssssssssssssssssddddxzzxzxaasdasdqweqqqwertffghyq11231232
|
||||
---
|
||||
|
||||
<h4 align="center">你可以通过以下几种方式赞助 Blossom。</h4>
|
||||
|
||||
@ -12,62 +12,67 @@ public enum ParamEnum {
|
||||
/**
|
||||
* 文章的 web 端访问路径
|
||||
*/
|
||||
WEB_ARTICLE_URL(false,0),
|
||||
WEB_ARTICLE_URL(false, 0,""),
|
||||
|
||||
/**
|
||||
* 文章日志过期天数
|
||||
*/
|
||||
ARTICLE_LOG_EXP_DAYS(false,0),
|
||||
ARTICLE_LOG_EXP_DAYS(false, 0,""),
|
||||
|
||||
/**
|
||||
* 文章回收站过期天数
|
||||
*/
|
||||
ARTICLE_RECYCLE_EXP_DAYS(false,0),
|
||||
ARTICLE_RECYCLE_EXP_DAYS(false, 0,""),
|
||||
|
||||
/**
|
||||
* 和风天气KEY
|
||||
*/
|
||||
HEFENG_KEY(true,20),
|
||||
HEFENG_KEY(true, 20,""),
|
||||
|
||||
/**
|
||||
* GITEE key
|
||||
*/
|
||||
GITEE_ACCESS_TOKEN(true,20),
|
||||
GITEE_ACCESS_TOKEN(true, 20,""),
|
||||
|
||||
/**
|
||||
* 备份路径
|
||||
*/
|
||||
BACKUP_PATH(false,0),
|
||||
BACKUP_PATH(false, 0,""),
|
||||
|
||||
/**
|
||||
* 备份过期天数
|
||||
*/
|
||||
BACKUP_EXP_DAYS(false,0),
|
||||
BACKUP_EXP_DAYS(false, 0,""),
|
||||
|
||||
/**
|
||||
* BLOSSOM 对象存储地址
|
||||
*/
|
||||
BLOSSOM_OBJECT_STORAGE_DOMAIN(false, 0,"http://www.xxx.com/"),
|
||||
|
||||
/**
|
||||
* 服务器JWT加密字符串
|
||||
*/
|
||||
SERVER_JWT_SECRET(true,9999),
|
||||
SERVER_JWT_SECRET(true, 9999,""),
|
||||
|
||||
/**
|
||||
* 过期时间 - 服务器
|
||||
*/
|
||||
SERVER_MACHINE_EXPIRE(false,0),
|
||||
SERVER_MACHINE_EXPIRE(false, 0,""),
|
||||
|
||||
/**
|
||||
* 过期时间 - 域名
|
||||
*/
|
||||
SERVER_DOMAIN_EXPIRE(false,0),
|
||||
SERVER_DOMAIN_EXPIRE(false, 0,""),
|
||||
|
||||
/**
|
||||
* 过期时间 - HTTPS 证书
|
||||
*/
|
||||
SERVER_HTTPS_EXPIRE(false,0),
|
||||
SERVER_HTTPS_EXPIRE(false, 0,""),
|
||||
|
||||
/**
|
||||
* 过期时间 - 数据库
|
||||
*/
|
||||
SERVER_DATABASE_EXPIRE(false,0),
|
||||
SERVER_DATABASE_EXPIRE(false, 0,""),
|
||||
;
|
||||
|
||||
/**
|
||||
@ -82,8 +87,15 @@ public enum ParamEnum {
|
||||
@Getter
|
||||
private final Integer maskingLength;
|
||||
|
||||
ParamEnum(Boolean masking, Integer maskingLength) {
|
||||
/**
|
||||
* 默认值
|
||||
*/
|
||||
@Getter
|
||||
private final String defaultValue;
|
||||
|
||||
ParamEnum(Boolean masking, Integer maskingLength, String defaultValue) {
|
||||
this.masking = masking;
|
||||
this.maskingLength = maskingLength;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,8 @@ import com.blossom.backend.base.param.pojo.ParamEntity;
|
||||
import com.blossom.backend.base.param.pojo.ParamUpdReq;
|
||||
import com.blossom.common.base.exception.XzException500;
|
||||
import com.blossom.common.base.util.BeanUtil;
|
||||
import com.blossom.common.iaas.IaasEnum;
|
||||
import com.blossom.common.iaas.OSManager;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||
@ -32,7 +34,11 @@ import java.util.Map;
|
||||
public class ParamService extends ServiceImpl<ParamMapper, ParamEntity> {
|
||||
|
||||
private static final Map<String, ParamEntity> CACHE = new HashMap<>(20);
|
||||
private final OSManager osManager;
|
||||
|
||||
/**
|
||||
* 初始化系统参数
|
||||
*/
|
||||
@EventListener(ApplicationStartedEvent.class)
|
||||
public void refresh() {
|
||||
log.info("[ BASE] 初始化系统参数缓存");
|
||||
@ -76,10 +82,39 @@ public class ParamService extends ServiceImpl<ParamMapper, ParamEntity> {
|
||||
param.setParamValue(StrUtil.hide(param.getParamValue(), 0, Math.min(param.getParamValue().length(), name.getMaskingLength())));
|
||||
}
|
||||
result.put(name.name(), param.getParamValue());
|
||||
|
||||
// domain 涉及多个地方配置, 需要特别处理
|
||||
if (name.equals(ParamEnum.BLOSSOM_OBJECT_STORAGE_DOMAIN)) {
|
||||
result.put(name.name(), getDomain());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象存储的地址前缀, 优先从数据库中获取, 如果数据库中配置的是默认值,
|
||||
*
|
||||
* @return 对象存储的地址
|
||||
* @since 1.12.0
|
||||
*/
|
||||
public String getDomain() {
|
||||
if (osManager.getProp().getOsType().equals(IaasEnum.BLOSSOM.getType())) {
|
||||
String domain = getValue(ParamEnum.BLOSSOM_OBJECT_STORAGE_DOMAIN).getParamValue();
|
||||
// 如果后台配置的图片地址为默认值
|
||||
if (ParamEnum.BLOSSOM_OBJECT_STORAGE_DOMAIN.getDefaultValue().equals(domain)) {
|
||||
// 如果配置文件中未配置地址
|
||||
if (StrUtil.isNotBlank(osManager.getDomain())) {
|
||||
domain = osManager.getDomain();
|
||||
}
|
||||
}
|
||||
if (StrUtil.isBlank(domain)) {
|
||||
throw new XzException500("文件地址 [" + ParamEnum.BLOSSOM_OBJECT_STORAGE_DOMAIN.name() + "] 配置错误");
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
return osManager.getDomain();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改参数
|
||||
*/
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
package com.blossom.backend.base.paramu;
|
||||
|
||||
import com.blossom.backend.base.auth.AuthContext;
|
||||
import com.blossom.backend.base.paramu.pojo.UserParamUpdReq;
|
||||
import com.blossom.common.base.pojo.R;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 用户参数配置
|
||||
*
|
||||
* @since 1.12.0
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/user/param")
|
||||
public class UserParamController {
|
||||
|
||||
@Autowired
|
||||
private UserParamService baseService;
|
||||
|
||||
/**
|
||||
* 用户参数列表
|
||||
*
|
||||
* @apiNote 敏感参数会进行脱敏
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public R<Map<String, String>> list() {
|
||||
Map<String, String> param = baseService.selectMap(AuthContext.getUserId(), true, UserParamEnum.values());
|
||||
return R.ok(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户参数
|
||||
*/
|
||||
@PostMapping("/upd")
|
||||
public R<Map<String, String>> upd(@Validated @RequestBody UserParamUpdReq req) {
|
||||
req.setUserId(AuthContext.getUserId());
|
||||
baseService.update(req);
|
||||
baseService.refresh();
|
||||
return R.ok(baseService.selectMap(AuthContext.getUserId(), true, UserParamEnum.values()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新用户配置
|
||||
*/
|
||||
@PostMapping("/refresh")
|
||||
public R<?> paramRefresh() {
|
||||
baseService.refresh();
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package com.blossom.backend.base.paramu;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 参数枚举
|
||||
*
|
||||
* @author xzzz
|
||||
* @since 1.12.0
|
||||
*/
|
||||
public enum UserParamEnum {
|
||||
|
||||
/**
|
||||
* 文章的 web 端访问路径
|
||||
*/
|
||||
WEB_ARTICLE_URL(false, 0, "https://www.domain.com/blossom/#/articles?articleId="),
|
||||
/**
|
||||
* 博客 LOGO 地址
|
||||
*/
|
||||
WEB_LOGO_URL(false, 0, ""),
|
||||
/**
|
||||
* 博客名称
|
||||
*/
|
||||
WEB_LOGO_NAME(false, 0, ""),
|
||||
/**
|
||||
* 博客的公网安备号
|
||||
*/
|
||||
WEB_GONG_WANG_AN_BEI(false, 0, ""),
|
||||
/**
|
||||
* 博客备案号
|
||||
*/
|
||||
WEB_IPC_BEI_AN_HAO(false, 0, ""),
|
||||
/**
|
||||
* 是否提示博客地址配置有误
|
||||
*/
|
||||
WEB_BLOG_URL_ERROR_TIP_SHOW(false, 0, ""),
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* 是否脱敏
|
||||
*/
|
||||
@Getter
|
||||
private final Boolean masking;
|
||||
|
||||
/**
|
||||
* 脱敏长度
|
||||
*/
|
||||
@Getter
|
||||
private final Integer maskingLength;
|
||||
|
||||
@Getter
|
||||
private final String defaultValue;
|
||||
|
||||
UserParamEnum(Boolean masking, Integer maskingLength, String defaultValue) {
|
||||
this.masking = masking;
|
||||
this.maskingLength = maskingLength;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.blossom.backend.base.paramu;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.blossom.backend.base.paramu.pojo.UserParamEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 用户参数
|
||||
*
|
||||
* @since 1.12.0
|
||||
*/
|
||||
@Mapper
|
||||
public interface UserParamMapper extends BaseMapper<UserParamEntity> {
|
||||
|
||||
/**
|
||||
* 参数是否存在
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param paramName 参数值
|
||||
*/
|
||||
UserParamEntity selectByUserId(@Param("userId") Long userId, @Param("paramName") String paramName);
|
||||
|
||||
/**
|
||||
* 修改用户参数
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param paramName 参数名称
|
||||
* @param paramValue 参数值
|
||||
*/
|
||||
void updByParamName(@Param("userId") Long userId, @Param("paramName") String paramName, @Param("paramValue") String paramValue);
|
||||
}
|
||||
@ -0,0 +1,146 @@
|
||||
package com.blossom.backend.base.paramu;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.blossom.backend.base.param.ParamEnum;
|
||||
import com.blossom.backend.base.param.ParamMapper;
|
||||
import com.blossom.backend.base.param.pojo.ParamEntity;
|
||||
import com.blossom.backend.base.paramu.pojo.UserParamEntity;
|
||||
import com.blossom.backend.base.paramu.pojo.UserParamUpdReq;
|
||||
import com.blossom.backend.base.user.UserService;
|
||||
import com.blossom.backend.base.user.pojo.UserEntity;
|
||||
import com.blossom.common.base.exception.XzException500;
|
||||
import com.blossom.common.base.util.BeanUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 用户参数
|
||||
*/
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class UserParamService extends ServiceImpl<UserParamMapper, UserParamEntity> {
|
||||
|
||||
private final ParamMapper paramMapper;
|
||||
private final UserService userService;
|
||||
|
||||
private static final Map<Long, Map<String, UserParamEntity>> CACHE = new HashMap<>(20);
|
||||
|
||||
/**
|
||||
* 启动时刷新数据
|
||||
*/
|
||||
@EventListener(ApplicationStartedEvent.class)
|
||||
public void refresh() {
|
||||
CACHE.clear();
|
||||
List<UserEntity> users = userService.listAll();
|
||||
// 初始化所有用户的配置参数
|
||||
for (UserEntity user : users) {
|
||||
initUserParams(user.getId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取博客地址
|
||||
* <p>在 1.12.0 版本前, 博客的地址配置在 SysParam 中
|
||||
* <p>如果 SysParam 配置中有值, 则使用 SysParam 中的值, 否则使用默认值
|
||||
*/
|
||||
public String getWebArticleUrl() {
|
||||
List<ParamEntity> sysParams = paramMapper.selectList(new QueryWrapper<>());
|
||||
String WEB_ARTICLE_URL = "";
|
||||
|
||||
// 获取数据库中的配置的博客地址
|
||||
for (ParamEntity param : sysParams) {
|
||||
if (param.getParamName().equals(ParamEnum.WEB_ARTICLE_URL.name())) {
|
||||
WEB_ARTICLE_URL = param.getParamValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 如果数据库中没有配置, 则使用默认值
|
||||
if (StrUtil.isBlank(WEB_ARTICLE_URL)) {
|
||||
WEB_ARTICLE_URL = UserParamEnum.WEB_ARTICLE_URL.getDefaultValue();
|
||||
}
|
||||
return WEB_ARTICLE_URL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化用户参数
|
||||
*
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
public void initUserParams(Long userId) {
|
||||
Map<String, UserParamEntity> params = new HashMap<>(UserParamEnum.values().length);
|
||||
for (UserParamEnum param : UserParamEnum.values()) {
|
||||
// TODO 一次性查出数据以提高效率
|
||||
UserParamEntity storeParam = baseMapper.selectByUserId(userId, param.name());
|
||||
// 该用户不存在该参数, 则新增参数
|
||||
if (storeParam == null) {
|
||||
UserParamEntity istParam = new UserParamEntity();
|
||||
istParam.setUserId(userId);
|
||||
istParam.setParamName(param.name());
|
||||
istParam.setParamValue(param.getDefaultValue());
|
||||
// 博客的地址需要特别兼容, 用于适配 1.12.0 之前的版本
|
||||
if (param.name().equals(UserParamEnum.WEB_ARTICLE_URL.name())) {
|
||||
istParam.setParamValue(getWebArticleUrl());
|
||||
}
|
||||
baseMapper.insert(istParam);
|
||||
params.put(param.name(), istParam);
|
||||
} else {
|
||||
params.put(param.name(), storeParam);
|
||||
}
|
||||
}
|
||||
CACHE.put(userId, params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据参数名称获取参数
|
||||
*
|
||||
* @param name 参数名称
|
||||
*/
|
||||
public UserParamEntity getValue(Long userId, UserParamEnum name) {
|
||||
UserParamEntity param = CACHE.get(userId).get(name.name());
|
||||
XzException500.throwBy(ObjUtil.isNull(param), String.format("缺失系统参数[%s], 请检查系统参数配置", name.name()));
|
||||
return param;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据多个名称查询
|
||||
*
|
||||
* @param masking 返回数据是否脱敏
|
||||
* @param names 参数名称
|
||||
* @return 返回参数 map
|
||||
*/
|
||||
public Map<String, String> selectMap(Long userId, boolean masking, UserParamEnum... names) {
|
||||
if (ArrayUtil.isEmpty(names)) {
|
||||
return new HashMap<>(0);
|
||||
}
|
||||
Map<String, String> result = new HashMap<>(names.length);
|
||||
for (UserParamEnum name : names) {
|
||||
ParamEntity param = BeanUtil.toObj(CACHE.get(userId).get(name.name()), ParamEntity.class);
|
||||
XzException500.throwBy(ObjUtil.isNull(param), "缺失所有系统参数, 请检查用户参数配置[BASE_USER_PARAM]中是否包含数据");
|
||||
if (masking && name.getMasking()) {
|
||||
param.setParamValue(StrUtil.hide(param.getParamValue(), 0, Math.min(param.getParamValue().length(), name.getMaskingLength())));
|
||||
}
|
||||
result.put(name.name(), param.getParamValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改参数
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void update(UserParamUpdReq req) {
|
||||
baseMapper.updByParamName(req.getUserId(), req.getParamName(), req.getParamValue());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.blossom.backend.base.paramu.pojo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户参数
|
||||
*
|
||||
* @since 1.12.0
|
||||
*/
|
||||
@Data
|
||||
@TableName("base_user_param")
|
||||
public class UserParamEntity {
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 参数名称
|
||||
*/
|
||||
private String paramName;
|
||||
/**
|
||||
* 参数值
|
||||
*/
|
||||
private String paramValue;
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
private Date updTime;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package com.blossom.backend.base.paramu.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 修改参数
|
||||
*
|
||||
* @since 1.12.0
|
||||
*/
|
||||
@Data
|
||||
public class UserParamUpdReq {
|
||||
|
||||
/**
|
||||
* 参数名称
|
||||
*/
|
||||
@NotBlank(message = "参数名称为必填项")
|
||||
private String paramName;
|
||||
|
||||
/**
|
||||
* 参数值
|
||||
*/
|
||||
private String paramValue;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
}
|
||||
@ -1,15 +1,17 @@
|
||||
package com.blossom.backend.base.user;
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import com.blossom.backend.base.auth.AuthContext;
|
||||
import com.blossom.backend.base.auth.annotation.AuthIgnore;
|
||||
import com.blossom.backend.base.param.ParamEnum;
|
||||
import com.blossom.backend.base.param.ParamService;
|
||||
import com.blossom.backend.base.paramu.UserParamEnum;
|
||||
import com.blossom.backend.base.paramu.UserParamService;
|
||||
import com.blossom.backend.base.sys.SysService;
|
||||
import com.blossom.backend.base.user.pojo.*;
|
||||
import com.blossom.backend.config.BlConstants;
|
||||
import com.blossom.backend.server.article.draft.pojo.ArticleStatRes;
|
||||
import com.blossom.backend.server.article.stat.ArticleStatService;
|
||||
import com.blossom.backend.base.auth.AuthContext;
|
||||
import com.blossom.backend.base.auth.annotation.AuthIgnore;
|
||||
import com.blossom.common.base.exception.XzException400;
|
||||
import com.blossom.common.base.exception.XzException404;
|
||||
import com.blossom.common.base.pojo.R;
|
||||
@ -32,6 +34,7 @@ public class UserController {
|
||||
private final ArticleStatService articleService;
|
||||
private final SysService sysService;
|
||||
private final ParamService paramService;
|
||||
private final UserParamService userParamService;
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
@ -42,6 +45,8 @@ public class UserController {
|
||||
user.setOsRes(sysService.getOsConfig());
|
||||
Map<String, String> paramMap = paramService.selectMap(true, ParamEnum.values());
|
||||
user.setParams(paramMap);
|
||||
Map<String, String> userParamMap = userParamService.selectMap(AuthContext.getUserId(), true, UserParamEnum.values());
|
||||
user.setUserParams(userParamMap);
|
||||
return R.ok(user);
|
||||
}
|
||||
|
||||
|
||||
@ -63,4 +63,9 @@ public class BlossomUserRes extends AbstractPOJO implements Serializable {
|
||||
* 系统参数, paramName: paramValue
|
||||
*/
|
||||
private Map<String, String> params;
|
||||
|
||||
/**
|
||||
* 用户参数, paramName: paramValue
|
||||
*/
|
||||
private Map<String, String> userParams;
|
||||
}
|
||||
|
||||
@ -96,7 +96,8 @@ public class WebConfigurer implements WebMvcConfigurer {
|
||||
.addPathPatterns("/**")
|
||||
.excludePathPatterns(
|
||||
"/blog/**",
|
||||
"/editor/**"
|
||||
"/editor/**",
|
||||
"/error"
|
||||
);
|
||||
|
||||
}
|
||||
@ -110,7 +111,7 @@ public class WebConfigurer implements WebMvcConfigurer {
|
||||
registry.addViewController("/editor/").setViewName("/editor/index.html");
|
||||
}
|
||||
|
||||
/***
|
||||
/**
|
||||
* 静态文件处理
|
||||
*/
|
||||
@Override
|
||||
|
||||
@ -6,9 +6,9 @@ import cn.hutool.extra.qrcode.QrCodeUtil;
|
||||
import cn.hutool.extra.qrcode.QrConfig;
|
||||
import com.blossom.backend.base.auth.AuthContext;
|
||||
import com.blossom.backend.base.auth.annotation.AuthIgnore;
|
||||
import com.blossom.backend.base.param.ParamEnum;
|
||||
import com.blossom.backend.base.param.ParamService;
|
||||
import com.blossom.backend.base.param.pojo.ParamEntity;
|
||||
import com.blossom.backend.base.paramu.UserParamEnum;
|
||||
import com.blossom.backend.base.paramu.UserParamService;
|
||||
import com.blossom.backend.base.paramu.pojo.UserParamEntity;
|
||||
import com.blossom.backend.server.article.draft.ArticleService;
|
||||
import com.blossom.backend.server.article.draft.pojo.ArticleEntity;
|
||||
import com.blossom.backend.server.article.draft.pojo.ArticleInfoRes;
|
||||
@ -46,7 +46,7 @@ public class ArticleOpenController {
|
||||
|
||||
private final ArticleService articleService;
|
||||
private final ArticleOpenService openService;
|
||||
private final ParamService paramService;
|
||||
private final UserParamService userParamService;
|
||||
|
||||
|
||||
/**
|
||||
@ -96,7 +96,7 @@ public class ArticleOpenController {
|
||||
* @param req 文章对象
|
||||
*/
|
||||
@PostMapping("/sync")
|
||||
public R<ArticleOpenRes> sync(@Validated @RequestBody ArticleOpenSyncReq req) {
|
||||
protected R<ArticleOpenRes> sync(@Validated @RequestBody ArticleOpenSyncReq req) {
|
||||
openService.sync(req.getId());
|
||||
ArticleOpenEntity openEntity = openService.selectById(req.getId(), false, false, false);
|
||||
return R.ok(openEntity.to(ArticleOpenRes.class));
|
||||
@ -110,8 +110,8 @@ public class ArticleOpenController {
|
||||
*/
|
||||
@GetMapping("/qrcode")
|
||||
public void qrcode(@RequestParam("id") Long id, HttpServletResponse response) {
|
||||
ParamEntity param = paramService.getValue(ParamEnum.WEB_ARTICLE_URL);
|
||||
XzException404.throwBy(ObjUtil.isNull(param), "未配置文章公网访问链接,无法生成二维码,请在服务端配置参数 [BaseParam.WEB_ARTICLE_URL]");
|
||||
UserParamEntity param = userParamService.getValue(AuthContext.getUserId(), UserParamEnum.WEB_ARTICLE_URL);
|
||||
XzException404.throwBy(ObjUtil.isNull(param), "请先在设置中配置博客访问路径");
|
||||
final String url = param.getParamValue() + id;
|
||||
BufferedImage bfi = QrCodeUtil.generate(url, new QrConfig(200, 200));
|
||||
response.setContentType("image/png");
|
||||
|
||||
@ -22,7 +22,6 @@ import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
@ -82,15 +81,26 @@ public class PictureBlosController {
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件路径
|
||||
*
|
||||
* @param filename 文件名称
|
||||
*/
|
||||
private void checkFilename(String filename) {
|
||||
if (StrUtil.isBlank(filename)) {
|
||||
throw new XzException400("未知文件");
|
||||
}
|
||||
if (!filename.startsWith(osManager.getDefaultPath())) {
|
||||
// 如果图片前缀不是配置的前缀,则去数据库查询文件是否上传过。
|
||||
log.error("路径必须以配置的前缀开头");
|
||||
throw new XzException400("无法访问");
|
||||
}
|
||||
if (!filename.startsWith("/")) {
|
||||
log.error("路径必须是绝对路径");
|
||||
throw new XzException400("无法访问");
|
||||
}
|
||||
if (!FileUtil.exist(filename)) {
|
||||
log.error("文件不存在");
|
||||
throw new XzException400("未知文件");
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.blossom.backend.base.param.ParamService;
|
||||
import com.blossom.backend.server.article.reference.ArticleReferenceService;
|
||||
import com.blossom.backend.server.folder.FolderService;
|
||||
import com.blossom.backend.server.folder.pojo.FolderEntity;
|
||||
@ -42,6 +43,7 @@ public class PictureService extends ServiceImpl<PictureMapper, PictureEntity> {
|
||||
private FolderService folderService;
|
||||
private ArticleReferenceService articleReferenceService;
|
||||
private OSManager osManager;
|
||||
private ParamService paramService;
|
||||
|
||||
@Autowired
|
||||
public void setFolderService(FolderService folderService) {
|
||||
@ -58,6 +60,11 @@ public class PictureService extends ServiceImpl<PictureMapper, PictureEntity> {
|
||||
this.osManager = osManager;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setParamService(ParamService paramService) {
|
||||
this.paramService = paramService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页列表
|
||||
*/
|
||||
@ -149,7 +156,7 @@ public class PictureService extends ServiceImpl<PictureMapper, PictureEntity> {
|
||||
}
|
||||
pic.setSize(file.getSize());
|
||||
|
||||
final String domain = osManager.getDomain();
|
||||
final String domain = paramService.getDomain();
|
||||
final String rootPath = osManager.getDefaultPath();
|
||||
final String uid = "/U" + userId;
|
||||
final String pname = "/" + pic.getName();
|
||||
@ -245,4 +252,5 @@ public class PictureService extends ServiceImpl<PictureMapper, PictureEntity> {
|
||||
public PictureStatRes stat(Long userId, Long pid) {
|
||||
return baseMapper.stat(userId, pid);
|
||||
}
|
||||
|
||||
}
|
||||
@ -16,6 +16,15 @@ logging:
|
||||
com.baomidou.dynamic.datasource.DynamicRoutingDataSource: warn
|
||||
com.zaxxer.hikari.HikariDataSource: warn
|
||||
org.apache.coyote.http11.Http11NioProtocol: warn
|
||||
com:
|
||||
blossom:
|
||||
backend:
|
||||
server:
|
||||
article:
|
||||
log: info
|
||||
draft:
|
||||
ArticleMapper:
|
||||
updContentById: info
|
||||
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ project ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
project:
|
||||
@ -75,7 +84,7 @@ project:
|
||||
os-type: blossom
|
||||
blos:
|
||||
# 请以 /pic 结尾, 如果你在 nginx 中配置有代理, 注意别忘了添加你的代理路径
|
||||
domain: "http://localhost:9999/pic/"
|
||||
domain:
|
||||
# 请以 / 开头, / 结尾, 简短的路径在文章中有更好的显示效果, 过长一定程度会使文章内容混乱
|
||||
default-path: "/home/bl/img/"
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ 全文搜索 ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
@ -76,7 +76,7 @@ project:
|
||||
blos:
|
||||
# 请以 /pic 结尾, 如果你在 nginx 中配置有代理, 注意别忘了添加你的代理路径
|
||||
# 注意:在下方示例中, /bl 即为 nginx 反向代理路径, 如果你的访问路径中不包含反向代理或路径不同, 请酌情删除或修改
|
||||
domain: "https://www.wangyunf.com/bl/pic/"
|
||||
domain: "http://www.xxx.com/"
|
||||
# 请以 / 开头, / 结尾, 简短的路径在文章中有更好的显示效果, 过长一定程度会使文章内容混乱
|
||||
default-path: "/home/bl/img/"
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ 全文搜索 ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.blossom.backend.base.paramu.UserParamMapper">
|
||||
<select id="selectByUserId" resultType="com.blossom.backend.base.paramu.pojo.UserParamEntity">
|
||||
select *
|
||||
from base_user_param
|
||||
where user_id = #{userId}
|
||||
and param_name = #{paramName}
|
||||
</select>
|
||||
|
||||
<update id="updByParamName">
|
||||
update base_user_param
|
||||
set param_value = #{paramValue}
|
||||
where param_name = #{paramName}
|
||||
and user_id = #{userId}
|
||||
</update>
|
||||
</mapper>
|
||||
@ -152,6 +152,22 @@ SELECT 904,
|
||||
WHERE id = 904);
|
||||
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- since: 1.12.0
|
||||
-- ----------------------------
|
||||
INSERT INTO base_sys_param (id, param_name, param_value, param_desc, open_state, cre_time, upd_time)
|
||||
SELECT 101,
|
||||
'BLOSSOM_OBJECT_STORAGE_DOMAIN',
|
||||
'http://www.xxx.com/',
|
||||
'BLOSSOM 对象存储地址',
|
||||
1,
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP
|
||||
WHERE NOT EXISTS (SELECT 1
|
||||
FROM base_sys_param
|
||||
WHERE id = 101);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for base_user
|
||||
-- ----------------------------
|
||||
|
||||
@ -27,7 +27,7 @@ public enum RCode implements IRCode {
|
||||
SERVER_DENIED_CUR_ENV ("40302", "当前环境无法访问该资源"),
|
||||
|
||||
/* ──────────────────────────────────────────── 404 ────────────────────────────────────────────────────────────*/
|
||||
NOT_FOUND ("40400", "找不到您的请求"),
|
||||
NOT_FOUND ("40400", "未找到您的请求"),
|
||||
|
||||
/* ──────────────────────────────────────────── 500 ────────────────────────────────────────*/
|
||||
INTERNAL_SERVER_ERROR ("50000", "服务器处理错误"),
|
||||
|
||||
@ -60,6 +60,13 @@ public class BLOSManager extends AbstractOSManager implements OSManager {
|
||||
return domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传图片, 并返回文件的访问地址
|
||||
* <p>但需要注意的是, 调用方可以保存自己的文件地址前缀, 而不使用 {@link BLOSManager#getDomain()},
|
||||
*
|
||||
* @param filename 文件名
|
||||
* @param inputStream 输入流
|
||||
*/
|
||||
@Override
|
||||
public String put(String filename, InputStream inputStream) {
|
||||
File file = FileUtil.newFile(filename);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { app, shell, ipcMain, BrowserWindow, Menu, IpcMainEvent, Tray, HandlerDetails } from 'electron'
|
||||
import { app, shell, ipcMain, BrowserWindow, Menu, IpcMainEvent, Tray, HandlerDetails, session } from 'electron'
|
||||
import { join } from 'path'
|
||||
import { electronApp, optimizer, is, platform } from '@electron-toolkit/utils'
|
||||
import icon from '../../resources/imgs/icon.ico?asset'
|
||||
@ -51,6 +51,15 @@ if (!gotTheLock) {
|
||||
createMainWindow()
|
||||
}, 300)
|
||||
|
||||
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
|
||||
callback({
|
||||
responseHeaders: {
|
||||
...details.responseHeaders,
|
||||
'Content-Security-Policy': ['frame-ancestors *']
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
@ -432,8 +441,8 @@ export const initOnWindow = (window: BrowserWindow) => {
|
||||
*/
|
||||
window.webContents.setWindowOpenHandler((details: HandlerDetails): any => {
|
||||
let url = details.url as string
|
||||
if (blossomUserinfo && url.startsWith(blossomUserinfo.params.WEB_ARTICLE_URL)) {
|
||||
let articleId: string = url.replaceAll(blossomUserinfo.params.WEB_ARTICLE_URL, '')
|
||||
if (blossomUserinfo && url.startsWith(blossomUserinfo.userParams.WEB_ARTICLE_URL)) {
|
||||
let articleId: string = url.replaceAll(blossomUserinfo.userParams.WEB_ARTICLE_URL, '')
|
||||
createNewWindow('article', articleId, Number(articleId))
|
||||
} else {
|
||||
shell.openExternal(url)
|
||||
@ -450,8 +459,8 @@ export const initOnWindow = (window: BrowserWindow) => {
|
||||
const interceptorATag = (e: Event, url: string): boolean => {
|
||||
e.preventDefault()
|
||||
let innerUrl = url
|
||||
if (blossomUserinfo && innerUrl.startsWith(blossomUserinfo.params.WEB_ARTICLE_URL)) {
|
||||
let articleId: string = innerUrl.replaceAll(blossomUserinfo.params.WEB_ARTICLE_URL, '')
|
||||
if (blossomUserinfo && innerUrl.startsWith(blossomUserinfo.userParams.WEB_ARTICLE_URL)) {
|
||||
let articleId: string = innerUrl.replaceAll(blossomUserinfo.userParams.WEB_ARTICLE_URL, '')
|
||||
createNewWindow('article', articleId, Number(articleId))
|
||||
} else if (!is.dev) {
|
||||
shell.openExternal(url)
|
||||
|
||||
@ -29,6 +29,33 @@ export const paramRefreshApi = (): Promise<R<any>> => {
|
||||
return rq.post<R<any>>('/sys/param/refresh', {})
|
||||
}
|
||||
|
||||
// 用户参数
|
||||
|
||||
/**
|
||||
* 获取用户参数列表
|
||||
* @returns
|
||||
*/
|
||||
export const userParamListApi = (): Promise<R<any>> => {
|
||||
return rq.get<R<any>>('/user/param/list', {})
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改系统参数
|
||||
* @returns
|
||||
*/
|
||||
export const userParamUpdApi = (data: object): Promise<R<any>> => {
|
||||
return rq.post<R<any>>('/user/param/upd', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新系统参数缓存
|
||||
* @param data 文件 form
|
||||
* @returns
|
||||
*/
|
||||
export const userParamRefreshApi = (): Promise<R<any>> => {
|
||||
return rq.post<R<any>>('/user/param/refresh', {})
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param data 文件 form
|
||||
@ -506,8 +533,8 @@ export const pictureStatApi = (params?: object): Promise<R<any>> => {
|
||||
|
||||
/**
|
||||
* 转移文件
|
||||
* @param data
|
||||
* @returns
|
||||
* @param data
|
||||
* @returns
|
||||
*/
|
||||
export const pictureTransferApi = (data?: object): Promise<R<any>> => {
|
||||
return rq.post<R<any>>('/picture/transfer', data)
|
||||
|
||||
@ -102,21 +102,28 @@ export class Request {
|
||||
* @returns
|
||||
*/
|
||||
(err: any) => {
|
||||
console.log(err)
|
||||
let errorMsg = err.message
|
||||
let url = ''
|
||||
if (err.config) {
|
||||
url = ':' + err.config.url
|
||||
}
|
||||
let code = err.code
|
||||
let resp = err.response
|
||||
if (resp && resp.data) {
|
||||
errorMsg = resp.data.msg
|
||||
}
|
||||
if (code === 'ERR_NETWORK') {
|
||||
errorMsg = '网络错误,请检查您的网络是否通畅'
|
||||
}
|
||||
if (err.request && err.request.status === 404) {
|
||||
Notify.error('未找到您的请求, 请您检查服务器地址或应用版本!', '请求失败(404)')
|
||||
Notify.error(resp.data.msg, '请求失败')
|
||||
return Promise.reject(err)
|
||||
}
|
||||
if (code === 'ERR_NETWORK') {
|
||||
Notify.error('网络错误,请检查您的网络是否通畅', '请求失败')
|
||||
return Promise.reject(err)
|
||||
}
|
||||
if (err.request && err.request.status === 404) {
|
||||
Notify.error('未找到您的请求, 请您检查服务器地址!', '请求失败(404)')
|
||||
return Promise.reject(err)
|
||||
}
|
||||
if (err.request && err.request.status === 405) {
|
||||
Notify.error(`您的请求地址可能有误, 请检查请求地址${url}`, '请求失败(405)')
|
||||
return Promise.reject(err)
|
||||
}
|
||||
Notify.error(errorMsg, '请求失败')
|
||||
return Promise.reject(err)
|
||||
}
|
||||
)
|
||||
|
||||
@ -9,7 +9,7 @@ const blossom = {
|
||||
|
||||
//
|
||||
DOC: 'https://www.wangyunf.com/blossom-doc/index',
|
||||
CONTACT: 'QQ群:522359970 / Email: kuamax888@qq.com',
|
||||
CONTACT: 'https://www.wangyunf.com/blossom-doc/guide/about/all.html',
|
||||
GITHUB_REPO: 'https://github.com/blossom-editor/blossom',
|
||||
GITHUB_RELEASE: 'https://github.com/blossom-editor/blossom/releases',
|
||||
GITEE_REPO: 'https://gitee.com/blossom-editor/blossom'
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconbl"; /* Project id 4118609 */
|
||||
src: url('iconfont.woff2?t=1702393359707') format('woff2'),
|
||||
url('iconfont.woff?t=1702393359707') format('woff'),
|
||||
url('iconfont.ttf?t=1702393359707') format('truetype');
|
||||
src: url('iconfont.woff2?t=1703588816023') format('woff2'),
|
||||
url('iconfont.woff?t=1703588816023') format('woff'),
|
||||
url('iconfont.ttf?t=1703588816023') format('truetype');
|
||||
}
|
||||
|
||||
.iconbl {
|
||||
@ -13,6 +13,18 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.bl-blog:before {
|
||||
content: "\e7c6";
|
||||
}
|
||||
|
||||
.bl-caution-line:before {
|
||||
content: "\ea4c";
|
||||
}
|
||||
|
||||
.bl-a-picturecracked-line:before {
|
||||
content: "\ea4b";
|
||||
}
|
||||
|
||||
.bl-xiaoxie:before {
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -5,6 +5,27 @@
|
||||
"css_prefix_text": "bl-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "12579639",
|
||||
"name": "blog",
|
||||
"font_class": "blog",
|
||||
"unicode": "e7c6",
|
||||
"unicode_decimal": 59334
|
||||
},
|
||||
{
|
||||
"icon_id": "24341306",
|
||||
"name": "caution-line",
|
||||
"font_class": "caution-line",
|
||||
"unicode": "ea4c",
|
||||
"unicode_decimal": 59980
|
||||
},
|
||||
{
|
||||
"icon_id": "24342104",
|
||||
"name": "picture cracked-line",
|
||||
"font_class": "a-picturecracked-line",
|
||||
"unicode": "ea4b",
|
||||
"unicode_decimal": 59979
|
||||
},
|
||||
{
|
||||
"icon_id": "11179871",
|
||||
"name": "小写",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -2,6 +2,43 @@
|
||||
<div class="app-header-root">
|
||||
<div class="drag">{{ tryuseComment }}</div>
|
||||
<div class="window-workbench">
|
||||
<el-popover
|
||||
popper-class="header-popover"
|
||||
ref="PopoverRef"
|
||||
trigger="click"
|
||||
width="350px"
|
||||
:virtual-ref="ButtonRef"
|
||||
:hide-after="10"
|
||||
:tabindex="100"
|
||||
:offset="5"
|
||||
:persistent="false"
|
||||
virtual-triggering>
|
||||
<div class="header-config-popover">
|
||||
<bl-row class="url-container" just="space-between">
|
||||
<bl-col width="60px" height="60px" class="iconbl bl-blog" just="center"></bl-col>
|
||||
<bl-col width="calc(100% - 70px)" height="60px" align="flex-start" just="flex-start">
|
||||
<div class="name"><span>博客地址</span> <span class="iconbl bl-sendmail-line"></span></div>
|
||||
<div class="url">
|
||||
{{ userStore.userParams.WEB_ARTICLE_URL }}123123123123123123123123123123123123123123123123123123123123123123123123123123123123
|
||||
</div>
|
||||
</bl-col>
|
||||
</bl-row>
|
||||
<bl-row class="url-container" height="100%" style="margin-bottom: 6px">
|
||||
<bl-col width="60px" height="60px" class="iconbl bl-image--line" just="center"></bl-col>
|
||||
<bl-col width="calc(100% - 70px)" height="60px" align="flex-start" just="flex-start">
|
||||
<div class="name">图片地址</div>
|
||||
<div class="url">{{ userStore.sysParams.BLOSSOM_OBJECT_STORAGE_DOMAIN }}</div>
|
||||
</bl-col>
|
||||
</bl-row>
|
||||
<bl-row just="space-between">
|
||||
<el-button text>关闭闪烁提示</el-button>
|
||||
<el-button type="primary" plain @click="showQuickSetting">快捷配置</el-button>
|
||||
</bl-row>
|
||||
</div>
|
||||
</el-popover>
|
||||
|
||||
<div class="iconbl bl-blog warn-heightlight" ref="ButtonRef" v-click-outside="onClickOutside"></div>
|
||||
|
||||
<div class="iconbl bl-a-colorpalette-line" @click="themeStrore.show()"></div>
|
||||
|
||||
<el-tooltip content="查看图标" effect="light" placement="top" :show-after="1000" :hide-after="0" :auto-close="2000">
|
||||
@ -27,19 +64,35 @@
|
||||
<el-drawer class="web-collect-drawer" size="420" v-model="isShowWebDrawer">
|
||||
<WebCollect></WebCollect>
|
||||
</el-drawer>
|
||||
|
||||
<el-dialog
|
||||
v-model="isShowQuickSetting"
|
||||
width="80%"
|
||||
style="height: fit-content; max-width: 800px"
|
||||
:align-center="true"
|
||||
:append-to-body="false"
|
||||
:destroy-on-close="true"
|
||||
:close-on-click-modal="false"
|
||||
draggable>
|
||||
<QuickSetting ref="PlanDayInfoRef"></QuickSetting>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { computed, onMounted, onUnmounted, ref, unref } from 'vue'
|
||||
import { ClickOutside as vClickOutside } from 'element-plus'
|
||||
import { toRoute } from '@renderer/router'
|
||||
import { useThemeStore } from '@renderer/stores/theme'
|
||||
import { windowMin, windowMax, windowHide, setBestSize } from '@renderer/assets/utils/electron'
|
||||
import { windowMin, windowMax, windowHide, setBestSize, openExtenal } from '@renderer/assets/utils/electron'
|
||||
import WebCollect from './WebCollect.vue'
|
||||
import { isWindows, isElectron } from '@renderer/assets/utils/util'
|
||||
import { isTryuse } from '@renderer/scripts/env'
|
||||
import SYSTEM from '@renderer/assets/constants/system'
|
||||
import { useUserStore } from '@renderer/stores/user'
|
||||
import QuickSetting from '@renderer/views/index/setting/QuickSetting.vue'
|
||||
|
||||
const themeStrore = useThemeStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', handleResize)
|
||||
@ -72,6 +125,22 @@ const isFullScreen = ref(checkFullScreen())
|
||||
const handleResize = () => {
|
||||
isFullScreen.value = checkFullScreen()
|
||||
}
|
||||
|
||||
//#region 快捷配置
|
||||
|
||||
const ButtonRef = ref()
|
||||
const PopoverRef = ref()
|
||||
const isShowQuickSetting = ref(false)
|
||||
|
||||
const onClickOutside = () => {
|
||||
unref(PopoverRef).popperRef?.delayHide?.()
|
||||
}
|
||||
|
||||
const showQuickSetting = () => {
|
||||
unref(PopoverRef).popperRef?.delayHide?.()
|
||||
isShowQuickSetting.value = true
|
||||
}
|
||||
//#endregion
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@ -79,7 +148,7 @@ const handleResize = () => {
|
||||
@include box(100%, 100%);
|
||||
@include flex(row, space-between, center);
|
||||
|
||||
$width-workbench: 220px;
|
||||
$width-workbench: 240px;
|
||||
$width-drag: calc(100% - #{$width-workbench});
|
||||
|
||||
.drag {
|
||||
@ -94,14 +163,16 @@ const handleResize = () => {
|
||||
|
||||
.window-workbench {
|
||||
@include box($width-workbench, 100%);
|
||||
@include flex(row, flex-end, center);
|
||||
@include flex(row, flex-end, flex-end);
|
||||
color: var(--el-color-primary);
|
||||
padding-right: 4px;
|
||||
|
||||
div {
|
||||
@include box(40px, 100%);
|
||||
@include box(40px, 90%);
|
||||
@include flex(row, center, center);
|
||||
cursor: pointer;
|
||||
transition: 0.3s;
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
@ -123,6 +194,72 @@ const handleResize = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.warn-heightlight {
|
||||
animation: animated-border 1.5s infinite;
|
||||
text-shadow: 0 0 3px #e3a300;
|
||||
background-color: #e3a300;
|
||||
color: var(--bl-html-color);
|
||||
}
|
||||
|
||||
@keyframes animated-border {
|
||||
0% {
|
||||
// box-shadow: 0 0 0 0 rgba(227, 163, 0, 0.7);
|
||||
filter: drop-shadow(0 0 0 #e3a300);
|
||||
}
|
||||
|
||||
100% {
|
||||
// box-shadow: 0 0 0 10px rgba(227, 163, 0, 0);
|
||||
filter: drop-shadow(0 0 30px #e3a300);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-config-popover {
|
||||
@include font(13px, 300);
|
||||
margin: 6px;
|
||||
|
||||
.url-container {
|
||||
padding: 6px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
|
||||
.bl-blog,
|
||||
.bl-image--line {
|
||||
@include themeBg(#f5f5f5, #060404);
|
||||
font-size: 28px;
|
||||
border-radius: 4px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.bl-image--line {
|
||||
font-size: 33px;
|
||||
}
|
||||
|
||||
.bl-sendmail-line {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 1px solid var(--el-border-color);
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
width: 100%;
|
||||
min-height: 20px;
|
||||
text-decoration: none;
|
||||
color: var(--el-text-color);
|
||||
}
|
||||
|
||||
.url {
|
||||
@include box(100%, 40px);
|
||||
font-size: 12px;
|
||||
padding: 2px 5px 0 5px;
|
||||
overflow-y: scroll;
|
||||
border-radius: 4px;
|
||||
color: var(--bl-text-color-light);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -137,4 +274,11 @@ const handleResize = () => {
|
||||
--el-drawer-padding-primary: 0;
|
||||
}
|
||||
}
|
||||
.header-popover {
|
||||
/* inset: 35.3333px 10px auto auto !important; */
|
||||
padding: 0 !important;
|
||||
.el-popper__arrow {
|
||||
/* left: 240.333px !important; */
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -7,7 +7,7 @@ const isDemo = import.meta.env.MODE === 'tryuse'
|
||||
export const storeKey = 'serverUrl'
|
||||
export const usernameKey = 'username'
|
||||
|
||||
const initServerUrl = () => {
|
||||
const initServerUrl = (): string => {
|
||||
const defaultUrl = isDemo ? SYSTEM.TRY_USE.serverUrl : ''
|
||||
Local.set(storeKey, defaultUrl)
|
||||
return defaultUrl
|
||||
@ -15,7 +15,7 @@ const initServerUrl = () => {
|
||||
|
||||
export const useServerStore = defineStore('serverStore', {
|
||||
state: () => ({
|
||||
serverUrl: Local.get(storeKey) || initServerUrl(),
|
||||
serverUrl: (Local.get(storeKey) as string) || initServerUrl(),
|
||||
serverUsername: Local.get(usernameKey) || ''
|
||||
}),
|
||||
actions: {
|
||||
|
||||
@ -34,42 +34,110 @@ const initAuth = () => {
|
||||
return auth
|
||||
}
|
||||
|
||||
const initUserinfo = () => {
|
||||
let userinfo = {
|
||||
id: '',
|
||||
username: '暂未登录',
|
||||
nickName: '暂未登录',
|
||||
avatar: '',
|
||||
remark: '',
|
||||
articleCount: 0,
|
||||
articleWords: 0,
|
||||
osRes: {
|
||||
osType: '',
|
||||
bucketName: '',
|
||||
domain: '',
|
||||
defaultPath: ''
|
||||
},
|
||||
params: {
|
||||
WEB_ARTICLE_URL: '',
|
||||
BACKUP_PATH: '',
|
||||
BACKUP_EXP_DAYS: '',
|
||||
ARTICLE_LOG_EXP_DAYS: '',
|
||||
ARTICLE_RECYCLE_EXP_DAYS: '',
|
||||
SERVER_MACHINE_EXPIRE: '',
|
||||
SERVER_DATABASE_EXPIRE: '',
|
||||
SERVER_HTTPS_EXPIRE: '',
|
||||
SERVER_DOMAIN_EXPIRE: ''
|
||||
}
|
||||
const DEFAULT_USER_INFO = {
|
||||
id: '',
|
||||
username: '暂未登录',
|
||||
nickName: '暂未登录',
|
||||
avatar: '',
|
||||
remark: '',
|
||||
articleCount: 0,
|
||||
articleWords: 0,
|
||||
osRes: {
|
||||
osType: '',
|
||||
bucketName: '',
|
||||
domain: '',
|
||||
defaultPath: ''
|
||||
},
|
||||
params: {
|
||||
/**
|
||||
* @deprecated 该字段已不使用, 博客地址改用 userParams.WEB_ARTICLE_URL, 使用该地址会报错
|
||||
*/
|
||||
WEB_ARTICLE_URL: '',
|
||||
BACKUP_PATH: '',
|
||||
BACKUP_EXP_DAYS: '',
|
||||
ARTICLE_LOG_EXP_DAYS: '',
|
||||
ARTICLE_RECYCLE_EXP_DAYS: '',
|
||||
HEFENG_KEY: '',
|
||||
BLOSSOM_OBJECT_STORAGE_DOMAIN: '',
|
||||
SERVER_MACHINE_EXPIRE: '',
|
||||
SERVER_DATABASE_EXPIRE: '',
|
||||
SERVER_HTTPS_EXPIRE: '',
|
||||
SERVER_DOMAIN_EXPIRE: ''
|
||||
},
|
||||
userParams: {
|
||||
WEB_ARTICLE_URL: '',
|
||||
WEB_IPC_BEI_AN_HAO: '',
|
||||
WEB_LOGO_NAME: '',
|
||||
WEB_LOGO_URL: '',
|
||||
WEB_GONG_WANG_AN_BEI: '',
|
||||
WEB_BLOG_URL_ERROR_TIP_SHOW: ''
|
||||
}
|
||||
Local.set(userinfoKey, userinfo)
|
||||
return userinfo
|
||||
}
|
||||
const timeoutMs = 800
|
||||
|
||||
export type Userinfo = typeof DEFAULT_USER_INFO
|
||||
|
||||
/**
|
||||
* 初始化用户默认值
|
||||
*/
|
||||
const initUserinfo = (): Userinfo => {
|
||||
// let userinfo = {
|
||||
// id: '',
|
||||
// username: '暂未登录',
|
||||
// nickName: '暂未登录',
|
||||
// avatar: '',
|
||||
// remark: '',
|
||||
// articleCount: 0,
|
||||
// articleWords: 0,
|
||||
// osRes: {
|
||||
// osType: '',
|
||||
// bucketName: '',
|
||||
// domain: '',
|
||||
// defaultPath: ''
|
||||
// },
|
||||
// params: {
|
||||
// /**
|
||||
// * @deprecated 该字段已不使用, 博客地址改用 userParams.WEB_ARTICLE_URL, 使用该地址会报错
|
||||
// */
|
||||
// WEB_ARTICLE_URL: '',
|
||||
// BACKUP_PATH: '',
|
||||
// BACKUP_EXP_DAYS: '',
|
||||
// ARTICLE_LOG_EXP_DAYS: '',
|
||||
// ARTICLE_RECYCLE_EXP_DAYS: '',
|
||||
// HEFENG_KEY: '',
|
||||
// BLOSSOM_OBJECT_STORAGE_DOMAIN: '',
|
||||
// SERVER_MACHINE_EXPIRE: '',
|
||||
// SERVER_DATABASE_EXPIRE: '',
|
||||
// SERVER_HTTPS_EXPIRE: '',
|
||||
// SERVER_DOMAIN_EXPIRE: ''
|
||||
// },
|
||||
// userParams: {
|
||||
// WEB_ARTICLE_URL: '',
|
||||
// WEB_IPC_BEI_AN_HAO: '',
|
||||
// WEB_LOGO_NAME: '',
|
||||
// WEB_LOGO_URL: '',
|
||||
// WEB_GONG_WANG_AN_BEI: '',
|
||||
// WEB_BLOG_URL_ERROR_TIP_SHOW: ''
|
||||
// }
|
||||
// }
|
||||
Local.set(userinfoKey, { ...DEFAULT_USER_INFO })
|
||||
return { ...DEFAULT_USER_INFO }
|
||||
}
|
||||
export const useUserStore = defineStore('userStore', {
|
||||
state: () => ({
|
||||
auth: Local.get(storeKey) || initAuth(),
|
||||
userinfo: Local.get(userinfoKey) || initUserinfo()
|
||||
/** @type { Userinfo } */
|
||||
userinfo: (Local.get(userinfoKey) as Userinfo) || initUserinfo()
|
||||
}),
|
||||
getters: {
|
||||
/** 获取系统个人配置信息 */
|
||||
sysParams(state) {
|
||||
return state.userinfo.params
|
||||
},
|
||||
/** 获取用户个人配置信息 */
|
||||
userParams(state) {
|
||||
return state.userinfo.userParams
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
/**
|
||||
* 根据用户名密码登录
|
||||
@ -84,20 +152,16 @@ export const useUserStore = defineStore('userStore', {
|
||||
*/
|
||||
await loginApi({ username: username, password: password, clientId: 'blossom', grantType: 'password' })
|
||||
.then((resp: any) => {
|
||||
setTimeout(() => {
|
||||
let auth = { token: resp.data.token, status: AuthStatus.Succ }
|
||||
this.auth = auth
|
||||
Local.set(storeKey, auth)
|
||||
this.getUserinfo()
|
||||
}, timeoutMs)
|
||||
let auth = { token: resp.data.token, status: AuthStatus.Succ }
|
||||
this.auth = auth
|
||||
Local.set(storeKey, auth)
|
||||
this.getUserinfo()
|
||||
})
|
||||
.catch((_e) => {
|
||||
setTimeout(() => {
|
||||
this.reset()
|
||||
// 登录失败的状态需要特别更改
|
||||
let auth = { token: '', status: AuthStatus.Fail }
|
||||
this.auth = auth
|
||||
}, timeoutMs)
|
||||
this.reset()
|
||||
// 登录失败的状态需要特别更改
|
||||
let auth = { token: '', status: AuthStatus.Fail }
|
||||
this.auth = auth
|
||||
})
|
||||
},
|
||||
async logout() {
|
||||
@ -112,22 +176,18 @@ export const useUserStore = defineStore('userStore', {
|
||||
this.auth.status = AuthStatus.Checking
|
||||
await checkApi()
|
||||
.then((resp) => {
|
||||
setTimeout(() => {
|
||||
let auth = { token: resp.data.token, status: AuthStatus.Succ }
|
||||
this.auth = auth
|
||||
Local.set(storeKey, auth)
|
||||
this.getUserinfo()
|
||||
succ()
|
||||
}, timeoutMs)
|
||||
let auth = { token: resp.data.token, status: AuthStatus.Succ }
|
||||
this.auth = auth
|
||||
Local.set(storeKey, auth)
|
||||
this.getUserinfo()
|
||||
succ()
|
||||
})
|
||||
.catch((_error) => {
|
||||
setTimeout(() => {
|
||||
this.reset()
|
||||
// 登录失败的状态需要特别更改
|
||||
let auth = { token: '', status: AuthStatus.Wait }
|
||||
this.auth = auth
|
||||
fail()
|
||||
}, timeoutMs)
|
||||
this.reset()
|
||||
// 登录失败的状态需要特别更改
|
||||
let auth = { token: '', status: AuthStatus.Wait }
|
||||
this.auth = auth
|
||||
fail()
|
||||
})
|
||||
},
|
||||
/**
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<div class="article-backup-root">
|
||||
<!-- 标题 -->
|
||||
<div class="info-title">
|
||||
<div class="iconbl bl-dizhicuowu"></div>
|
||||
博客地址配置方式
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { formatFileSize } from '@renderer/assets/utils/util'
|
||||
import { articleBackupListApi, articleBackupApi, articleBackupDownloadFragmentApi, articleBackupDownloadFragmentHeadApi } from '@renderer/api/blossom'
|
||||
import type { BackupFile } from '@renderer/api/blossom'
|
||||
import Notify from '@renderer/scripts/notify'
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '@renderer/assets/styles/bl-dialog-info';
|
||||
|
||||
.article-backup-root {
|
||||
border-radius: 10px;
|
||||
@include box(100%, 100%);
|
||||
|
||||
.content {
|
||||
@include box(100%, calc(100% - 50px));
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -166,8 +166,8 @@ const renderChart = () => {
|
||||
if (!params.data.inner) {
|
||||
url = `<div>地址: <a target="_blank" href="${params.data.artUrl}">${params.data.artUrl}</a></div>`
|
||||
} else {
|
||||
url = `<div>地址: <a target="_blank" href="${userStore.userinfo.params.WEB_ARTICLE_URL + params.data.artId}">${
|
||||
userStore.userinfo.params.WEB_ARTICLE_URL + params.data.artId
|
||||
url = `<div>地址: <a target="_blank" href="${userStore.userinfo.userParams.WEB_ARTICLE_URL + params.data.artId}">${
|
||||
userStore.userinfo.userParams.WEB_ARTICLE_URL + params.data.artId
|
||||
}</a></div>`
|
||||
}
|
||||
return `<div class="chart-graph-article-ref-tooltip">
|
||||
|
||||
@ -184,14 +184,7 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 二维码 -->
|
||||
<el-dialog
|
||||
v-model="isShowQrCodeDialog"
|
||||
width="335"
|
||||
top="100px"
|
||||
:append-to-body="true"
|
||||
:destroy-on-close="true"
|
||||
:close-on-click-modal="false"
|
||||
draggable>
|
||||
<el-dialog v-model="isShowQrCodeDialog" width="335" :append-to-body="true" :destroy-on-close="true" :close-on-click-modal="false" draggable>
|
||||
<ArticleQrCode ref="ArticleQrCodeRef"></ArticleQrCode>
|
||||
</el-dialog>
|
||||
|
||||
@ -253,7 +246,7 @@ import ArticleImport from './ArticleImport.vue'
|
||||
import { useLifecycle } from '@renderer/scripts/lifecycle'
|
||||
|
||||
const server = useServerStore()
|
||||
const { userinfo } = useUserStore()
|
||||
const user = useUserStore()
|
||||
const { viewStyle } = useConfigStore()
|
||||
const route = useRoute()
|
||||
|
||||
@ -443,13 +436,13 @@ const openArticleWindow = () => {
|
||||
* @param open: 生成链接后是否直接打开
|
||||
*/
|
||||
const createUrl = (type: 'open' | 'copy' | 'link' | 'tempVisit', open: boolean = false) => {
|
||||
let url: string = userinfo.params.WEB_ARTICLE_URL + curDoc.value.i
|
||||
let url: string = user.userParams.WEB_ARTICLE_URL + curDoc.value.i
|
||||
if (type === 'open') {
|
||||
openExtenal(url)
|
||||
} else if (type === 'copy') {
|
||||
writeText(url)
|
||||
} else if (type === 'link') {
|
||||
url = `[${curDoc.value.n}](${userinfo.params.WEB_ARTICLE_URL + curDoc.value.i} "${grammar}${curDoc.value.i}${grammar}")`
|
||||
url = `[${curDoc.value.n}](${user.userParams.WEB_ARTICLE_URL + curDoc.value.i} "${grammar}${curDoc.value.i}${grammar}")`
|
||||
writeText(url)
|
||||
} else if (type === 'tempVisit') {
|
||||
articleTempKey({ id: curDoc.value.i }).then((resp) => {
|
||||
@ -536,13 +529,16 @@ const syncDoc = () => {
|
||||
/** 删除文档 */
|
||||
const delDoc = () => {
|
||||
let type = curDoc.value.ty === 3 ? '文章' : '文件夹'
|
||||
ElMessageBox.confirm(`是否确定删除${type}: <span style="color:#C02B2B;text-decoration: underline;">${curDoc.value.n}</span>?删除后的文章可在回收站中查看。`, {
|
||||
confirmButtonText: '确定删除',
|
||||
cancelButtonText: '我再想想',
|
||||
type: 'info',
|
||||
draggable: true,
|
||||
dangerouslyUseHTMLString: true
|
||||
}).then(() => {
|
||||
ElMessageBox.confirm(
|
||||
`是否确定删除${type}: <span style="color:#C02B2B;text-decoration: underline;">${curDoc.value.n}</span>?删除后的文章可在回收站中查看。`,
|
||||
{
|
||||
confirmButtonText: '确定删除',
|
||||
cancelButtonText: '我再想想',
|
||||
type: 'info',
|
||||
draggable: true,
|
||||
dangerouslyUseHTMLString: true
|
||||
}
|
||||
).then(() => {
|
||||
if (curDoc.value.ty === 3) {
|
||||
articleDelApi({ id: curDoc.value.i }).then((_resp) => {
|
||||
Notify.success(`删除文章成功`)
|
||||
|
||||
@ -19,7 +19,7 @@ export const keymaps = {
|
||||
|
||||
blockquote: isMac ? '>' : '>',
|
||||
code: isMac ? 'Cmd + E' : 'Alt + E',
|
||||
pre: isMac ? 'Ctrl + Cmd + S' : 'Ctrl + Alt + E',
|
||||
pre: isMac ? 'Ctrl + Cmd + E' : 'Ctrl + Alt + E',
|
||||
|
||||
table: isMac ? 'Cmd + T' : 'Alt + T',
|
||||
image: isMac ? 'Cmd + M' : 'Alt + M',
|
||||
|
||||
@ -62,7 +62,7 @@ const toRoute = (articleId: number) => {
|
||||
|
||||
const toWebview = (article: any) => {
|
||||
if (article.openStatus === 1) {
|
||||
openExtenal(userStore.userinfo.params.WEB_ARTICLE_URL + article.id)
|
||||
openExtenal(userStore.userinfo.userParams.WEB_ARTICLE_URL + article.id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,58 +0,0 @@
|
||||
<template>
|
||||
<div class="index-footer-root">
|
||||
<el-popover placement="top-start" :width="350" trigger="hover" :show-after="100" :hide-after="300">
|
||||
<template #reference>
|
||||
<div class="operator-buttons">
|
||||
<el-radio-group v-model="copyType" class="copy-type-radio">
|
||||
<el-radio-button label="http">HT</el-radio-button>
|
||||
<el-radio-button label="markdown">MD</el-radio-button>
|
||||
<el-radio-button label="binary">01</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-button class="iconbl bl-copy-line" />
|
||||
</div>
|
||||
</template>
|
||||
<el-input :suffix-icon="Link" placeholder="截图后可查看图片链接..." disabled>
|
||||
<template #prepend>
|
||||
<el-button class="iconbl bl-copy-line" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-popover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { Link } from '@element-plus/icons-vue';
|
||||
|
||||
const copyType = ref('markdown')
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.index-footer-root {
|
||||
@include box(100%, 100%);
|
||||
@include flex(row, space-around, center);
|
||||
font-size: 12px;
|
||||
-webkit-app-region: drag;
|
||||
|
||||
.operator-buttons {
|
||||
@include flex(row, flex-end, center);
|
||||
|
||||
.copy-type-radio {
|
||||
margin-right: 10px;
|
||||
|
||||
:deep(.el-radio-button__inner) {
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.el-input {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
@ -57,8 +57,11 @@
|
||||
</ol>
|
||||
|
||||
<p class="paragraph">
|
||||
更多内容,可前往<a :href="CONFIG.SYS.GITHUB_REPO" target="_blank">源码仓库</a>、<a :href="CONFIG.SYS.DOC" target="_blank">查看文档</a
|
||||
>、或联系作者<span style="font-size: 13px">({{ CONFIG.SYS.CONTACT }})</span>。
|
||||
更多内容,可前往<a :href="CONFIG.SYS.GITHUB_REPO" target="_blank">源码仓库</a>、<a :href="CONFIG.SYS.DOC" target="_blank">查看文档</a>、或<a
|
||||
:href="CONFIG.SYS.CONTACT"
|
||||
target="_blank"
|
||||
>联系作者</a
|
||||
>。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -120,8 +123,8 @@ const developer = [
|
||||
|
||||
.project-name {
|
||||
@include font(50px, 500);
|
||||
@include themeColor(#2b2b2b, #e4e4e4);
|
||||
@include themeText(2px 2px 5px #878787, 2px 2px 5px #000000);
|
||||
color: var(--el-color-primary);
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@ -7,6 +7,9 @@
|
||||
<el-tab-pane label="服务器配置" :lazy="true">
|
||||
<div class="tab-content"><ConfigServer></ConfigServer></div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="博客配置" :lazy="true">
|
||||
<div class="tab-content"><ConfigBlog></ConfigBlog></div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="修改个人信息" :lazy="true">
|
||||
<div class="tab-content"><ConfigUserinfo></ConfigUserinfo></div>
|
||||
</el-tab-pane>
|
||||
@ -28,6 +31,7 @@ import ConfigUpdPwd from './SettingConfigUpdPwd.vue'
|
||||
import ConfigAddUser from './SettingConfigAddUser.vue'
|
||||
import ConfigClient from './SettingConfigClient.vue'
|
||||
import ConfigServer from './SettingConfigServer.vue'
|
||||
import ConfigBlog from './SettingConfigBlog.vue'
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div class="config-root" v-loading="auth.status !== '已登录'" element-loading-spinner="none" element-loading-text="请登录后使用博客设置...">
|
||||
<div class="title">博客配置</div>
|
||||
<div class="desc">博客配置,若无内容请点击右侧刷新。<el-button @click="refreshParam" text bg>刷新</el-button></div>
|
||||
|
||||
<el-form v-if="auth.status == '已登录'" :model="userParamForm" label-position="right" label-width="130px" style="max-width: 800px">
|
||||
<el-form-item label="文章查看地址" :required="true">
|
||||
<el-input
|
||||
size="default"
|
||||
v-model="userParamForm.WEB_ARTICLE_URL"
|
||||
@change="(cur: any) => updParam('WEB_ARTICLE_URL', cur)"
|
||||
style="width: calc(100% - 100px)"></el-input>
|
||||
<el-button size="default" style="width: 90px; margin-left: 10px">访问测试</el-button>
|
||||
<div class="conf-tip">网页端博客的访问地址,如果不使用博客可不配置。需以<code>/#/articles?articleId=</code>结尾。</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>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="博客LOGO地址">
|
||||
<el-input size="default" v-model="userParamForm.WEB_LOGO_URL" @change="(cur: any) => updParam('WEB_LOGO_URL', cur)"></el-input>
|
||||
<div class="conf-tip">博客左上角 Logo 的访问地址。</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="IPC备案号">
|
||||
<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">如果博客作为你的域名首页,你可能需要配置 IPC 备案号</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="公网安备号">
|
||||
<el-input
|
||||
size="default"
|
||||
v-model="userParamForm.WEB_GONG_WANG_AN_BEI"
|
||||
@change="(cur: any) => updParam('WEB_GONG_WANG_AN_BEI', cur)"></el-input>
|
||||
<div class="conf-tip">如果博客作为你的域名首页,你可能需要配置公网安备号</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="server-config">
|
||||
{{ userinfoJson }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onActivated, onMounted, ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useUserStore } from '@renderer/stores/user'
|
||||
import { userParamListApi, userParamUpdApi, userParamRefreshApi } from '@renderer/api/blossom'
|
||||
import { formatJson } from '@renderer/assets/utils/util'
|
||||
import Notify from '@renderer/scripts/notify'
|
||||
|
||||
onMounted(() => {
|
||||
getParamList()
|
||||
})
|
||||
|
||||
onActivated(() => {
|
||||
getParamList()
|
||||
})
|
||||
|
||||
const userStore = useUserStore()
|
||||
const { userinfo, auth } = storeToRefs(userStore)
|
||||
|
||||
const userParamForm = ref({
|
||||
WEB_ARTICLE_URL: '',
|
||||
WEB_IPC_BEI_AN_HAO: '',
|
||||
WEB_LOGO_NAME: '',
|
||||
WEB_LOGO_URL: '',
|
||||
WEB_GONG_WANG_AN_BEI: '',
|
||||
WEB_BLOG_URL_ERROR_TIP_SHOW: ''
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取参数列表
|
||||
*/
|
||||
const getParamList = () => {
|
||||
userParamListApi().then((resp) => {
|
||||
userParamForm.value = resp.data
|
||||
})
|
||||
}
|
||||
|
||||
const refreshParam = () => {
|
||||
userParamRefreshApi().then((_) => {
|
||||
Notify.success('刷新参数成功', '刷新成功')
|
||||
getParamList()
|
||||
userStore.getUserinfo()
|
||||
})
|
||||
}
|
||||
|
||||
const updParam = (paramName: string, paramValue: string) => {
|
||||
userParamUpdApi({ paramName: paramName, paramValue: paramValue }).then((_resp) => {
|
||||
userStore.getUserinfo()
|
||||
})
|
||||
}
|
||||
|
||||
const userinfoJson = computed(() => {
|
||||
return formatJson(userinfo.value)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import './styles/config-root.scss';
|
||||
|
||||
.server-config {
|
||||
padding: 10px;
|
||||
font-size: 12px;
|
||||
white-space: pre;
|
||||
color: var(--bl-text-color-light);
|
||||
}
|
||||
</style>
|
||||
@ -3,14 +3,14 @@
|
||||
<div class="title">
|
||||
客户端配置<span class="version">{{ CONFIG.SYS.VERSION }}</span>
|
||||
</div>
|
||||
<div class="desc">Blossom 桌面客户端配置</div>
|
||||
<div class="desc">桌面客户端配置</div>
|
||||
|
||||
<el-form label-position="right" label-width="130px" style="max-width: 800px">
|
||||
<bl-row just="flex-start" class="config-module-titile"><span class="iconbl bl-a-texteditorhighlightcolor-line"></span>文章设置</bl-row>
|
||||
<el-form-item label="编辑器字体">
|
||||
<el-input v-model="configEditorStyleForm.fontFamily" size="default" @input="changeEditorStyle"></el-input>
|
||||
<div class="conf-tip">
|
||||
会影响 Markdown 编辑器、预览页面、新窗口预览、编辑历史中的正文字体样式。中英文等宽字体在表格中会有更好的样式表现,如:
|
||||
Markdown 编辑器、预览页面、新窗口预览、编辑历史中的正文字体样式。中英文等宽字体在表格中会有更好的样式表现,如:
|
||||
<a href="https://github.com/be5invis/Sarasa-Gothic" target="_blank">更纱黑体(Sarasa Fixed CL)</a>。
|
||||
</div>
|
||||
</el-form-item>
|
||||
@ -19,19 +19,19 @@
|
||||
<el-input v-model="configEditorStyleForm.fontSize" size="default" @input="changeEditorStyle">
|
||||
<template #append>单位 px</template>
|
||||
</el-input>
|
||||
<div class="conf-tip">会影响 Markdown 编辑器、预览页面、新窗口预览、编辑历史中的正文字体大小。</div>
|
||||
<div class="conf-tip">Markdown 编辑器、预览页面、新窗口预览、编辑历史中的正文字体大小。</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="文档菜单字体大小">
|
||||
<el-input v-model="configViewStyleForm.treeDocsFontSize" size="default" @input="changeViewStyle">
|
||||
<template #append>单位 px</template>
|
||||
</el-input>
|
||||
<div class="conf-tip">会影响文章、照片墙功能中左侧树状菜单的字体大小。</div>
|
||||
<div class="conf-tip">文章、照片墙功能中左侧树状菜单的字体大小。</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="代码块默认语言">
|
||||
<el-input v-model="configEditorStyleForm.defaultPreLanguage" size="default" @input="changeEditorStyle"> </el-input>
|
||||
<div class="conf-tip">通过快捷键或者操作按钮生成多行代码块<code>```</code>时的默认语言。</div>
|
||||
<div class="conf-tip">通过快捷键或者工具栏按钮生成多行代码块<code>```</code>时的默认语言。</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="显示代码块行数">
|
||||
|
||||
@ -3,12 +3,20 @@
|
||||
<div class="title">
|
||||
服务器配置<span class="version" v-if="isNotBlank(serverParamForm.serverVersion)">{{ 'v' + serverParamForm.serverVersion }}</span>
|
||||
</div>
|
||||
<div class="desc">Blossom 服务器配置,若无内容请点击右侧刷新。<el-button @click="refreshParam" text bg>刷新</el-button></div>
|
||||
<div class="desc">服务器配置,若无内容请点击右侧刷新。<el-button @click="refreshParam" text bg>刷新</el-button></div>
|
||||
|
||||
<el-form v-if="auth.status == '已登录'" :model="serverParamForm" label-position="right" label-width="130px" style="max-width: 800px">
|
||||
<el-form-item label="网页端地址">
|
||||
<!-- <el-form-item label="网页端地址">
|
||||
<el-input size="default" v-model="serverParamForm.WEB_ARTICLE_URL" @change="(cur: any) => updParam('WEB_ARTICLE_URL', cur)"></el-input>
|
||||
<div class="conf-tip">网页端博客的访问地址,如果不使用博客可不配置。需以<code>/#/articles?articleId=</code>结尾。</div>
|
||||
</el-form-item> -->
|
||||
|
||||
<el-form-item label="文件访问地址" :required="true">
|
||||
<el-input
|
||||
size="default"
|
||||
v-model="serverParamForm.BLOSSOM_OBJECT_STORAGE_DOMAIN"
|
||||
@change="(cur: any) => updParam('BLOSSOM_OBJECT_STORAGE_DOMAIN', cur)"></el-input>
|
||||
<div class="conf-tip">文件访问地址。需以<code>/pic</code>结尾。</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备份文件路径">
|
||||
@ -124,6 +132,7 @@ const serverParamForm = ref({
|
||||
ARTICLE_RECYCLE_EXP_DAYS: '',
|
||||
BACKUP_EXP_DAYS: '',
|
||||
HEFENG_KEY: '',
|
||||
BLOSSOM_OBJECT_STORAGE_DOMAIN: '',
|
||||
SERVER_MACHINE_EXPIRE: '',
|
||||
SERVER_DATABASE_EXPIRE: '',
|
||||
SERVER_DOMAIN_EXPIRE: '',
|
||||
|
||||
@ -35,7 +35,7 @@ import CONFIG from '@renderer/assets/constants/system'
|
||||
<style scoped lang="scss">
|
||||
.setting-index-root {
|
||||
@include box(100%, 100%);
|
||||
background-image: linear-gradient(145deg, var(--bl-html-color) 0%, var(--bl-html-color) 55%, var(--el-color-primary-light-5));
|
||||
background-image: linear-gradient(145deg, transparent 0%, transparent 55%, var(--el-color-primary-light-5));
|
||||
padding: 50px 0 0 50px;
|
||||
z-index: 2;
|
||||
|
||||
@ -68,7 +68,7 @@ import CONFIG from '@renderer/assets/constants/system'
|
||||
}
|
||||
|
||||
.version {
|
||||
@include themeColor(#FFFFFF, #9B9B9B);
|
||||
@include themeColor(#ffffff, #9b9b9b);
|
||||
@include font(13px, 300);
|
||||
@include absolute('', 10px, 10px, '');
|
||||
z-index: 2;
|
||||
|
||||
@ -0,0 +1,251 @@
|
||||
<template>
|
||||
<div class="quick-setting-root">
|
||||
<el-steps :active="activeSetp" align-center>
|
||||
<el-step title="文件" description="文件访问地址配置">
|
||||
<template #icon>
|
||||
<div class="iconbl bl-image--line"></div>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step title="博客" description="博客地址配置">
|
||||
<template #icon>
|
||||
<div class="iconbl bl-blog"></div>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step title="完成">
|
||||
<template #icon>
|
||||
<div class="iconbl bl-check"></div>
|
||||
</template>
|
||||
</el-step>
|
||||
</el-steps>
|
||||
<!--
|
||||
|
||||
|
||||
|
||||
|
||||
-->
|
||||
<div class="step-detail" v-if="activeSetp === 1">
|
||||
<div class="row">下方是否为您在登录页面添加的地址。</div>
|
||||
<div class="row">若不是,请在登录页重新登录。</div>
|
||||
<div class="row server-url">{{ server.serverUrl }}</div>
|
||||
|
||||
<div class="row">
|
||||
<el-button size="default" type="primary" plain @click="savePicture">是</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
|
||||
|
||||
|
||||
|
||||
-->
|
||||
<div class="step-detail blog-detail" v-if="activeSetp === 2">
|
||||
<div class="detail">
|
||||
<div class="row">您选择使用后台自带博客, 还是自己独立部署博客?</div>
|
||||
<div class="row" just="center">
|
||||
<el-button size="default" :type="blogType == 1 ? 'primary' : ''" @click="setBlogType(1)">自带博客</el-button>
|
||||
<el-button size="default" :type="blogType == 2 ? 'primary' : ''" @click="setBlogType(2)">独立部署</el-button>
|
||||
</div>
|
||||
<div v-if="blogType == 1" class="row blog-type">
|
||||
<div>
|
||||
自带博客只能作为用户ID为1的用户使用,若想修改,请查看<a
|
||||
href="https://www.wangyunf.com/blossom-doc/guide/deploy/blog.html#update-config"
|
||||
target="_blank"
|
||||
>修改方法<span class="iconbl bl-sendmail-line"></span></a
|
||||
>。
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="blogType == 2" class="row blog-type">
|
||||
<div style="font-size: 13px">
|
||||
填写博客地址,并以<code>/#/articles?articleId=</code>结尾
|
||||
<el-tooltip effect="light" content="复制地址结尾" placement="top">
|
||||
<span class="iconbl bl-copy-line" @click="writeText(URL_SUFFIX)"></span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<bl-row>
|
||||
<el-input type="textarea" :rows="2" resize="none" v-model="blogUrl" placeholder="请填写博客地址..." @input="blogUrlChange"></el-input>
|
||||
</bl-row>
|
||||
<div class="blog-url-error">
|
||||
<span v-show="blogUrlError">博客地址格式错误!</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 20px">
|
||||
<el-button size="default" text @click="last(1)">上一步</el-button>
|
||||
<el-button size="default" type="primary" @click="saveBlog" plain>确认使用{{ blogType === 1 ? '自带博客' : '独立部署' }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="iframe-container">
|
||||
<bl-row v-if="isBlank(blogUrlPreview)" class="iframe-placeholder" just="center">请填写博客地址</bl-row>
|
||||
<iframe v-else :src="blogUrlPreview" width="100%"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step-detail" v-if="activeSetp === 3">
|
||||
<img style="width: 200px" src="@renderer/assets/imgs/plant/杨桃.svg" />
|
||||
<div class="row">配置完成,</div>
|
||||
<div class="row">
|
||||
<el-button size="default" type="primary" plain @click="savePicture">开始!</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
import { useServerStore } from '@renderer/stores/server'
|
||||
import { isBlank } from '@renderer/assets/utils/obj'
|
||||
import { writeText } from '@renderer/assets/utils/electron'
|
||||
|
||||
const server = useServerStore()
|
||||
const activeSetp = ref(1)
|
||||
|
||||
const last = (active: number) => {
|
||||
activeSetp.value = active
|
||||
}
|
||||
|
||||
const savePicture = () => {
|
||||
activeSetp.value = 2
|
||||
}
|
||||
|
||||
const URL_SUFFIX_SERVER = '/blog/#/articles?articleId='
|
||||
const URL_SUFFIX = '/#/articles?articleId='
|
||||
const previewId = -123
|
||||
const blogType = ref<1 | 2>(1)
|
||||
const blogUrl = ref('')
|
||||
const blogUrlError = ref(false)
|
||||
|
||||
/**
|
||||
* 预览页面
|
||||
*/
|
||||
const blogUrlPreview = computed(() => {
|
||||
console.log(blogUrl.value)
|
||||
|
||||
if (blogType.value == 1) {
|
||||
return server.serverUrl + URL_SUFFIX_SERVER + previewId
|
||||
} else if (isBlank(blogUrl.value) || (!blogUrl.value.startsWith('http://') && !blogUrl.value.startsWith('https://'))) {
|
||||
return ''
|
||||
} else if (blogUrl.value.endsWith(URL_SUFFIX)) {
|
||||
return blogUrl.value + previewId
|
||||
}
|
||||
|
||||
return blogUrl.value
|
||||
})
|
||||
|
||||
const setBlogType = (type: 1 | 2) => {
|
||||
blogType.value = type
|
||||
}
|
||||
|
||||
const blogUrlChange = (val) => {
|
||||
blogUrl.value = ''
|
||||
blogUrlError.value = false
|
||||
nextTick(() => {
|
||||
blogUrl.value = val
|
||||
})
|
||||
}
|
||||
|
||||
const saveBlog = () => {
|
||||
if (blogType.value === 2 && !blogUrl.value.endsWith(URL_SUFFIX)) {
|
||||
blogUrlError.value = true
|
||||
return
|
||||
}
|
||||
activeSetp.value = 3
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.quick-setting-root {
|
||||
padding: 20px 10px 0 10px;
|
||||
.el-steps {
|
||||
--el-bg-color: var(--bl-dialog-bg-color);
|
||||
.iconbl {
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-bottom: 15px;
|
||||
&:last-child {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.step-detail {
|
||||
@include font(14px, 300);
|
||||
padding: 35px 20px 20px 20px;
|
||||
text-align: center;
|
||||
|
||||
.server-url {
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
background-color: var(--bl-preview-code-bg-color);
|
||||
color: var(--bl-preview-code-color);
|
||||
}
|
||||
|
||||
.blog-type {
|
||||
@include flex(column, space-around, center);
|
||||
@include box(100%, 100px);
|
||||
padding: 5px;
|
||||
border-radius: 6px;
|
||||
border: 1px dashed var(--el-border-color);
|
||||
background-color: var(--bl-preview-code-bg-color);
|
||||
}
|
||||
|
||||
.blog-url-error {
|
||||
height: 16px;
|
||||
font-size: 12px;
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
.bl-sendmail-line {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.bl-copy-line {
|
||||
font-size: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bl-refresh-smile {
|
||||
font-size: 50px;
|
||||
}
|
||||
|
||||
code {
|
||||
color: var(--el-color-primary);
|
||||
font-size: 13px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.blog-detail {
|
||||
@include flex(row, space-around, center);
|
||||
padding-top: 0;
|
||||
|
||||
.detail {
|
||||
@include flex(column, flex-start, center);
|
||||
@include box(400px, auto, 400px, 400px);
|
||||
}
|
||||
|
||||
.iframe-container {
|
||||
@include box(240px, 480px);
|
||||
position: relative;
|
||||
|
||||
.iframe-placeholder {
|
||||
@include box(240px, 480px);
|
||||
color: var(--bl-text-color-light);
|
||||
border: 1px solid var(--el-border-color);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
iframe {
|
||||
height: 800px;
|
||||
width: 400px;
|
||||
transform: scale(0.6);
|
||||
position: absolute;
|
||||
left: -80px;
|
||||
top: -160px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="picture-cant-show-tip-root">
|
||||
<div class="info-title">
|
||||
<div class="iconbl bl-delete-line"></div>
|
||||
<div class="iconbl bl-a-picturecracked-line"></div>
|
||||
图片无法显示的解决方式
|
||||
</div>
|
||||
<div class="content">
|
||||
|
||||
23
blossom-web/src/scripts/lifecycle.ts
Normal file
23
blossom-web/src/scripts/lifecycle.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { onActivated, onMounted } from 'vue'
|
||||
|
||||
/**
|
||||
* 初始化时生命周期封装, 主要控制 mounted 和 activated 只执行一次
|
||||
* @param mounted
|
||||
* @param activated
|
||||
*/
|
||||
export const useLifecycle = (mounted: Function, activated: Function) => {
|
||||
let isMounted = false
|
||||
|
||||
onMounted(() => {
|
||||
if (!isMounted) {
|
||||
mounted()
|
||||
}
|
||||
})
|
||||
|
||||
onActivated(() => {
|
||||
if (isMounted) {
|
||||
activated()
|
||||
}
|
||||
isMounted = true
|
||||
})
|
||||
}
|
||||
@ -125,28 +125,33 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ref, onActivated, onUnmounted, onMounted } from 'vue'
|
||||
import { ref, onUnmounted } from 'vue'
|
||||
import { ArrowDownBold, ArrowRightBold } from '@element-plus/icons-vue'
|
||||
import { articleInfoOpenApi, articleInfoApi, docTreeOpenApi, docTreeApi } from '@/api/blossom'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { isNull, isEmpty, isNotNull } from '@/assets/utils/obj'
|
||||
import DocTitle from './DocTitle.vue'
|
||||
import { useLifecycle } from '@/scripts/lifecycle'
|
||||
import 'katex/dist/katex.min.css'
|
||||
|
||||
const userStore = useUserStore()
|
||||
useLifecycle(
|
||||
() => {
|
||||
window.onHtmlEventDispatch = onHtmlEventDispatch
|
||||
getRouteQueryParams()
|
||||
window.addEventListener('resize', onresize)
|
||||
initStyle()
|
||||
},
|
||||
() => {
|
||||
getRouteQueryParams()
|
||||
window.addEventListener('resize', onresize)
|
||||
initStyle()
|
||||
}
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
window.onHtmlEventDispatch = onHtmlEventDispatch
|
||||
getRouteQueryParams()
|
||||
window.addEventListener('resize', onresize)
|
||||
initStyle()
|
||||
})
|
||||
// onMounted(() => {})
|
||||
|
||||
onActivated(() => {
|
||||
getRouteQueryParams()
|
||||
window.addEventListener('resize', onresize)
|
||||
initStyle()
|
||||
})
|
||||
// onActivated(() => {})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', onresize)
|
||||
@ -227,6 +232,12 @@ const clickCurDoc = async (tree: DocTree) => {
|
||||
* 如果点击的是文章, 则查询文章信息和正文, 并在编辑器中显示.
|
||||
*/
|
||||
const getCurEditArticle = async (id: number) => {
|
||||
if (id == -123) {
|
||||
article.value.html = `<div style="color:#C6C6C6;font-weight: 300;width:100%;height:300px;padding:0 20px;display:flex;justify-content: center;
|
||||
align-items: center;text-align:center;font-size:25px;">如果您看到这句话, 证明博客验证成功</div>`
|
||||
return
|
||||
}
|
||||
|
||||
const then = (resp: any) => {
|
||||
if (isNull(resp.data)) return
|
||||
article.value = resp.data
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user