refactor: 重构偏好模块.
This commit is contained in:
@@ -517,7 +517,7 @@ public class RedisMaps extends RedisUtils {
|
||||
* @param <V> V
|
||||
* @return entity
|
||||
*/
|
||||
public static <K, V> Map<String, V> entitiesJson(String key, Class<V> clazz) {
|
||||
public static <V> Map<String, V> entitiesJson(String key, Class<V> clazz) {
|
||||
return entitiesJson(key, Function.identity(), clazz);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
package com.orion.ops.module.infra.handler.preference.model;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.orion.lang.define.wrapper.Ref;
|
||||
import com.orion.lang.utils.collect.Maps;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 偏好
|
||||
@@ -18,8 +23,9 @@ public interface PreferenceModel {
|
||||
*
|
||||
* @return map
|
||||
*/
|
||||
default Map<String, Object> toMap() {
|
||||
return JSON.parseObject(JSON.toJSONString(this));
|
||||
default Map<String, String> toMap() {
|
||||
JSONObject map = JSON.parseObject(JSON.toJSONString(this));
|
||||
return Maps.map(map, Function.identity(), v -> JSON.toJSONString(Ref.of(v)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ Authorization: {{token}}
|
||||
|
||||
{
|
||||
"type": "SYSTEM",
|
||||
"config": {
|
||||
}
|
||||
"item": "",
|
||||
"value": ""
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package com.orion.ops.module.infra.controller;
|
||||
|
||||
import com.orion.lang.define.wrapper.HttpWrapper;
|
||||
import com.orion.ops.framework.web.core.annotation.RestWrapper;
|
||||
import com.orion.ops.module.infra.entity.request.preference.PreferenceUpdatePartialRequest;
|
||||
import com.orion.ops.module.infra.entity.request.preference.PreferenceUpdateRequest;
|
||||
import com.orion.ops.module.infra.entity.vo.PreferenceVO;
|
||||
import com.orion.ops.module.infra.service.PreferenceService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
@@ -12,6 +13,7 @@ import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 用户偏好 api
|
||||
@@ -33,21 +35,22 @@ public class PreferenceController {
|
||||
private PreferenceService preferenceService;
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新用户偏好-整体")
|
||||
@Operation(summary = "更新用户偏好-单个")
|
||||
public Integer updatePreference(@Validated @RequestBody PreferenceUpdateRequest request) {
|
||||
return preferenceService.updatePreference(request, false);
|
||||
return preferenceService.updatePreference(request);
|
||||
}
|
||||
|
||||
@PutMapping("/update-partial")
|
||||
@Operation(summary = "更新用户偏好-部分")
|
||||
public Integer updatePreferencePartial(@Validated @RequestBody PreferenceUpdateRequest request) {
|
||||
return preferenceService.updatePreference(request, true);
|
||||
public HttpWrapper<?> updatePreferencePartial(@Validated @RequestBody PreferenceUpdatePartialRequest request) {
|
||||
preferenceService.updatePreferencePartial(request);
|
||||
return HttpWrapper.ok();
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "查询用户偏好")
|
||||
@Parameter(name = "type", description = "type", required = true)
|
||||
public PreferenceVO getPreference(@RequestParam("type") String type) {
|
||||
public Map<String, Object> getPreference(@RequestParam("type") String type) {
|
||||
return preferenceService.getPreferenceByType(type);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.orion.ops.module.infra.convert;
|
||||
|
||||
import com.orion.ops.module.infra.entity.domain.PreferenceDO;
|
||||
import com.orion.ops.module.infra.entity.request.preference.PreferenceUpdateRequest;
|
||||
import com.orion.ops.module.infra.entity.vo.PreferenceVO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* 用户偏好 内部对象转换器
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023-9-27 18:37
|
||||
*/
|
||||
@Mapper
|
||||
public interface PreferenceConvert {
|
||||
|
||||
PreferenceConvert MAPPER = Mappers.getMapper(PreferenceConvert.class);
|
||||
|
||||
@Mapping(target = "config", ignore = true)
|
||||
PreferenceDO to(PreferenceUpdateRequest request);
|
||||
|
||||
@Mapping(target = "config", ignore = true)
|
||||
PreferenceVO to(PreferenceDO domain);
|
||||
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.orion.ops.module.infra.define.cache;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.orion.lang.define.cache.key.CacheKeyBuilder;
|
||||
import com.orion.lang.define.cache.key.CacheKeyDefine;
|
||||
import com.orion.lang.define.cache.key.struct.RedisCacheStruct;
|
||||
import com.orion.lang.define.wrapper.Ref;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -19,8 +19,8 @@ public interface PreferenceCacheKeyDefine {
|
||||
CacheKeyDefine PREFERENCE = new CacheKeyBuilder()
|
||||
.key("user:preference:{}:{}")
|
||||
.desc("用户偏好 ${userId} ${type}")
|
||||
.type(JSONObject.class)
|
||||
.struct(RedisCacheStruct.STRING)
|
||||
.type(Ref.class)
|
||||
.struct(RedisCacheStruct.HASH)
|
||||
.timeout(1, TimeUnit.DAYS)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -38,8 +38,12 @@ public class PreferenceDO extends BaseDO {
|
||||
@TableField("type")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "偏好配置")
|
||||
@TableField("config")
|
||||
private String config;
|
||||
@Schema(description = "配置项")
|
||||
@TableField("item")
|
||||
private String item;
|
||||
|
||||
@Schema(description = "配置值")
|
||||
@TableField("value")
|
||||
private String value;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.orion.ops.module.infra.entity.request.preference;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 用户偏好 部分更新请求对象
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023-9-27 18:37
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "PreferenceUpdatePartialRequest", description = "用户偏好 部分更新请求对象")
|
||||
public class PreferenceUpdatePartialRequest implements Serializable {
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 12)
|
||||
@Schema(description = "类型")
|
||||
private String type;
|
||||
|
||||
@NotEmpty
|
||||
@Schema(description = "偏好配置")
|
||||
private Map<String, Object> config;
|
||||
|
||||
}
|
||||
@@ -7,10 +7,8 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 用户偏好 更新请求对象
|
||||
@@ -31,8 +29,12 @@ public class PreferenceUpdateRequest implements Serializable {
|
||||
@Schema(description = "类型")
|
||||
private String type;
|
||||
|
||||
@NotEmpty
|
||||
@NotBlank
|
||||
@Size(max = 32)
|
||||
@Schema(description = "偏好配置")
|
||||
private Map<String, Object> config;
|
||||
private String item;
|
||||
|
||||
@Schema(description = "偏好配置")
|
||||
private Object value;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.orion.ops.module.infra.entity.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 用户偏好 视图响应对象
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023-9-27 18:37
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "PreferenceVO", description = "用户偏好 视图响应对象")
|
||||
public class PreferenceVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "偏好配置")
|
||||
private Map<String, Object> config;
|
||||
|
||||
}
|
||||
@@ -17,7 +17,7 @@ public class TerminalPreferenceStrategy implements IPreferenceStrategy<TerminalP
|
||||
@Override
|
||||
public TerminalPreferenceModel getDefault() {
|
||||
return TerminalPreferenceModel.builder()
|
||||
.darkTheme("dark")
|
||||
.darkTheme("auto")
|
||||
.newConnectionType("group")
|
||||
.displaySetting(TerminalPreferenceModel.DisplaySettingModel.builder()
|
||||
.fontFamily("_")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.orion.ops.module.infra.service;
|
||||
|
||||
import com.orion.ops.module.infra.entity.request.preference.PreferenceUpdatePartialRequest;
|
||||
import com.orion.ops.module.infra.entity.request.preference.PreferenceUpdateRequest;
|
||||
import com.orion.ops.module.infra.entity.vo.PreferenceVO;
|
||||
import com.orion.ops.module.infra.enums.PreferenceTypeEnum;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -17,21 +17,27 @@ import java.util.concurrent.Future;
|
||||
public interface PreferenceService {
|
||||
|
||||
/**
|
||||
* 更新用户偏好
|
||||
* 更新用户偏好-单个
|
||||
*
|
||||
* @param request request
|
||||
* @param partial 是否为部分更新
|
||||
* @return effect
|
||||
*/
|
||||
Integer updatePreference(PreferenceUpdateRequest request, boolean partial);
|
||||
Integer updatePreference(PreferenceUpdateRequest request);
|
||||
|
||||
/**
|
||||
* 更新用户偏好-部分
|
||||
*
|
||||
* @param request request
|
||||
*/
|
||||
void updatePreferencePartial(PreferenceUpdatePartialRequest request);
|
||||
|
||||
/**
|
||||
* 查询用户偏好
|
||||
*
|
||||
* @param type type
|
||||
* @return row
|
||||
* @return rows
|
||||
*/
|
||||
PreferenceVO getPreferenceByType(String type);
|
||||
Map<String, Object> getPreferenceByType(String type);
|
||||
|
||||
/**
|
||||
* 获取用户偏好
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
package com.orion.ops.module.infra.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.orion.lang.define.wrapper.Ref;
|
||||
import com.orion.lang.function.Functions;
|
||||
import com.orion.lang.utils.collect.Maps;
|
||||
import com.orion.ops.framework.common.utils.Valid;
|
||||
import com.orion.ops.framework.redis.core.utils.RedisStrings;
|
||||
import com.orion.ops.framework.redis.core.utils.RedisMaps;
|
||||
import com.orion.ops.framework.security.core.utils.SecurityUtils;
|
||||
import com.orion.ops.module.infra.dao.PreferenceDAO;
|
||||
import com.orion.ops.module.infra.define.cache.PreferenceCacheKeyDefine;
|
||||
import com.orion.ops.module.infra.entity.domain.PreferenceDO;
|
||||
import com.orion.ops.module.infra.entity.request.preference.PreferenceUpdatePartialRequest;
|
||||
import com.orion.ops.module.infra.entity.request.preference.PreferenceUpdateRequest;
|
||||
import com.orion.ops.module.infra.entity.vo.PreferenceVO;
|
||||
import com.orion.ops.module.infra.enums.PreferenceTypeEnum;
|
||||
import com.orion.ops.module.infra.service.PreferenceService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -24,6 +25,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -41,51 +43,73 @@ public class PreferenceServiceImpl implements PreferenceService {
|
||||
private PreferenceDAO preferenceDAO;
|
||||
|
||||
@Override
|
||||
public Integer updatePreference(PreferenceUpdateRequest request, boolean partial) {
|
||||
public Integer updatePreference(PreferenceUpdateRequest request) {
|
||||
Long userId = SecurityUtils.getLoginUserId();
|
||||
String type = request.getType();
|
||||
String item = request.getItem();
|
||||
Valid.valid(PreferenceTypeEnum::of, type);
|
||||
// 查询
|
||||
PreferenceDO preference = preferenceDAO.of()
|
||||
.wrapper(this.buildQueryWrapper(userId, type))
|
||||
.createWrapper()
|
||||
.eq(PreferenceDO::getUserId, userId)
|
||||
.eq(PreferenceDO::getType, type)
|
||||
.eq(PreferenceDO::getItem, item)
|
||||
.then()
|
||||
.getOne();
|
||||
int effect;
|
||||
if (preference == null) {
|
||||
// 直接插入
|
||||
// 插入
|
||||
PreferenceDO insertRecord = new PreferenceDO();
|
||||
insertRecord.setUserId(userId);
|
||||
insertRecord.setType(type);
|
||||
insertRecord.setConfig(JSON.toJSONString(request.getConfig()));
|
||||
insertRecord.setItem(item);
|
||||
insertRecord.setValue(this.toJsonValue(request.getValue()));
|
||||
effect = preferenceDAO.insert(insertRecord);
|
||||
} else {
|
||||
// 更新
|
||||
PreferenceDO updateRecord = new PreferenceDO();
|
||||
updateRecord.setId(preference.getId());
|
||||
if (partial) {
|
||||
// 部分更新
|
||||
JSONObject config = JSON.parseObject(preference.getConfig());
|
||||
config.putAll(request.getConfig());
|
||||
updateRecord.setConfig(JSON.toJSONString(config));
|
||||
} else {
|
||||
// 全部更新
|
||||
updateRecord.setConfig(JSON.toJSONString(request.getConfig()));
|
||||
}
|
||||
updateRecord.setValue(this.toJsonValue(request.getValue()));
|
||||
effect = preferenceDAO.updateById(updateRecord);
|
||||
// 删除缓存
|
||||
RedisStrings.delete(PreferenceCacheKeyDefine.PREFERENCE.format(userId, type));
|
||||
}
|
||||
// 删除缓存
|
||||
RedisMaps.delete(PreferenceCacheKeyDefine.PREFERENCE.format(userId, type));
|
||||
return effect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreferenceVO getPreferenceByType(String type) {
|
||||
public void updatePreferencePartial(PreferenceUpdatePartialRequest request) {
|
||||
Long userId = SecurityUtils.getLoginUserId();
|
||||
String type = request.getType();
|
||||
Map<String, Object> config = request.getConfig();
|
||||
Valid.valid(PreferenceTypeEnum::of, type);
|
||||
// 删除配置
|
||||
LambdaQueryWrapper<PreferenceDO> wrapper = preferenceDAO.lambda()
|
||||
.eq(PreferenceDO::getUserId, userId)
|
||||
.eq(PreferenceDO::getType, type)
|
||||
.in(PreferenceDO::getItem, config.keySet());
|
||||
preferenceDAO.delete(wrapper);
|
||||
// 插入配置
|
||||
List<PreferenceDO> records = config.entrySet()
|
||||
.stream()
|
||||
.map(s -> {
|
||||
PreferenceDO insertRecord = new PreferenceDO();
|
||||
insertRecord.setUserId(userId);
|
||||
insertRecord.setType(type);
|
||||
insertRecord.setItem(s.getKey());
|
||||
insertRecord.setValue(this.toJsonValue(s.getValue()));
|
||||
return insertRecord;
|
||||
}).collect(Collectors.toList());
|
||||
preferenceDAO.insertBatch(records);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(PreferenceCacheKeyDefine.PREFERENCE.format(userId, type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getPreferenceByType(String type) {
|
||||
Long userId = SecurityUtils.getLoginUserId();
|
||||
PreferenceTypeEnum typeEnum = Valid.valid(PreferenceTypeEnum::of, type);
|
||||
Map<String, Object> config = this.getPreferenceByCache(userId, typeEnum);
|
||||
// 返回
|
||||
return PreferenceVO.builder()
|
||||
.config(config)
|
||||
.build();
|
||||
return this.getPreferenceByCache(userId, typeEnum);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -104,7 +128,7 @@ public class PreferenceServiceImpl implements PreferenceService {
|
||||
List<String> deleteKeys = Arrays.stream(PreferenceTypeEnum.values())
|
||||
.map(s -> PreferenceCacheKeyDefine.PREFERENCE.format(userId, s))
|
||||
.collect(Collectors.toList());
|
||||
RedisStrings.delete(deleteKeys);
|
||||
RedisMaps.delete(deleteKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,47 +142,58 @@ public class PreferenceServiceImpl implements PreferenceService {
|
||||
String typeValue = type.getType();
|
||||
// 查询缓存 用 string 防止数据类型丢失
|
||||
String key = PreferenceCacheKeyDefine.PREFERENCE.format(userId, type);
|
||||
Map<String, Object> config = RedisStrings.getJson(key);
|
||||
Map<String, String> config = RedisMaps.entities(key);
|
||||
boolean setCache = Maps.isEmpty(config);
|
||||
// 查询数据库
|
||||
if (Maps.isEmpty(config)) {
|
||||
config = preferenceDAO.of()
|
||||
.wrapper(this.buildQueryWrapper(userId, typeValue))
|
||||
.optionalOne()
|
||||
.map(PreferenceDO::getConfig)
|
||||
.map(JSON::parseObject)
|
||||
.orElse(null);
|
||||
.createWrapper()
|
||||
.eq(PreferenceDO::getUserId, userId)
|
||||
.eq(PreferenceDO::getType, type)
|
||||
.then()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(
|
||||
PreferenceDO::getItem,
|
||||
PreferenceDO::getValue,
|
||||
Functions.right())
|
||||
);
|
||||
}
|
||||
// 初始化
|
||||
if (Maps.isEmpty(config)) {
|
||||
// 获取默认值
|
||||
config = type.getStrategy()
|
||||
.getDefault()
|
||||
.toMap();
|
||||
// 插入
|
||||
PreferenceDO entity = new PreferenceDO();
|
||||
entity.setUserId(userId);
|
||||
entity.setType(typeValue);
|
||||
entity.setConfig(JSON.toJSONString(config));
|
||||
preferenceDAO.insert(entity);
|
||||
// 插入默认值
|
||||
List<PreferenceDO> entities = config
|
||||
.entrySet()
|
||||
.stream()
|
||||
.map(s -> {
|
||||
PreferenceDO entity = new PreferenceDO();
|
||||
entity.setUserId(userId);
|
||||
entity.setType(typeValue);
|
||||
entity.setItem(s.getKey());
|
||||
entity.setValue(s.getValue());
|
||||
return entity;
|
||||
}).collect(Collectors.toList());
|
||||
preferenceDAO.insertBatch(entities);
|
||||
}
|
||||
// 设置缓存
|
||||
if (setCache) {
|
||||
RedisStrings.setJson(key, PreferenceCacheKeyDefine.PREFERENCE, config);
|
||||
RedisMaps.putAll(key, PreferenceCacheKeyDefine.PREFERENCE, config);
|
||||
}
|
||||
return config;
|
||||
// unref
|
||||
return Maps.map(config, Function.identity(), v -> JSON.parseObject(v, Ref.class).getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询 wrapper
|
||||
* 转为 json 对象
|
||||
*
|
||||
* @param userId userId
|
||||
* @param type type
|
||||
* @return wrapper
|
||||
* @param o o
|
||||
* @return value
|
||||
*/
|
||||
private LambdaQueryWrapper<PreferenceDO> buildQueryWrapper(Long userId, String type) {
|
||||
return preferenceDAO.wrapper()
|
||||
.eq(PreferenceDO::getUserId, userId)
|
||||
.eq(PreferenceDO::getType, type);
|
||||
private String toJsonValue(Object o) {
|
||||
return JSON.toJSONString(Ref.of(o));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,12 +12,13 @@
|
||||
<result column="deleted" property="deleted"/>
|
||||
<result column="user_id" property="userId"/>
|
||||
<result column="type" property="type"/>
|
||||
<result column="config" property="config"/>
|
||||
<result column="item" property="item"/>
|
||||
<result column="value" property="value"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 通用查询结果列 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, user_id, type, config, create_time, update_time, creator, updater, deleted
|
||||
id, user_id, type, item, value, create_time, update_time, creator, updater, deleted
|
||||
</sql>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
import axios from 'axios';
|
||||
|
||||
type Preference = 'SYSTEM' | 'TERMINAL'
|
||||
type PreferenceType = 'SYSTEM' | 'TERMINAL'
|
||||
|
||||
/**
|
||||
* 用户偏好更新请求
|
||||
* 用户偏好更新请求-单个
|
||||
*/
|
||||
export interface PreferenceUpdateRequest {
|
||||
type: Preference;
|
||||
config: object;
|
||||
type: PreferenceType;
|
||||
item: string;
|
||||
value: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户偏好查询响应
|
||||
* 用户偏好更新请求-部分
|
||||
*/
|
||||
export interface PreferenceQueryResponse<T> {
|
||||
config: T;
|
||||
export interface PreferenceUpdatePartialRequest {
|
||||
type: PreferenceType;
|
||||
config: Record<string, any> | object;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户偏好-整体
|
||||
* 更新用户偏好-单个
|
||||
*/
|
||||
export function updatePreference(request: PreferenceUpdateRequest) {
|
||||
return axios.put('/infra/preference/update', request);
|
||||
@@ -27,14 +29,14 @@ export function updatePreference(request: PreferenceUpdateRequest) {
|
||||
/**
|
||||
* 更新用户偏好-部分
|
||||
*/
|
||||
export function updatePreferencePartial(request: PreferenceUpdateRequest) {
|
||||
export function updatePreferencePartial(request: PreferenceUpdatePartialRequest) {
|
||||
return axios.put('/infra/preference/update-partial', request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户偏好
|
||||
*/
|
||||
export function getPreference<T>(type: Preference) {
|
||||
return axios.get<PreferenceQueryResponse<T>>('/infra/preference/get', { params: { type } });
|
||||
export function getPreference<T>(type: PreferenceType) {
|
||||
return axios.get<T>('/infra/preference/get', { params: { type } });
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
import type { SelectOption } from '@arco-design/web-vue/es/select/interface';
|
||||
import { useAppStore } from '@/store';
|
||||
import FormWrapper from './form-wrapper.vue';
|
||||
import { updatePreferencePartial } from '@/api/user/preference';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { updatePreference } from '@/api/user/preference';
|
||||
|
||||
interface OptionsProps {
|
||||
name: string;
|
||||
@@ -61,20 +60,15 @@
|
||||
});
|
||||
}
|
||||
// 修改配置
|
||||
const updateConfig = { [key]: value };
|
||||
appStore.updateSettings(updateConfig);
|
||||
appStore.updateSettings({ [key]: value });
|
||||
// 同步偏好
|
||||
Message.clear();
|
||||
const loading = Message.loading('同步中...');
|
||||
try {
|
||||
await updatePreferencePartial({
|
||||
await updatePreference({
|
||||
type: 'SYSTEM',
|
||||
config: updateConfig
|
||||
item: key,
|
||||
value
|
||||
});
|
||||
Message.success('同步成功');
|
||||
} catch (e) {
|
||||
} finally {
|
||||
loading.close();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { TerminalDisplaySetting, TerminalPreference, TerminalState, TerminalThemeSchema } from './types';
|
||||
import { defineStore } from 'pinia';
|
||||
import { getPreference, updatePreferencePartial } from '@/api/user/preference';
|
||||
import { getPreference, updatePreference } from '@/api/user/preference';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { useDark, useDebounceFn } from '@vueuse/core';
|
||||
import { useDark } from '@vueuse/core';
|
||||
import { DEFAULT_SCHEMA } from '@/views/host-ops/terminal/types/terminal.theme';
|
||||
|
||||
// 暗色主题
|
||||
@@ -36,14 +36,14 @@ export default defineStore('terminal', {
|
||||
try {
|
||||
const { data } = await getPreference<TerminalPreference>('TERMINAL');
|
||||
// 设置默认终端主题
|
||||
if (!data.config.themeSchema?.name) {
|
||||
data.config.themeSchema = DEFAULT_SCHEMA;
|
||||
if (!data.themeSchema?.name) {
|
||||
data.themeSchema = DEFAULT_SCHEMA;
|
||||
}
|
||||
this.preference = data.config;
|
||||
this.preference = data;
|
||||
// 设置暗色主题
|
||||
const userDarkTheme = data.config.darkTheme;
|
||||
const userDarkTheme = data.darkTheme;
|
||||
if (userDarkTheme === DarkTheme.AUTO) {
|
||||
this.isDarkTheme = data.config.themeSchema?.dark === true;
|
||||
this.isDarkTheme = data.themeSchema?.dark === true;
|
||||
} else {
|
||||
this.isDarkTheme = userDarkTheme === DarkTheme.DARK;
|
||||
}
|
||||
@@ -53,7 +53,7 @@ export default defineStore('terminal', {
|
||||
},
|
||||
|
||||
// 修改暗色主题
|
||||
changeDarkTheme(darkTheme: string) {
|
||||
async changeDarkTheme(darkTheme: string) {
|
||||
this.preference.darkTheme = darkTheme;
|
||||
if (darkTheme === DarkTheme.DARK) {
|
||||
// 暗色
|
||||
@@ -66,53 +66,47 @@ export default defineStore('terminal', {
|
||||
this.isDarkTheme = this.preference.themeSchema.dark;
|
||||
}
|
||||
// 同步配置
|
||||
this.updateTerminalPreference();
|
||||
await this.updateTerminalPreference('darkTheme', darkTheme);
|
||||
},
|
||||
|
||||
// 修改显示配置
|
||||
changeDisplaySetting(displaySetting: TerminalDisplaySetting) {
|
||||
async changeDisplaySetting(displaySetting: TerminalDisplaySetting) {
|
||||
this.preference.displaySetting = displaySetting;
|
||||
// 同步配置
|
||||
this.updateTerminalPreference();
|
||||
await this.updateTerminalPreference('displaySetting', displaySetting);
|
||||
},
|
||||
|
||||
// 选择终端主题
|
||||
changeThemeSchema(themeSchema: TerminalThemeSchema) {
|
||||
async changeThemeSchema(themeSchema: TerminalThemeSchema) {
|
||||
this.preference.themeSchema = themeSchema;
|
||||
// 切换主题配色
|
||||
if (this.preference.darkTheme === DarkTheme.AUTO) {
|
||||
this.isDarkTheme = themeSchema.dark;
|
||||
}
|
||||
// 同步配置
|
||||
this.updateTerminalPreference();
|
||||
await this.updateTerminalPreference('themeSchema', themeSchema);
|
||||
},
|
||||
|
||||
// 切换新建连接类型
|
||||
changeNewConnectionType(newConnectionType: string) {
|
||||
async changeNewConnectionType(newConnectionType: string) {
|
||||
this.preference.newConnectionType = newConnectionType;
|
||||
// 同步配置
|
||||
this.updateTerminalPreference();
|
||||
await this.updateTerminalPreference('newConnectionType', newConnectionType);
|
||||
},
|
||||
|
||||
// 更新终端偏好-防抖
|
||||
updateTerminalPreference() {
|
||||
// 初始化函数
|
||||
if (!this.updateTerminalPreferenceFn) {
|
||||
this.updateTerminalPreferenceFn = useDebounceFn(async () => {
|
||||
try {
|
||||
// 修改配置
|
||||
await updatePreferencePartial({
|
||||
type: 'TERMINAL',
|
||||
config: this.preference
|
||||
});
|
||||
} catch (e) {
|
||||
Message.error('同步失败');
|
||||
}
|
||||
}, 1500);
|
||||
async updateTerminalPreference(item: string, value: any) {
|
||||
try {
|
||||
// 修改配置
|
||||
await updatePreference({
|
||||
type: 'TERMINAL',
|
||||
item,
|
||||
value
|
||||
});
|
||||
} catch (e) {
|
||||
Message.error('同步失败');
|
||||
}
|
||||
// 更新
|
||||
this.updateTerminalPreferenceFn();
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
@@ -3,8 +3,6 @@ import type { Ref } from 'vue';
|
||||
export interface TerminalState {
|
||||
isDarkTheme: Ref<boolean>;
|
||||
preference: TerminalPreference;
|
||||
|
||||
updateTerminalPreferenceFn?: () => void;
|
||||
}
|
||||
|
||||
// 终端配置
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<!-- 新建连接 -->
|
||||
<new-connection-view v-if="tab.key === InnerTabs.NEW_CONNECTION.key" />
|
||||
<!-- 显示设置 -->
|
||||
<terminal-view-setting v-else-if="tab.key === InnerTabs.THEME_SETTING.key" />
|
||||
<terminal-view-setting v-else-if="tab.key === InnerTabs.VIEW_SETTING.key" />
|
||||
<span v-else>
|
||||
{{ tab.key }}
|
||||
{{ tab.title }}
|
||||
|
||||
@@ -55,8 +55,6 @@
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
import { computed } from 'vue';
|
||||
import IconActions from '../layout/icon-actions.vue';
|
||||
import { useTerminalStore } from '@/store';
|
||||
import { DarkTheme } from '@/store/modules/terminal';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
@@ -72,7 +70,6 @@
|
||||
const emits = defineEmits(['update:modelValue', 'clickTab', 'deleteTab', 'share']);
|
||||
|
||||
const { isFullscreen, toggle: toggleFullScreen } = useFullscreen();
|
||||
const terminalStore = useTerminalStore();
|
||||
|
||||
// 顶部操作
|
||||
const actions = computed<Array<SidebarAction>>(() => [
|
||||
@@ -82,11 +79,6 @@
|
||||
visible: false,
|
||||
click: () => emits('share')
|
||||
},
|
||||
{
|
||||
icon: terminalStore.isDarkTheme ? 'icon-sun-fill' : 'icon-moon-fill',
|
||||
content: terminalStore.isDarkTheme ? '点击切换为亮色模式' : '点击切换为暗色模式',
|
||||
click: () => terminalStore.changeDarkTheme(terminalStore.isDarkTheme ? DarkTheme.LIGHT : DarkTheme.DARK)
|
||||
},
|
||||
{
|
||||
icon: isFullscreen.value ? 'icon-fullscreen-exit' : 'icon-fullscreen',
|
||||
content: isFullscreen.value ? '点击退出全屏模式' : '点击切换全屏模式',
|
||||
@@ -113,7 +105,7 @@
|
||||
.terminal-header {
|
||||
--logo-width: 168px;
|
||||
--right-avatar-width: calc(28px * 5 - 7px * 4);
|
||||
--right-action-width: calc(var(--header-height) * 3);
|
||||
--right-action-width: calc(var(--sidebar-icon-wrapper-size) * 2);
|
||||
}
|
||||
|
||||
.terminal-header {
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
{
|
||||
icon: 'icon-palette',
|
||||
content: '外观设置',
|
||||
click: () => emits('switchTab', InnerTabs.THEME_SETTING)
|
||||
click: () => emits('switchTab', InnerTabs.VIEW_SETTING)
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -20,11 +20,16 @@
|
||||
<script lang="ts" setup>
|
||||
import type { SidebarAction } from '../../types/terminal.const';
|
||||
import IconActions from './icon-actions.vue';
|
||||
import { computed } from 'vue';
|
||||
import { useTerminalStore } from '@/store';
|
||||
import { DarkTheme } from '@/store/modules/terminal';
|
||||
|
||||
const emits = defineEmits(['openSnippet', 'openSftp', 'openTransfer', 'openHistory', 'screenshot']);
|
||||
|
||||
const terminalStore = useTerminalStore();
|
||||
|
||||
// 顶部操作
|
||||
const topActions: Array<SidebarAction> = [
|
||||
const topActions = computed<Array<SidebarAction>>(() => [
|
||||
{
|
||||
icon: 'icon-code-block',
|
||||
content: '打开命令片段',
|
||||
@@ -49,7 +54,12 @@
|
||||
visible: false,
|
||||
click: () => emits('openHistory')
|
||||
},
|
||||
];
|
||||
{
|
||||
icon: terminalStore.isDarkTheme ? 'icon-sun-fill' : 'icon-moon-fill',
|
||||
content: terminalStore.isDarkTheme ? '点击切换为亮色模式' : '点击切换为暗色模式',
|
||||
click: () => terminalStore.changeDarkTheme(terminalStore.isDarkTheme ? DarkTheme.LIGHT : DarkTheme.DARK)
|
||||
},
|
||||
]);
|
||||
|
||||
// 底部操作
|
||||
const bottomActions: Array<SidebarAction> = [
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
主题设置
|
||||
</h3>
|
||||
<!-- 暗色选择 -->
|
||||
<a-radio-group :default-value="preference.darkTheme"
|
||||
<a-radio-group v-model="preference.darkTheme"
|
||||
class="usn"
|
||||
size="mini"
|
||||
type="button"
|
||||
@change="changeDarkTheme"
|
||||
:options="toOptions(darkThemeKey)">
|
||||
:options="toOptions(darkThemeKey)"
|
||||
@change="changeDarkTheme">
|
||||
</a-radio-group>
|
||||
</div>
|
||||
<!-- 内容区域 -->
|
||||
|
||||
@@ -36,9 +36,9 @@ export const InnerTabs = {
|
||||
title: '快捷键设置',
|
||||
type: TabType.SETTING
|
||||
},
|
||||
THEME_SETTING: {
|
||||
key: 'themeSetting',
|
||||
title: '主题设置',
|
||||
VIEW_SETTING: {
|
||||
key: 'viewSetting',
|
||||
title: '外观设置',
|
||||
type: TabType.SETTING
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user