mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-09 22:45:58 +08:00
feat(iam): 用户工作台快捷入口偏好(显隐+排序) + 建表
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
-- 用户工作台快捷入口偏好表: 用户个性化工作台快捷入口(显隐+排序), PC与移动按 client_code 分开管理
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."iam_user_dashboard_preference" (
|
||||
"id" bigint NOT NULL PRIMARY KEY,
|
||||
"user_id" bigint NOT NULL,
|
||||
"client_code" varchar(32) NOT NULL,
|
||||
"entries" jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
"creator" bigint,
|
||||
"create_time" timestamptz(6),
|
||||
"last_modifier" bigint,
|
||||
"last_modified_time" timestamptz(6),
|
||||
"version" integer NOT NULL DEFAULT 0,
|
||||
"deleted" boolean NOT NULL DEFAULT false
|
||||
);
|
||||
|
||||
COMMENT ON TABLE "public"."iam_user_dashboard_preference" IS '用户工作台快捷入口偏好';
|
||||
COMMENT ON COLUMN "public"."iam_user_dashboard_preference"."id" IS '主键';
|
||||
COMMENT ON COLUMN "public"."iam_user_dashboard_preference"."user_id" IS '用户ID';
|
||||
COMMENT ON COLUMN "public"."iam_user_dashboard_preference"."client_code" IS '终端编码(WEB/MOBILE), PC与移动分开管理';
|
||||
COMMENT ON COLUMN "public"."iam_user_dashboard_preference"."entries" IS '已选快捷入口有序序列(纯key数组), 如 ["merchant","notify"]';
|
||||
COMMENT ON COLUMN "public"."iam_user_dashboard_preference"."creator" IS '创建人ID';
|
||||
COMMENT ON COLUMN "public"."iam_user_dashboard_preference"."create_time" IS '创建时间(UTC)';
|
||||
COMMENT ON COLUMN "public"."iam_user_dashboard_preference"."last_modifier" IS '最后修改人ID';
|
||||
COMMENT ON COLUMN "public"."iam_user_dashboard_preference"."last_modified_time" IS '最后修改时间(UTC)';
|
||||
COMMENT ON COLUMN "public"."iam_user_dashboard_preference"."version" IS '乐观锁版本号';
|
||||
COMMENT ON COLUMN "public"."iam_user_dashboard_preference"."deleted" IS '逻辑删除标志';
|
||||
|
||||
-- 每用户每终端唯一一份配置(仅在未逻辑删除时生效, 允许删后重建)
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "uk_user_das_pref_user_client"
|
||||
ON "public"."iam_user_dashboard_preference" ("user_id", "client_code")
|
||||
WHERE "deleted" = false;
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package cn.daxpay.open.platform.iam.controller.dashboardpreference;
|
||||
|
||||
import cn.daxpay.open.platform.core.rest.Res;
|
||||
import cn.daxpay.open.platform.core.rest.result.Result;
|
||||
import cn.daxpay.open.platform.iam.param.dashboardpreference.QuickEntrySaveParam;
|
||||
import cn.daxpay.open.platform.iam.result.dashboardpreference.QuickEntryResult;
|
||||
import cn.daxpay.open.platform.iam.service.dashboardpreference.UserDashboardPreferenceService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/// # 工作台快捷入口偏好
|
||||
///
|
||||
/// 用户个性化工作台快捷入口(显隐 + 排序), PC 与移动端按请求终端自动区分.
|
||||
/// 每个登录用户均可管理自己的偏好, 无需额外权限码.
|
||||
@Validated
|
||||
@Tag(name = "工作台快捷入口")
|
||||
@RestController
|
||||
@RequestMapping("/iam/dashboard/quick-entry")
|
||||
@RequiredArgsConstructor
|
||||
public class UserDashboardPreferenceController {
|
||||
|
||||
private final UserDashboardPreferenceService userDashboardPreferenceService;
|
||||
|
||||
@Operation(summary = "查询当前用户的快捷入口序列")
|
||||
@GetMapping
|
||||
public Result<QuickEntryResult> find() {
|
||||
return Res.ok(userDashboardPreferenceService.findCurrent());
|
||||
}
|
||||
|
||||
@Operation(summary = "保存当前用户的快捷入口序列(整体覆盖)")
|
||||
@PutMapping
|
||||
public Result<Void> save(@RequestBody @Validated QuickEntrySaveParam param) {
|
||||
userDashboardPreferenceService.saveCurrent(param.getEntries());
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package cn.daxpay.open.platform.iam.convert.dashboardpreference;
|
||||
|
||||
import cn.daxpay.open.platform.iam.entity.dashboardpreference.UserDashboardPreference;
|
||||
import cn.daxpay.open.platform.iam.result.dashboardpreference.QuickEntryResult;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface UserDashboardPreferenceConvert {
|
||||
|
||||
UserDashboardPreferenceConvert CONVERT = Mappers.getMapper(UserDashboardPreferenceConvert.class);
|
||||
|
||||
QuickEntryResult toResult(UserDashboardPreference in);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.daxpay.open.platform.iam.dao.dashboardpreference;
|
||||
|
||||
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.daxpay.open.platform.iam.entity.dashboardpreference.UserDashboardPreference;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/// # 用户工作台快捷入口偏好
|
||||
///
|
||||
@Repository
|
||||
public class UserDashboardPreferenceManager extends BaseManager<UserDashboardPreferenceMapper, UserDashboardPreference> {
|
||||
|
||||
/// 按用户 + 终端查询偏好
|
||||
public Optional<UserDashboardPreference> findByUserAndClient(Long userId, String clientCode) {
|
||||
return lambdaQuery()
|
||||
.eq(UserDashboardPreference::getUserId, userId)
|
||||
.eq(UserDashboardPreference::getClientCode, clientCode)
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package cn.daxpay.open.platform.iam.dao.dashboardpreference;
|
||||
|
||||
import cn.daxpay.open.platform.iam.entity.dashboardpreference.UserDashboardPreference;
|
||||
import com.github.yulichang.base.MPJBaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/// # 用户工作台快捷入口偏好
|
||||
///
|
||||
@Mapper
|
||||
public interface UserDashboardPreferenceMapper extends MPJBaseMapper<UserDashboardPreference> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package cn.daxpay.open.platform.iam.entity.dashboardpreference;
|
||||
|
||||
import cn.daxpay.open.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.daxpay.open.platform.common.mybatisplus.function.ToResult;
|
||||
import cn.daxpay.open.platform.common.mybatisplus.handler.type.StringListTypeHandler;
|
||||
import cn.daxpay.open.platform.iam.convert.dashboardpreference.UserDashboardPreferenceConvert;
|
||||
import cn.daxpay.open.platform.iam.result.dashboardpreference.QuickEntryResult;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/// # 用户工作台快捷入口偏好
|
||||
///
|
||||
/// 按用户 + 终端(clientCode)维度存储用户在工作台自定义的快捷入口序列.
|
||||
/// 仅存已选入口的 key 有序列表, 入口元信息(图标/标题/路由)由前端各端自行维护, 后端不感知.
|
||||
/// PC 与移动端通过 clientCode 区分, 互不影响.
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@TableName(value = "iam_user_dashboard_preference", autoResultMap = true)
|
||||
public class UserDashboardPreference extends MpBaseEntity implements ToResult<QuickEntryResult> {
|
||||
|
||||
/// 用户ID
|
||||
private Long userId;
|
||||
|
||||
/// 终端编码(WEB / MOBILE), PC 与移动分开管理
|
||||
private String clientCode;
|
||||
|
||||
/// 已选快捷入口有序序列(纯 key 数组), 如 ["merchant","notify","app"]
|
||||
@TableField(typeHandler = StringListTypeHandler.class)
|
||||
private List<String> entries;
|
||||
|
||||
@Override
|
||||
public QuickEntryResult toResult() {
|
||||
return UserDashboardPreferenceConvert.CONVERT.toResult(this);
|
||||
}
|
||||
|
||||
/// 构造新实例(新增用)
|
||||
public static UserDashboardPreference init(Long userId, String clientCode, List<String> entries) {
|
||||
return new UserDashboardPreference()
|
||||
.setUserId(userId)
|
||||
.setClientCode(clientCode)
|
||||
.setEntries(entries);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package cn.daxpay.open.platform.iam.param.dashboardpreference;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "工作台快捷入口保存参数")
|
||||
public class QuickEntrySaveParam {
|
||||
|
||||
/// 已选快捷入口有序序列(纯 key 数组), 允许空数组表示全部隐藏
|
||||
@Schema(description = "已选快捷入口有序序列(纯 key 数组), 允许空数组")
|
||||
private List<String> entries;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package cn.daxpay.open.platform.iam.result.dashboardpreference;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "工作台快捷入口偏好")
|
||||
public class QuickEntryResult {
|
||||
|
||||
/// 已选快捷入口有序序列(纯 key 数组); 为 null 表示用户尚未自定义, 前端使用默认序列
|
||||
@Schema(description = "已选快捷入口有序序列(纯 key 数组), null 表示未自定义")
|
||||
private List<String> entries;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package cn.daxpay.open.platform.iam.service.dashboardpreference;
|
||||
|
||||
import cn.daxpay.open.platform.capability.auth.util.SecurityUtil;
|
||||
import cn.daxpay.open.platform.iam.dao.dashboardpreference.UserDashboardPreferenceManager;
|
||||
import cn.daxpay.open.platform.iam.entity.dashboardpreference.UserDashboardPreference;
|
||||
import cn.daxpay.open.platform.iam.result.dashboardpreference.QuickEntryResult;
|
||||
import cn.daxpay.open.platform.iam.service.client.ClientCodeService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/// # 用户工作台快捷入口偏好
|
||||
///
|
||||
/// PC 与移动端通过请求终端(clientCode)区分, 每用户每端一份配置, 互不影响.
|
||||
/// 仅存储用户已选入口的 key 有序序列, 入口元信息由前端维护.
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UserDashboardPreferenceService {
|
||||
|
||||
private final UserDashboardPreferenceManager userDashboardPreferenceManager;
|
||||
|
||||
private final ClientCodeService clientCodeService;
|
||||
|
||||
/// 查询当前用户在当前终端的快捷入口序列
|
||||
/// 未自定义时 entries 返回 null, 前端据此使用默认序列
|
||||
public QuickEntryResult findCurrent() {
|
||||
Long userId = SecurityUtil.getUserId();
|
||||
String clientCode = clientCodeService.getClientCode();
|
||||
return userDashboardPreferenceManager.findByUserAndClient(userId, clientCode)
|
||||
.map(UserDashboardPreference::toResult)
|
||||
.orElseGet(() -> new QuickEntryResult().setEntries(null));
|
||||
}
|
||||
|
||||
/// 保存(整体覆盖)当前用户在当前终端的快捷入口序列
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveCurrent(List<String> entries) {
|
||||
Long userId = SecurityUtil.getUserId();
|
||||
String clientCode = clientCodeService.getClientCode();
|
||||
// 入参为 null 时按空序列处理, 表示全部隐藏
|
||||
List<String> safeEntries = entries == null ? new ArrayList<>() : entries;
|
||||
UserDashboardPreference existed = userDashboardPreferenceManager
|
||||
.findByUserAndClient(userId, clientCode).orElse(null);
|
||||
if (existed == null) {
|
||||
// 新增
|
||||
userDashboardPreferenceManager.save(
|
||||
UserDashboardPreference.init(userId, clientCode, safeEntries));
|
||||
}
|
||||
else {
|
||||
// 整体覆盖更新
|
||||
existed.setEntries(safeEntries);
|
||||
userDashboardPreferenceManager.updateById(existed);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user