feat: add env disenable
This commit is contained in:
@@ -35,6 +35,7 @@ func (ec *EnvController) CreateEnvVar(c *gin.Context) {
|
|||||||
Value string `json:"value" binding:"required"`
|
Value string `json:"value" binding:"required"`
|
||||||
Remark string `json:"remark"`
|
Remark string `json:"remark"`
|
||||||
Hidden *bool `json:"hidden"`
|
Hidden *bool `json:"hidden"`
|
||||||
|
Enabled *bool `json:"enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
@@ -47,7 +48,12 @@ func (ec *EnvController) CreateEnvVar(c *gin.Context) {
|
|||||||
hidden = *req.Hidden
|
hidden = *req.Hidden
|
||||||
}
|
}
|
||||||
|
|
||||||
envVar := ec.envService.CreateEnvVar(req.Name, req.Value, req.Remark, hidden, userID)
|
enabled := true
|
||||||
|
if req.Enabled != nil {
|
||||||
|
enabled = *req.Enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
envVar := ec.envService.CreateEnvVar(req.Name, req.Value, req.Remark, hidden, enabled, userID)
|
||||||
utils.Success(c, vo.ToEnvVO(envVar))
|
utils.Success(c, vo.ToEnvVO(envVar))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,10 +139,11 @@ func (ec *EnvController) UpdateEnvVar(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var req struct {
|
var req struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
Remark string `json:"remark"`
|
Remark string `json:"remark"`
|
||||||
Hidden *bool `json:"hidden"`
|
Hidden *bool `json:"hidden"`
|
||||||
|
Enabled *bool `json:"enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
@@ -155,7 +162,13 @@ func (ec *EnvController) UpdateEnvVar(c *gin.Context) {
|
|||||||
if req.Hidden != nil {
|
if req.Hidden != nil {
|
||||||
hidden = *req.Hidden
|
hidden = *req.Hidden
|
||||||
}
|
}
|
||||||
envVar := ec.envService.UpdateEnvVar(id, req.Name, req.Value, req.Remark, hidden)
|
|
||||||
|
enabled := existing.Enabled
|
||||||
|
if req.Enabled != nil {
|
||||||
|
enabled = *req.Enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
envVar := ec.envService.UpdateEnvVar(id, req.Name, req.Value, req.Remark, hidden, enabled)
|
||||||
if envVar == nil {
|
if envVar == nil {
|
||||||
utils.NotFound(c, "环境变量不存在")
|
utils.NotFound(c, "环境变量不存在")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -30,10 +30,20 @@ func Migrate() error {
|
|||||||
&models.NotifyBinding{},
|
&models.NotifyBinding{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查环境变量表中是否已存在 enabled 列
|
||||||
|
hasEnabled := DB.Migrator().HasColumn(&models.EnvironmentVariable{}, "enabled")
|
||||||
if err := AutoMigrate(allModels...); err != nil {
|
if err := AutoMigrate(allModels...); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果原来没有 enabled 列,说明是平滑升级,将现有的环境变量默认设置为启用
|
||||||
|
if !hasEnabled {
|
||||||
|
logger.Infof("[Database] 为现有环境变量初始化启用状态...")
|
||||||
|
if err := DB.Model(&models.EnvironmentVariable{}).Where("1=1").Update("enabled", true).Error; err != nil {
|
||||||
|
logger.Errorf("[Database] 初始化环境变量启用状态失败: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ type EnvironmentVariable struct {
|
|||||||
Value BigText `json:"value"`
|
Value BigText `json:"value"`
|
||||||
Remark string `json:"remark" gorm:"size:500"`
|
Remark string `json:"remark" gorm:"size:500"`
|
||||||
Hidden bool `json:"hidden" gorm:"default:true"`
|
Hidden bool `json:"hidden" gorm:"default:true"`
|
||||||
|
Enabled bool `json:"enabled" gorm:"default:true"`
|
||||||
UserID string `json:"user_id" gorm:"size:20;index"`
|
UserID string `json:"user_id" gorm:"size:20;index"`
|
||||||
CreatedAt LocalTime `json:"created_at"`
|
CreatedAt LocalTime `json:"created_at"`
|
||||||
UpdatedAt LocalTime `json:"updated_at"`
|
UpdatedAt LocalTime `json:"updated_at"`
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ type EnvVO struct {
|
|||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
Remark string `json:"remark"`
|
Remark string `json:"remark"`
|
||||||
Hidden bool `json:"hidden"`
|
Hidden bool `json:"hidden"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
CreatedAt models.LocalTime `json:"created_at"`
|
CreatedAt models.LocalTime `json:"created_at"`
|
||||||
UpdatedAt models.LocalTime `json:"updated_at"`
|
UpdatedAt models.LocalTime `json:"updated_at"`
|
||||||
}
|
}
|
||||||
@@ -51,6 +52,7 @@ func ToEnvVO(env *models.EnvironmentVariable) *EnvVO {
|
|||||||
Value: string(env.Value),
|
Value: string(env.Value),
|
||||||
Remark: env.Remark,
|
Remark: env.Remark,
|
||||||
Hidden: env.Hidden,
|
Hidden: env.Hidden,
|
||||||
|
Enabled: env.Enabled,
|
||||||
CreatedAt: env.CreatedAt,
|
CreatedAt: env.CreatedAt,
|
||||||
UpdatedAt: env.UpdatedAt,
|
UpdatedAt: env.UpdatedAt,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,13 +16,14 @@ func NewEnvService() *EnvService {
|
|||||||
return &EnvService{}
|
return &EnvService{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *EnvService) CreateEnvVar(name, value, remark string, hidden bool, userID string) *models.EnvironmentVariable {
|
func (es *EnvService) CreateEnvVar(name, value, remark string, hidden, enabled bool, userID string) *models.EnvironmentVariable {
|
||||||
env := &models.EnvironmentVariable{
|
env := &models.EnvironmentVariable{
|
||||||
ID: utils.GenerateID(),
|
ID: utils.GenerateID(),
|
||||||
Name: name,
|
Name: name,
|
||||||
Value: models.BigText(value),
|
Value: models.BigText(value),
|
||||||
Remark: remark,
|
Remark: remark,
|
||||||
Hidden: hidden,
|
Hidden: hidden,
|
||||||
|
Enabled: enabled,
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
CreatedAt: models.Now(),
|
CreatedAt: models.Now(),
|
||||||
UpdatedAt: models.Now(),
|
UpdatedAt: models.Now(),
|
||||||
@@ -65,16 +66,17 @@ func (es *EnvService) GetEnvVarByID(id string) *models.EnvironmentVariable {
|
|||||||
return &env
|
return &env
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *EnvService) UpdateEnvVar(id string, name, value, remark string, hidden bool) *models.EnvironmentVariable {
|
func (es *EnvService) UpdateEnvVar(id string, name, value, remark string, hidden, enabled bool) *models.EnvironmentVariable {
|
||||||
var env models.EnvironmentVariable
|
var env models.EnvironmentVariable
|
||||||
if err := database.DB.Where("id = ?", id).First(&env).Error; err != nil {
|
if err := database.DB.Where("id = ?", id).First(&env).Error; err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
updates := map[string]interface{}{
|
updates := map[string]interface{}{
|
||||||
"name": name,
|
"name": name,
|
||||||
"value": models.BigText(value),
|
"value": models.BigText(value),
|
||||||
"remark": remark,
|
"remark": remark,
|
||||||
"hidden": hidden,
|
"hidden": hidden,
|
||||||
|
"enabled": enabled,
|
||||||
}
|
}
|
||||||
database.DB.Model(&env).Updates(updates)
|
database.DB.Model(&env).Updates(updates)
|
||||||
return &env
|
return &env
|
||||||
@@ -165,13 +167,18 @@ func (es *EnvService) formatEnvVars(envs []models.EnvironmentVariable) []string
|
|||||||
nameToIndex := make(map[string]int)
|
nameToIndex := make(map[string]int)
|
||||||
|
|
||||||
for _, env := range envs {
|
for _, env := range envs {
|
||||||
|
value := string(env.Value)
|
||||||
|
if !env.Enabled {
|
||||||
|
value = ""
|
||||||
|
}
|
||||||
|
|
||||||
if idx, ok := nameToIndex[env.Name]; ok {
|
if idx, ok := nameToIndex[env.Name]; ok {
|
||||||
mergedList[idx].values = append(mergedList[idx].values, string(env.Value))
|
mergedList[idx].values = append(mergedList[idx].values, value)
|
||||||
} else {
|
} else {
|
||||||
nameToIndex[env.Name] = len(mergedList)
|
nameToIndex[env.Name] = len(mergedList)
|
||||||
mergedList = append(mergedList, mergedEnv{
|
mergedList = append(mergedList, mergedEnv{
|
||||||
name: env.Name,
|
name: env.Name,
|
||||||
values: []string{string(env.Value)},
|
values: []string{value},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -377,6 +377,7 @@ export interface EnvVar {
|
|||||||
value: string
|
value: string
|
||||||
remark: string
|
remark: string
|
||||||
hidden: boolean
|
hidden: boolean
|
||||||
|
enabled: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EnvListResponse {
|
export interface EnvListResponse {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { Input } from '@/components/ui/input'
|
|||||||
import { Textarea } from '@/components/ui/textarea'
|
import { Textarea } from '@/components/ui/textarea'
|
||||||
import { Label } from '@/components/ui/label'
|
import { Label } from '@/components/ui/label'
|
||||||
import Pagination from '@/components/Pagination.vue'
|
import Pagination from '@/components/Pagination.vue'
|
||||||
import { Plus, Pencil, Trash2, Eye, EyeOff, Search, AlertTriangle, Terminal } from 'lucide-vue-next'
|
import { Plus, Pencil, Trash2, Eye, EyeOff, Search, AlertTriangle, Terminal, Zap, ZapOff } from 'lucide-vue-next'
|
||||||
import TextOverflow from '@/components/TextOverflow.vue'
|
import TextOverflow from '@/components/TextOverflow.vue'
|
||||||
import { api, type EnvVar } from '@/api'
|
import { api, type EnvVar } from '@/api'
|
||||||
import { toast } from 'vue-sonner'
|
import { toast } from 'vue-sonner'
|
||||||
@@ -61,7 +61,7 @@ function handlePageChange(page: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openCreate() {
|
function openCreate() {
|
||||||
editingEnv.value = { name: '', value: '', remark: '', hidden: true }
|
editingEnv.value = { name: '', value: '', remark: '', hidden: true, enabled: true }
|
||||||
isEdit.value = false
|
isEdit.value = false
|
||||||
showDialog.value = true
|
showDialog.value = true
|
||||||
}
|
}
|
||||||
@@ -133,6 +133,16 @@ function toggleShow(id: string) {
|
|||||||
showValues.value[id] = !showValues.value[id]
|
showValues.value[id] = !showValues.value[id]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function toggleEnabled(env: EnvVar) {
|
||||||
|
try {
|
||||||
|
await api.env.update(env.id, { ...env, enabled: !env.enabled })
|
||||||
|
env.enabled = !env.enabled
|
||||||
|
toast.success(env.enabled ? '变量已启用' : '变量已禁用')
|
||||||
|
} catch {
|
||||||
|
toast.error('操作失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function maskValue(value: string) {
|
function maskValue(value: string) {
|
||||||
return '•'.repeat(Math.min(value.length, 20))
|
return '•'.repeat(Math.min(value.length, 20))
|
||||||
}
|
}
|
||||||
@@ -166,7 +176,7 @@ onMounted(loadEnvVars)
|
|||||||
<span class="w-32 sm:w-48 shrink-0">变量名</span>
|
<span class="w-32 sm:w-48 shrink-0">变量名</span>
|
||||||
<span class="w-24 sm:flex-1 shrink-0 sm:shrink">值</span>
|
<span class="w-24 sm:flex-1 shrink-0 sm:shrink">值</span>
|
||||||
<span class="w-32 sm:w-48 shrink-0 hidden md:block">备注</span>
|
<span class="w-32 sm:w-48 shrink-0 hidden md:block">备注</span>
|
||||||
<span class="w-20 sm:w-24 shrink-0 text-center">操作</span>
|
<span class="w-28 sm:w-36 shrink-0 text-center">操作</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- 列表 -->
|
<!-- 列表 -->
|
||||||
<div class="divide-y min-w-[500px]">
|
<div class="divide-y min-w-[500px]">
|
||||||
@@ -183,7 +193,13 @@ onMounted(loadEnvVars)
|
|||||||
<span class="w-32 sm:w-48 shrink-0 text-muted-foreground truncate text-sm hidden md:block">
|
<span class="w-32 sm:w-48 shrink-0 text-muted-foreground truncate text-sm hidden md:block">
|
||||||
<TextOverflow :text="env.remark || '-'" title="备注" />
|
<TextOverflow :text="env.remark || '-'" title="备注" />
|
||||||
</span>
|
</span>
|
||||||
<span class="w-20 sm:w-24 shrink-0 flex justify-center gap-1">
|
<span class="w-28 sm:w-36 shrink-0 flex justify-center gap-1">
|
||||||
|
<Button variant="ghost" size="icon" class="h-7 w-7 rounded-md transition-all"
|
||||||
|
:class="env.enabled ? 'text-green-500 bg-green-500/10 hover:bg-green-500/20' : 'text-muted-foreground bg-muted/50 hover:bg-muted'"
|
||||||
|
@click="toggleEnabled(env)" :title="env.enabled ? '已启用(点击禁用)' : '已禁用(点击启用)'">
|
||||||
|
<Zap v-if="env.enabled" class="h-3.5 w-3.5 fill-current" />
|
||||||
|
<ZapOff v-else class="h-3.5 w-3.5" />
|
||||||
|
</Button>
|
||||||
<Button variant="ghost" size="icon" class="h-7 w-7" @click="toggleShow(env.id)"
|
<Button variant="ghost" size="icon" class="h-7 w-7" @click="toggleShow(env.id)"
|
||||||
:title="showValues[env.id] ? '隐藏' : '显示'">
|
:title="showValues[env.id] ? '隐藏' : '显示'">
|
||||||
<Eye v-if="!showValues[env.id]" class="h-3.5 w-3.5" />
|
<Eye v-if="!showValues[env.id]" class="h-3.5 w-3.5" />
|
||||||
@@ -225,6 +241,10 @@ onMounted(loadEnvVars)
|
|||||||
<Label class="text-sm font-medium">隐藏变量值</Label>
|
<Label class="text-sm font-medium">隐藏变量值</Label>
|
||||||
<Switch v-model="editingEnv.hidden" />
|
<Switch v-model="editingEnv.hidden" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex items-center justify-between space-x-2">
|
||||||
|
<Label class="text-sm font-medium">启用变量</Label>
|
||||||
|
<Switch v-model="editingEnv.enabled" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button variant="outline" @click="showDialog = false">取消</Button>
|
<Button variant="outline" @click="showDialog = false">取消</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user