增加品牌方案管理

This commit is contained in:
2026-07-23 18:56:35 +08:00
parent 4c07ec5455
commit b689656faf
67 changed files with 5572 additions and 231 deletions
+5
View File
@@ -27,6 +27,11 @@
<artifactId>manage-notify</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.novalon.gym.manage</groupId>
<artifactId>gym-brand</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.novalon.gym.manage</groupId>
<artifactId>manage-file</artifactId>
@@ -0,0 +1,59 @@
package cn.novalon.gym.manage.db.converter;
import cn.novalon.gym.manage.brand.core.domain.BrandConfig;
import cn.novalon.gym.manage.db.entity.BrandConfigEntity;
import org.springframework.stereotype.Component;
/**
* 品牌配置实体转换器
*
* @author 张翔
* @date 2026-07-23
*/
@Component
public class BrandConfigConverter {
public BrandConfig toDomain(BrandConfigEntity entity) {
if (entity == null) {
return null;
}
BrandConfig domain = new BrandConfig();
domain.setId(entity.getId());
domain.setTenantId(entity.getTenantId());
domain.setLogoUrl(entity.getLogoUrl());
domain.setBackgroundImageUrl(entity.getBackgroundImageUrl());
domain.setPrimaryColor(entity.getPrimaryColor());
domain.setPrimaryColorRgb(entity.getPrimaryColorRgb());
domain.setSecondaryColor(entity.getSecondaryColor());
domain.setSecondaryColorRgb(entity.getSecondaryColorRgb());
domain.setFontFamily(entity.getFontFamily());
domain.setBrandName(entity.getBrandName());
domain.setSlogan(entity.getSlogan());
domain.setCreatedAt(entity.getCreatedAt());
domain.setUpdatedAt(entity.getUpdatedAt());
domain.setDeletedAt(entity.getDeletedAt());
return domain;
}
public BrandConfigEntity toEntity(BrandConfig domain) {
if (domain == null) {
return null;
}
BrandConfigEntity entity = new BrandConfigEntity();
entity.setId(domain.getId());
entity.setTenantId(domain.getTenantId());
entity.setLogoUrl(domain.getLogoUrl());
entity.setBackgroundImageUrl(domain.getBackgroundImageUrl());
entity.setPrimaryColor(domain.getPrimaryColor());
entity.setPrimaryColorRgb(domain.getPrimaryColorRgb());
entity.setSecondaryColor(domain.getSecondaryColor());
entity.setSecondaryColorRgb(domain.getSecondaryColorRgb());
entity.setFontFamily(domain.getFontFamily());
entity.setBrandName(domain.getBrandName());
entity.setSlogan(domain.getSlogan());
entity.setCreatedAt(domain.getCreatedAt());
entity.setUpdatedAt(domain.getUpdatedAt());
entity.setDeletedAt(domain.getDeletedAt());
return entity;
}
}
@@ -0,0 +1,20 @@
package cn.novalon.gym.manage.db.dao;
import cn.novalon.gym.manage.db.entity.BrandConfigEntity;
import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.r2dbc.repository.R2dbcRepository;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Mono;
/**
* 品牌配置数据访问接口
*
* @author 张翔
* @date 2026-07-23
*/
@Repository
public interface BrandConfigDao extends R2dbcRepository<BrandConfigEntity, Long> {
@Query("SELECT * FROM brand_config WHERE tenant_id = $1 AND deleted_at IS NULL")
Mono<BrandConfigEntity> findByTenantIdAndDeletedAtIsNull(String tenantId);
}
@@ -0,0 +1,88 @@
package cn.novalon.gym.manage.db.entity;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;
import java.time.LocalDateTime;
/**
* 品牌配置数据库实体类
*
* @author 张翔
* @date 2026-07-23
*/
@Table("brand_config")
public class BrandConfigEntity {
@Id
private Long id;
@Column("tenant_id")
private String tenantId;
@Column("logo_url")
private String logoUrl;
@Column("background_image_url")
private String backgroundImageUrl;
@Column("primary_color")
private String primaryColor;
@Column("primary_color_rgb")
private String primaryColorRgb;
@Column("secondary_color")
private String secondaryColor;
@Column("secondary_color_rgb")
private String secondaryColorRgb;
@Column("font_family")
private String fontFamily;
@Column("brand_name")
private String brandName;
@Column("slogan")
private String slogan;
@Column("created_at")
private LocalDateTime createdAt;
@Column("updated_at")
private LocalDateTime updatedAt;
@Column("deleted_at")
private LocalDateTime deletedAt;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getTenantId() { return tenantId; }
public void setTenantId(String tenantId) { this.tenantId = tenantId; }
public String getLogoUrl() { return logoUrl; }
public void setLogoUrl(String logoUrl) { this.logoUrl = logoUrl; }
public String getBackgroundImageUrl() { return backgroundImageUrl; }
public void setBackgroundImageUrl(String backgroundImageUrl) { this.backgroundImageUrl = backgroundImageUrl; }
public String getPrimaryColor() { return primaryColor; }
public void setPrimaryColor(String primaryColor) { this.primaryColor = primaryColor; }
public String getPrimaryColorRgb() { return primaryColorRgb; }
public void setPrimaryColorRgb(String primaryColorRgb) { this.primaryColorRgb = primaryColorRgb; }
public String getSecondaryColor() { return secondaryColor; }
public void setSecondaryColor(String secondaryColor) { this.secondaryColor = secondaryColor; }
public String getSecondaryColorRgb() { return secondaryColorRgb; }
public void setSecondaryColorRgb(String secondaryColorRgb) { this.secondaryColorRgb = secondaryColorRgb; }
public String getFontFamily() { return fontFamily; }
public void setFontFamily(String fontFamily) { this.fontFamily = fontFamily; }
public String getBrandName() { return brandName; }
public void setBrandName(String brandName) { this.brandName = brandName; }
public String getSlogan() { return slogan; }
public void setSlogan(String slogan) { this.slogan = slogan; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public LocalDateTime getUpdatedAt() { return updatedAt; }
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
public LocalDateTime getDeletedAt() { return deletedAt; }
public void setDeletedAt(LocalDateTime deletedAt) { this.deletedAt = deletedAt; }
}
@@ -0,0 +1,38 @@
package cn.novalon.gym.manage.db.repository;
import cn.novalon.gym.manage.brand.core.domain.BrandConfig;
import cn.novalon.gym.manage.brand.core.repository.IBrandConfigRepository;
import cn.novalon.gym.manage.db.converter.BrandConfigConverter;
import cn.novalon.gym.manage.db.dao.BrandConfigDao;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Mono;
/**
* 品牌配置仓储实现类
*
* @author 张翔
* @date 2026-07-23
*/
@Repository
public class BrandConfigRepository implements IBrandConfigRepository {
private final BrandConfigDao brandConfigDao;
private final BrandConfigConverter brandConfigConverter;
public BrandConfigRepository(BrandConfigDao brandConfigDao, BrandConfigConverter brandConfigConverter) {
this.brandConfigDao = brandConfigDao;
this.brandConfigConverter = brandConfigConverter;
}
@Override
public Mono<BrandConfig> findByTenantId(String tenantId) {
return brandConfigDao.findByTenantIdAndDeletedAtIsNull(tenantId)
.map(brandConfigConverter::toDomain);
}
@Override
public Mono<BrandConfig> save(BrandConfig brandConfig) {
return brandConfigDao.save(brandConfigConverter.toEntity(brandConfig))
.map(brandConfigConverter::toDomain);
}
}
@@ -0,0 +1,33 @@
-- ============================================
-- V25: 创建品牌配置表
-- ============================================
-- 创建 brand_config 表(租户独立品牌配置)
CREATE TABLE IF NOT EXISTS brand_config (
id BIGSERIAL PRIMARY KEY,
tenant_id VARCHAR(50) NOT NULL,
logo_url VARCHAR(512),
background_image_url VARCHAR(512),
primary_color VARCHAR(20) DEFAULT '#00E676',
primary_color_rgb VARCHAR(30),
secondary_color VARCHAR(20) DEFAULT '#1A1A1A',
secondary_color_rgb VARCHAR(30),
font_family VARCHAR(100) DEFAULT 'default',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- 创建唯一索引:每个租户只能有一条品牌配置
CREATE UNIQUE INDEX IF NOT EXISTS idx_brand_config_tenant_id ON brand_config(tenant_id) WHERE deleted_at IS NULL;
-- 添加注释
COMMENT ON TABLE brand_config IS '品牌配置表';
COMMENT ON COLUMN brand_config.tenant_id IS '租户ID';
COMMENT ON COLUMN brand_config.logo_url IS 'Logo图片URL';
COMMENT ON COLUMN brand_config.background_image_url IS '背景图URL';
COMMENT ON COLUMN brand_config.primary_color IS '品牌主色调(HEX格式)';
COMMENT ON COLUMN brand_config.primary_color_rgb IS '品牌主色调(RGB格式)';
COMMENT ON COLUMN brand_config.secondary_color IS '品牌辅助色(HEX格式)';
COMMENT ON COLUMN brand_config.secondary_color_rgb IS '品牌辅助色(RGB格式)';
COMMENT ON COLUMN brand_config.font_family IS '字体';
@@ -0,0 +1,27 @@
-- ============================================
-- V26: 新增品牌定制菜单及按钮权限
-- ============================================
-- 品牌定制菜单(顶级菜单,parent_id=0,排序在轮播图之后)
INSERT INTO sys_menu (id, menu_name, parent_id, order_num, menu_type, perms, component, status, created_at, updated_at)
VALUES (29, '品牌定制', 0, 9, 'C', 'brand:config:list', 'brand/index', 1, NOW(), NOW())
ON CONFLICT (id) DO NOTHING;
-- 品牌定制按钮权限
INSERT INTO sys_menu (id, menu_name, parent_id, order_num, menu_type, perms, component, status, created_at, updated_at) VALUES
(291, '品牌配置查询', 29, 1, 'F', 'brand:config:query', NULL, 1, NOW(), NOW()),
(292, '品牌配色修改', 29, 2, 'F', 'brand:config:edit', NULL, 1, NOW(), NOW()),
(293, 'Logo上传', 29, 3, 'F', 'brand:logo:upload', NULL, 1, NOW(), NOW()),
(294, '背景图上传', 29, 4, 'F', 'brand:bg:upload', NULL, 1, NOW(), NOW())
ON CONFLICT (id) DO NOTHING;
-- 为管理员角色(role_id=1)分配品牌定制权限
INSERT INTO sys_role_permission (role_id, permission_id)
SELECT 1, id FROM sys_permission
WHERE permission_code IN ('brand:config:list', 'brand:config:query', 'brand:config:edit', 'brand:logo:upload', 'brand:bg:upload')
AND NOT EXISTS (
SELECT 1 FROM sys_role_permission WHERE role_id = 1 AND permission_id = sys_permission.id
);
-- 重置菜单序列
SELECT setval('sys_menu_id_seq', (SELECT COALESCE(MAX(id), 1) FROM sys_menu));
@@ -0,0 +1,12 @@
-- =====================================================
-- V27: 为 brand_config 表添加品牌名和口号字段
-- 作者: 张翔
-- 日期: 2026-07-23
-- =====================================================
ALTER TABLE brand_config
ADD COLUMN IF NOT EXISTS brand_name VARCHAR(100),
ADD COLUMN IF NOT EXISTS slogan VARCHAR(200);
COMMENT ON COLUMN brand_config.brand_name IS '品牌名称';
COMMENT ON COLUMN brand_config.slogan IS '品牌口号';