基于 opsx-web-lite 框架(Go+Gin+Vue3+Element Plus)构建许可证管理服务器,
业务域参考 Licence 服务器 Web 版。
【后端 - 4层架构】
- 认证:单 Admin 表 + JWT(HS256)
- 核心授权域:Product / Customer / License / Activation
· License 生成/验证/激活/机器绑定/心跳/续期/吊销
· 客户端契约接口:/api/v1/license/{verify,activate,deactivate,heartbeat}
- 定价订单:Plan / Order / 支付网关配置
- 防重复购买:CustomerEntitlement + 幂等支付 webhook + 手动发放
- 分析审计:Dashboard 统计 / Analytics / AuditLog / Setting 管理
【前端】
- Dashboard(ECharts 图表)、产品、客户、License、计划、订单、权益、日志、设置
- 9 个完整 CRUD 业务页面 + 登录/布局
【部署】
- SQLite + 单二进制(//go:embed 嵌入前端)
- 开发:./run.sh start(前端5181/后端9001)
- 生产:./run.sh build && ./run.sh binary start
- 默认账号:admin/admin
Author: Logan.Li
141 lines
3.8 KiB
Go
141 lines
3.8 KiB
Go
package setting
|
|
|
|
import (
|
|
"backend/internal/dto"
|
|
"backend/internal/model"
|
|
"errors"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// SettingService 系统设置业务逻辑层 // Logan.Li
|
|
type SettingService struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewSettingService 创建 service 实例 // Logan.Li
|
|
func NewSettingService(db *gorm.DB) *SettingService {
|
|
return &SettingService{db: db}
|
|
}
|
|
|
|
// Get 获取系统设置(单行) // Logan.Li
|
|
func (s *SettingService) Get() (*model.Setting, error) {
|
|
var setting model.Setting
|
|
if err := s.db.First(&setting).Error; err != nil {
|
|
return nil, errors.New("系统设置不存在")
|
|
}
|
|
return &setting, nil
|
|
}
|
|
|
|
// Update 更新系统设置 // Logan.Li
|
|
func (s *SettingService) Update(req dto.SettingUpdate) (*model.Setting, error) {
|
|
var setting model.Setting
|
|
if err := s.db.First(&setting).Error; err != nil {
|
|
return nil, errors.New("系统设置不存在")
|
|
}
|
|
|
|
updates := map[string]interface{}{}
|
|
if req.SystemName != nil {
|
|
updates["system_name"] = *req.SystemName
|
|
}
|
|
if req.DefaultDuration != nil {
|
|
updates["default_duration"] = *req.DefaultDuration
|
|
}
|
|
if req.DefaultMaxActivations != nil {
|
|
updates["default_max_activations"] = *req.DefaultMaxActivations
|
|
}
|
|
if req.ExpireReminderDays != nil {
|
|
updates["expire_reminder_days"] = *req.ExpireReminderDays
|
|
}
|
|
if req.APIRateLimit != nil {
|
|
updates["api_rate_limit"] = *req.APIRateLimit
|
|
}
|
|
if req.LogRetentionDays != nil {
|
|
updates["log_retention_days"] = *req.LogRetentionDays
|
|
}
|
|
|
|
if len(updates) > 0 {
|
|
if err := s.db.Model(&setting).Updates(updates).Error; err != nil {
|
|
return nil, errors.New("更新系统设置失败")
|
|
}
|
|
}
|
|
s.db.First(&setting)
|
|
return &setting, nil
|
|
}
|
|
|
|
// ============ 审计日志 ============
|
|
|
|
// ListAuditLogs 分页查询审计日志 // Logan.Li
|
|
func (s *SettingService) ListAuditLogs(page, pageSize int, action, targetType string) ([]dto.AuditLogResponse, int64, error) {
|
|
var logs []model.AuditLog
|
|
var total int64
|
|
|
|
query := s.db.Model(&model.AuditLog{})
|
|
if action != "" {
|
|
query = query.Where("action = ?", action)
|
|
}
|
|
if targetType != "" {
|
|
query = query.Where("target_type = ?", targetType)
|
|
}
|
|
|
|
query.Count(&total)
|
|
if err := query.Order("created_at DESC").
|
|
Offset((page - 1) * pageSize).Limit(pageSize).
|
|
Find(&logs).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
results := make([]dto.AuditLogResponse, 0, len(logs))
|
|
for _, l := range logs {
|
|
results = append(results, dto.AuditLogResponse{
|
|
ID: l.ID,
|
|
Username: l.Username,
|
|
Action: l.Action,
|
|
TargetType: l.TargetType,
|
|
TargetID: l.TargetID,
|
|
TargetName: l.TargetName,
|
|
Detail: l.Detail,
|
|
Result: l.Result,
|
|
IP: l.IP,
|
|
CreatedAt: l.CreatedAt.Format("2006-01-02 15:04:05"),
|
|
})
|
|
}
|
|
return results, total, nil
|
|
}
|
|
|
|
// ClearAuditLogs 清空审计日志 // Logan.Li
|
|
func (s *SettingService) ClearAuditLogs() error {
|
|
return s.db.Exec("DELETE FROM audit_logs").Error
|
|
}
|
|
|
|
// ============ License 模板 ============
|
|
|
|
// ListLicenseTemplates 查询 License 模板 // Logan.Li
|
|
func (s *SettingService) ListLicenseTemplates() ([]model.LicenseTemplate, error) {
|
|
var templates []model.LicenseTemplate
|
|
s.db.Order("created_at DESC").Find(&templates)
|
|
return templates, nil
|
|
}
|
|
|
|
// SaveLicenseTemplate 创建/更新 License 模板 // Logan.Li
|
|
func (s *SettingService) SaveLicenseTemplate(tmpl model.LicenseTemplate) (*model.LicenseTemplate, error) {
|
|
if tmpl.Name == "" {
|
|
return nil, errors.New("模板名称不能为空")
|
|
}
|
|
if tmpl.ID > 0 {
|
|
if err := s.db.Save(&tmpl).Error; err != nil {
|
|
return nil, errors.New("更新模板失败")
|
|
}
|
|
} else {
|
|
if err := s.db.Create(&tmpl).Error; err != nil {
|
|
return nil, errors.New("创建模板失败")
|
|
}
|
|
}
|
|
return &tmpl, nil
|
|
}
|
|
|
|
// DeleteLicenseTemplate 删除 License 模板 // Logan.Li
|
|
func (s *SettingService) DeleteLicenseTemplate(id uint) error {
|
|
return s.db.Delete(&model.LicenseTemplate{}, id).Error
|
|
}
|