Add registration Settings

This commit is contained in:
2025-10-24 08:25:16 +08:00
parent 1aff8ff459
commit 3d4f3e3f82
7 changed files with 511 additions and 25 deletions

View File

@@ -136,7 +136,7 @@ func setDefaults(config *AppConfig) {
config.Database.MySQL.MaxOpenConns = 100 config.Database.MySQL.MaxOpenConns = 100
} }
if config.Database.SQLite.Path == "" { if config.Database.SQLite.Path == "" {
config.Database.SQLite.Path = "./recharge.db" config.Database.SQLite.Path = "./database.db"
} }
// Redis默认值 // Redis默认值

View File

@@ -801,16 +801,18 @@ func AppGetBindConfigHandler(w http.ResponseWriter, r *http.Request) {
// 返回绑定配置信息 // 返回绑定配置信息
response := map[string]interface{}{ response := map[string]interface{}{
"machine_code_verify": app.MachineCodeVerify, "machine_code_verify": app.MachineCodeVerify,
"machine_code_option": app.MachineCodeOption, "machine_code_rebind_enabled": app.MachineCodeRebindEnabled,
"machine_code_free_count": app.MachineCodeFreeCount, "machine_code_option": app.MachineCodeOption,
"machine_code_rebind_count": app.MachineCodeRebindCount, "machine_code_free_count": app.MachineCodeFreeCount,
"machine_code_rebind_deduct": app.MachineCodeRebindDeduct, "machine_code_rebind_count": app.MachineCodeRebindCount,
"ip_verify": app.IPVerify, "machine_code_rebind_deduct": app.MachineCodeRebindDeduct,
"ip_option": app.IPOption, "ip_verify": app.IPVerify,
"ip_free_count": app.IPFreeCount, "ip_rebind_enabled": app.IPRebindEnabled,
"ip_rebind_count": app.IPRebindCount, "ip_option": app.IPOption,
"ip_rebind_deduct": app.IPRebindDeduct, "ip_free_count": app.IPFreeCount,
"ip_rebind_count": app.IPRebindCount,
"ip_rebind_deduct": app.IPRebindDeduct,
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@@ -827,11 +829,13 @@ func AppUpdateBindConfigHandler(w http.ResponseWriter, r *http.Request) {
var req struct { var req struct {
UUID string `json:"uuid"` UUID string `json:"uuid"`
MachineCodeVerify int `json:"machine_code_verify"` MachineCodeVerify int `json:"machine_code_verify"`
MachineCodeRebindEnabled int `json:"machine_code_rebind_enabled"`
MachineCodeOption int `json:"machine_code_option"` MachineCodeOption int `json:"machine_code_option"`
MachineCodeFreeCount int `json:"machine_code_free_count"` MachineCodeFreeCount int `json:"machine_code_free_count"`
MachineCodeRebindCount int `json:"machine_code_rebind_count"` MachineCodeRebindCount int `json:"machine_code_rebind_count"`
MachineCodeRebindDeduct int `json:"machine_code_rebind_deduct"` MachineCodeRebindDeduct int `json:"machine_code_rebind_deduct"`
IPVerify int `json:"ip_verify"` IPVerify int `json:"ip_verify"`
IPRebindEnabled int `json:"ip_rebind_enabled"`
IPOption int `json:"ip_option"` IPOption int `json:"ip_option"`
IPFreeCount int `json:"ip_free_count"` IPFreeCount int `json:"ip_free_count"`
IPRebindCount int `json:"ip_rebind_count"` IPRebindCount int `json:"ip_rebind_count"`
@@ -911,6 +915,26 @@ func AppUpdateBindConfigHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
if req.MachineCodeRebindEnabled < 0 || req.MachineCodeRebindEnabled > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "机器码重绑开关参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.IPRebindEnabled < 0 || req.IPRebindEnabled > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "IP地址重绑开关参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.MachineCodeFreeCount < 0 || req.MachineCodeRebindCount < 0 || req.MachineCodeRebindDeduct < 0 || if req.MachineCodeFreeCount < 0 || req.MachineCodeRebindCount < 0 || req.MachineCodeRebindDeduct < 0 ||
req.IPFreeCount < 0 || req.IPRebindCount < 0 || req.IPRebindDeduct < 0 { req.IPFreeCount < 0 || req.IPRebindCount < 0 || req.IPRebindDeduct < 0 {
response := map[string]interface{}{ response := map[string]interface{}{
@@ -949,16 +973,18 @@ func AppUpdateBindConfigHandler(w http.ResponseWriter, r *http.Request) {
// 更新绑定配置 // 更新绑定配置
updates := map[string]interface{}{ updates := map[string]interface{}{
"machine_code_verify": req.MachineCodeVerify, "machine_code_verify": req.MachineCodeVerify,
"machine_code_option": req.MachineCodeOption, "machine_code_rebind_enabled": req.MachineCodeRebindEnabled,
"machine_code_free_count": req.MachineCodeFreeCount, "machine_code_option": req.MachineCodeOption,
"machine_code_rebind_count": req.MachineCodeRebindCount, "machine_code_free_count": req.MachineCodeFreeCount,
"machine_code_rebind_deduct": req.MachineCodeRebindDeduct, "machine_code_rebind_count": req.MachineCodeRebindCount,
"ip_verify": req.IPVerify, "machine_code_rebind_deduct": req.MachineCodeRebindDeduct,
"ip_option": req.IPOption, "ip_verify": req.IPVerify,
"ip_free_count": req.IPFreeCount, "ip_rebind_enabled": req.IPRebindEnabled,
"ip_rebind_count": req.IPRebindCount, "ip_option": req.IPOption,
"ip_rebind_deduct": req.IPRebindDeduct, "ip_free_count": req.IPFreeCount,
"ip_rebind_count": req.IPRebindCount,
"ip_rebind_deduct": req.IPRebindDeduct,
} }
if err := db.Model(&app).Updates(updates).Error; err != nil { if err := db.Model(&app).Updates(updates).Error; err != nil {
@@ -980,3 +1006,248 @@ func AppUpdateBindConfigHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response) json.NewEncoder(w).Encode(response)
} }
// AppGetRegisterConfigHandler 获取应用注册配置
func AppGetRegisterConfigHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
appUUID := r.URL.Query().Get("uuid")
if appUUID == "" {
response := map[string]interface{}{
"code": 1,
"msg": "缺少应用UUID",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 验证UUID格式
if _, err := uuid.Parse(appUUID); err != nil {
response := map[string]interface{}{
"code": 1,
"msg": "无效的UUID格式",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
response := map[string]interface{}{
"code": 1,
"msg": "数据库连接失败",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
var app models.App
if err := db.Where("uuid = ?", appUUID).First(&app).Error; err != nil {
logrus.WithError(err).Error("Failed to find app")
response := map[string]interface{}{
"code": 1,
"msg": "应用不存在",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 返回注册配置信息
response := map[string]interface{}{
"register_enabled": app.RegisterEnabled,
"register_limit_enabled": app.RegisterLimitEnabled,
"register_limit_time": app.RegisterLimitTime,
"register_count": app.RegisterCount,
"trial_enabled": app.TrialEnabled,
"trial_limit_time": app.TrialLimitTime,
"trial_duration": app.TrialDuration,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// AppUpdateRegisterConfigHandler 更新应用注册配置
func AppUpdateRegisterConfigHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var req struct {
UUID string `json:"uuid"`
RegisterEnabled int `json:"register_enabled"`
RegisterLimitEnabled int `json:"register_limit_enabled"`
RegisterLimitTime int `json:"register_limit_time"`
RegisterCount int `json:"register_count"`
TrialEnabled int `json:"trial_enabled"`
TrialLimitTime int `json:"trial_limit_time"`
TrialDuration int `json:"trial_duration"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
logrus.WithError(err).Error("Failed to decode JSON request")
response := map[string]interface{}{
"code": 1,
"msg": "无效的JSON格式",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 验证UUID
if req.UUID == "" {
response := map[string]interface{}{
"code": 1,
"msg": "应用UUID不能为空",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if _, err := uuid.Parse(req.UUID); err != nil {
response := map[string]interface{}{
"code": 1,
"msg": "无效的UUID格式",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 验证参数范围
if req.RegisterEnabled < 0 || req.RegisterEnabled > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "账号注册开关参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.RegisterLimitEnabled < 0 || req.RegisterLimitEnabled > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "注册限制开关参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.RegisterLimitTime < 0 || req.RegisterLimitTime > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "注册限制时间参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.RegisterCount < 1 {
response := map[string]interface{}{
"code": 1,
"msg": "注册次数必须大于0",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.TrialEnabled < 0 || req.TrialEnabled > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "领取试用开关参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.TrialLimitTime < 0 || req.TrialLimitTime > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "试用限制时间参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.TrialDuration < 0 {
response := map[string]interface{}{
"code": 1,
"msg": "试用时间不能为负数",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
response := map[string]interface{}{
"code": 1,
"msg": "数据库连接失败",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 查找应用
var app models.App
if err := db.Where("uuid = ?", req.UUID).First(&app).Error; err != nil {
logrus.WithError(err).Error("Failed to find app")
response := map[string]interface{}{
"code": 1,
"msg": "应用不存在",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 更新注册配置
updates := map[string]interface{}{
"register_enabled": req.RegisterEnabled,
"register_limit_enabled": req.RegisterLimitEnabled,
"register_limit_time": req.RegisterLimitTime,
"register_count": req.RegisterCount,
"trial_enabled": req.TrialEnabled,
"trial_limit_time": req.TrialLimitTime,
"trial_duration": req.TrialDuration,
}
if err := db.Model(&app).Updates(updates).Error; err != nil {
logrus.WithError(err).Error("Failed to update app register config")
response := map[string]interface{}{
"code": 1,
"msg": "更新注册配置失败",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
response := map[string]interface{}{
"code": 0,
"msg": "注册配置更新成功",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}

View File

@@ -1,9 +1,10 @@
package admin package admin
import ( import (
"crypto/rand"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"math/rand" "math/big"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@@ -14,6 +15,15 @@ import (
// 全局验证码存储器 // 全局验证码存储器
var store = base64Captcha.DefaultMemStore var store = base64Captcha.DefaultMemStore
// secureRandomInt 生成安全的随机整数,范围 [0, max)
func secureRandomInt(max int) (int, error) {
n, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
if err != nil {
return 0, err
}
return int(n.Int64()), nil
}
// CaptchaHandler 生成验证码图片 // CaptchaHandler 生成验证码图片
// GET /admin/captcha - 返回验证码图片 // GET /admin/captcha - 返回验证码图片
func CaptchaHandler(w http.ResponseWriter, r *http.Request) { func CaptchaHandler(w http.ResponseWriter, r *http.Request) {
@@ -23,8 +33,13 @@ func CaptchaHandler(w http.ResponseWriter, r *http.Request) {
} }
// 随机生成4-6位长度 // 随机生成4-6位长度
// Go 1.20+ 无需手动设置随机种子,使用默认全局随机源即可 // 使用crypto/rand生成安全的随机数
captchaLength := 4 + rand.Intn(3) // 4-6位随机长度 randomNum, err := secureRandomInt(3)
if err != nil {
http.Error(w, "生成随机数失败", http.StatusInternalServerError)
return
}
captchaLength := 4 + randomNum // 4-6位随机长度
// 配置验证码参数 - 使用字母数字混合 // 配置验证码参数 - 使用字母数字混合
driver := base64Captcha.DriverString{ driver := base64Captcha.DriverString{

View File

@@ -78,7 +78,7 @@ func GetDB() (*gorm.DB, error) {
func initSQLite() error { func initSQLite() error {
path := viper.GetString("database.sqlite.path") path := viper.GetString("database.sqlite.path")
if path == "" { if path == "" {
path = "./recharge.db" path = "./database.db"
} }
dsn := fmt.Sprintf("file:%s?cache=shared&_busy_timeout=5000&_fk=1", path) dsn := fmt.Sprintf("file:%s?cache=shared&_busy_timeout=5000&_fk=1", path)
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{}) db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{})

View File

@@ -56,6 +56,8 @@ type App struct {
// 机器码验证相关字段 // 机器码验证相关字段
// MachineCodeVerify机器码验证0=关闭1=开启) // MachineCodeVerify机器码验证0=关闭1=开启)
MachineCodeVerify int `gorm:"default:0;not null;comment:机器码验证0=关闭1=开启" json:"machine_code_verify"` MachineCodeVerify int `gorm:"default:0;not null;comment:机器码验证0=关闭1=开启" json:"machine_code_verify"`
// MachineCodeRebindEnabled机器码重绑开关0=关闭1=开启)
MachineCodeRebindEnabled int `gorm:"default:0;not null;comment:机器码重绑开关0=关闭1=开启" json:"machine_code_rebind_enabled"`
// MachineCodeOption机器码选项0=每天1=永久) // MachineCodeOption机器码选项0=每天1=永久)
MachineCodeOption int `gorm:"default:0;not null;comment:机器码选项0=每天1=永久" json:"machine_code_option"` MachineCodeOption int `gorm:"default:0;not null;comment:机器码选项0=每天1=永久" json:"machine_code_option"`
// MachineCodeFreeCount机器码免费次数默认0 // MachineCodeFreeCount机器码免费次数默认0
@@ -68,6 +70,8 @@ type App struct {
// IP地址验证相关字段 // IP地址验证相关字段
// IPVerifyIP地址验证0=关闭1=开启2=开启(市)3=开启(省) // IPVerifyIP地址验证0=关闭1=开启2=开启(市)3=开启(省)
IPVerify int `gorm:"default:0;not null;comment:IP地址验证0=关闭1=开启2=开启(市)3=开启(省)" json:"ip_verify"` IPVerify int `gorm:"default:0;not null;comment:IP地址验证0=关闭1=开启2=开启(市)3=开启(省)" json:"ip_verify"`
// IPRebindEnabledIP地址重绑开关0=关闭1=开启)
IPRebindEnabled int `gorm:"default:0;not null;comment:IP地址重绑开关0=关闭1=开启" json:"ip_rebind_enabled"`
// IPOptionIP地址选项0=每天1=永久) // IPOptionIP地址选项0=每天1=永久)
IPOption int `gorm:"default:0;not null;comment:IP地址选项0=每天1=永久" json:"ip_option"` IPOption int `gorm:"default:0;not null;comment:IP地址选项0=每天1=永久" json:"ip_option"`
// IPFreeCountIP地址免费次数默认0 // IPFreeCountIP地址免费次数默认0
@@ -77,6 +81,24 @@ type App struct {
// IPRebindDeductIP地址重绑扣除默认0单位分钟 // IPRebindDeductIP地址重绑扣除默认0单位分钟
IPRebindDeduct int `gorm:"default:0;not null;comment:IP地址重绑扣除单位分钟" json:"ip_rebind_deduct"` IPRebindDeduct int `gorm:"default:0;not null;comment:IP地址重绑扣除单位分钟" json:"ip_rebind_deduct"`
// 账号注册相关字段
// RegisterEnabled账号注册开关0=关闭1=开启)
RegisterEnabled int `gorm:"default:1;not null;comment:账号注册开关0=关闭1=开启" json:"register_enabled"`
// RegisterLimitEnabled注册限制开关0=关闭1=开启)
RegisterLimitEnabled int `gorm:"default:0;not null;comment:注册限制开关0=关闭1=开启" json:"register_limit_enabled"`
// RegisterLimitTime限制时间0=每天1=永久)
RegisterLimitTime int `gorm:"default:1;not null;comment:注册限制时间0=每天1=永久" json:"register_limit_time"`
// RegisterCount注册次数
RegisterCount int `gorm:"default:1;not null;comment:注册次数" json:"register_count"`
// 领取试用相关字段
// TrialEnabled领取试用开关0=关闭1=开启)
TrialEnabled int `gorm:"default:0;not null;comment:领取试用开关0=关闭1=开启" json:"trial_enabled"`
// TrialLimitTime试用限制时间0=每天1=永久)
TrialLimitTime int `gorm:"default:1;not null;comment:试用限制时间0=每天1=永久" json:"trial_limit_time"`
// TrialDuration试用时间单位分钟
TrialDuration int `gorm:"default:0;not null;comment:试用时间,单位分钟" json:"trial_duration"`
// CreatedAt/UpdatedAt时间字段返回为 created_at/updated_at便于前端展示 // CreatedAt/UpdatedAt时间字段返回为 created_at/updated_at便于前端展示
CreatedAt time.Time `gorm:"comment:创建时间" json:"created_at"` CreatedAt time.Time `gorm:"comment:创建时间" json:"created_at"`
UpdatedAt time.Time `gorm:"comment:更新时间" json:"updated_at"` UpdatedAt time.Time `gorm:"comment:更新时间" json:"updated_at"`

View File

@@ -67,6 +67,8 @@ func RegisterAdminRoutes(mux *http.ServeMux) {
mux.HandleFunc("/admin/api/apps/update_multi_config", adminctl.AdminAuthRequired(adminctl.AppUpdateMultiConfigHandler)) mux.HandleFunc("/admin/api/apps/update_multi_config", adminctl.AdminAuthRequired(adminctl.AppUpdateMultiConfigHandler))
mux.HandleFunc("/admin/api/apps/get_bind_config", adminctl.AdminAuthRequired(adminctl.AppGetBindConfigHandler)) mux.HandleFunc("/admin/api/apps/get_bind_config", adminctl.AdminAuthRequired(adminctl.AppGetBindConfigHandler))
mux.HandleFunc("/admin/api/apps/update_bind_config", adminctl.AdminAuthRequired(adminctl.AppUpdateBindConfigHandler)) mux.HandleFunc("/admin/api/apps/update_bind_config", adminctl.AdminAuthRequired(adminctl.AppUpdateBindConfigHandler))
mux.HandleFunc("/admin/api/apps/get_register_config", adminctl.AdminAuthRequired(adminctl.AppGetRegisterConfigHandler))
mux.HandleFunc("/admin/api/apps/update_register_config", adminctl.AdminAuthRequired(adminctl.AppUpdateRegisterConfigHandler))
// 系统信息API用于仪表盘定时刷新 // 系统信息API用于仪表盘定时刷新

View File

@@ -330,6 +330,10 @@
title: '绑定设置', title: '绑定设置',
id: 'bind_settings' id: 'bind_settings'
}, },
{
title: '注册设置',
id: 'register_settings'
},
{ {
title: '重置密钥', title: '重置密钥',
id: 'reset_secret' id: 'reset_secret'
@@ -578,6 +582,13 @@
'</div>' + '</div>' +
'</div>' + '</div>' +
'<div class="layui-form-item" pane>' + '<div class="layui-form-item" pane>' +
'<label class="layui-form-label">机器码重绑</label>' +
'<div class="layui-input-block">' +
'<input type="radio" name="machine_code_rebind_enabled" value="0" title="关闭" ' + (config.machine_code_rebind_enabled === 0 ? 'checked' : '') + '>' +
'<input type="radio" name="machine_code_rebind_enabled" value="1" title="开启" ' + (config.machine_code_rebind_enabled === 1 ? 'checked' : '') + '>' +
'</div>' +
'</div>' +
'<div class="layui-form-item" pane>' +
'<label class="layui-form-label">机器码选项</label>' + '<label class="layui-form-label">机器码选项</label>' +
'<div class="layui-input-block">' + '<div class="layui-input-block">' +
'<input type="radio" name="machine_code_option" value="0" title="每天" ' + (config.machine_code_option === 0 ? 'checked' : '') + '>' + '<input type="radio" name="machine_code_option" value="0" title="每天" ' + (config.machine_code_option === 0 ? 'checked' : '') + '>' +
@@ -617,6 +628,13 @@
'</div>' + '</div>' +
'</div>' + '</div>' +
'<div class="layui-form-item" pane>' + '<div class="layui-form-item" pane>' +
'<label class="layui-form-label">IP地址重绑</label>' +
'<div class="layui-input-block">' +
'<input type="radio" name="ip_rebind_enabled" value="0" title="关闭" ' + (config.ip_rebind_enabled === 0 ? 'checked' : '') + '>' +
'<input type="radio" name="ip_rebind_enabled" value="1" title="开启" ' + (config.ip_rebind_enabled === 1 ? 'checked' : '') + '>' +
'</div>' +
'</div>' +
'<div class="layui-form-item" pane>' +
'<label class="layui-form-label">IP地址选项</label>' + '<label class="layui-form-label">IP地址选项</label>' +
'<div class="layui-input-block">' + '<div class="layui-input-block">' +
'<input type="radio" name="ip_option" value="0" title="每天" ' + (config.ip_option === 0 ? 'checked' : '') + '>' + '<input type="radio" name="ip_option" value="0" title="每天" ' + (config.ip_option === 0 ? 'checked' : '') + '>' +
@@ -649,11 +667,13 @@
var formData = { var formData = {
uuid: obj.data.uuid, uuid: obj.data.uuid,
machine_code_verify: parseInt($('input[name="machine_code_verify"]:checked').val()), machine_code_verify: parseInt($('input[name="machine_code_verify"]:checked').val()),
machine_code_rebind_enabled: parseInt($('input[name="machine_code_rebind_enabled"]:checked').val()),
machine_code_option: parseInt($('input[name="machine_code_option"]:checked').val()), machine_code_option: parseInt($('input[name="machine_code_option"]:checked').val()),
machine_code_free_count: parseInt($('input[name="machine_code_free_count"]').val()) || 0, machine_code_free_count: parseInt($('input[name="machine_code_free_count"]').val()) || 0,
machine_code_rebind_count: parseInt($('input[name="machine_code_rebind_count"]').val()) || 0, machine_code_rebind_count: parseInt($('input[name="machine_code_rebind_count"]').val()) || 0,
machine_code_rebind_deduct: parseInt($('input[name="machine_code_rebind_deduct"]').val()) || 0, machine_code_rebind_deduct: parseInt($('input[name="machine_code_rebind_deduct"]').val()) || 0,
ip_verify: parseInt($('input[name="ip_verify"]:checked').val()), ip_verify: parseInt($('input[name="ip_verify"]:checked').val()),
ip_rebind_enabled: parseInt($('input[name="ip_rebind_enabled"]:checked').val()),
ip_option: parseInt($('input[name="ip_option"]:checked').val()), ip_option: parseInt($('input[name="ip_option"]:checked').val()),
ip_free_count: parseInt($('input[name="ip_free_count"]').val()) || 0, ip_free_count: parseInt($('input[name="ip_free_count"]').val()) || 0,
ip_rebind_count: parseInt($('input[name="ip_rebind_count"]').val()) || 0, ip_rebind_count: parseInt($('input[name="ip_rebind_count"]').val()) || 0,
@@ -665,6 +685,10 @@
layer.msg('请选择机器码验证选项', {icon: 2}); layer.msg('请选择机器码验证选项', {icon: 2});
return; return;
} }
if (isNaN(formData.machine_code_rebind_enabled) || formData.machine_code_rebind_enabled < 0 || formData.machine_code_rebind_enabled > 1) {
layer.msg('请选择机器码重绑选项', {icon: 2});
return;
}
if (isNaN(formData.machine_code_option) || formData.machine_code_option < 0 || formData.machine_code_option > 1) { if (isNaN(formData.machine_code_option) || formData.machine_code_option < 0 || formData.machine_code_option > 1) {
layer.msg('请选择机器码选项', {icon: 2}); layer.msg('请选择机器码选项', {icon: 2});
return; return;
@@ -673,6 +697,10 @@
layer.msg('请选择IP地址验证选项', {icon: 2}); layer.msg('请选择IP地址验证选项', {icon: 2});
return; return;
} }
if (isNaN(formData.ip_rebind_enabled) || formData.ip_rebind_enabled < 0 || formData.ip_rebind_enabled > 1) {
layer.msg('请选择IP地址重绑选项', {icon: 2});
return;
}
if (isNaN(formData.ip_option) || formData.ip_option < 0 || formData.ip_option > 1) { if (isNaN(formData.ip_option) || formData.ip_option < 0 || formData.ip_option > 1) {
layer.msg('请选择IP地址选项', {icon: 2}); layer.msg('请选择IP地址选项', {icon: 2});
return; return;
@@ -711,6 +739,154 @@
layer.msg('获取绑定设置失败,请稍后重试', {icon: 2}); layer.msg('获取绑定设置失败,请稍后重试', {icon: 2});
} }
}); });
} else if (menudata.id === 'register_settings') {
// 注册设置
$.ajax({
url: '/admin/api/apps/get_register_config?uuid=' + obj.data.uuid,
type: 'GET',
success: function(config) {
layer.open({
type: 1,
title: '注册设置 - ' + obj.data.name,
area: ['550px', '500px'],
content: '<div style="padding: 20px;">' +
'<form class="layui-form layui-form-pane" lay-filter="registerConfigForm">' +
// 账号注册设置
'<fieldset class="layui-elem-field layui-field-title">' +
'<legend>账号注册设置</legend>' +
'</fieldset>' +
'<div class="layui-form-item" pane>' +
'<label class="layui-form-label">账号注册</label>' +
'<div class="layui-input-block">' +
'<input type="radio" name="register_enabled" value="0" title="关闭" ' + (config.register_enabled === 0 ? 'checked' : '') + '>' +
'<input type="radio" name="register_enabled" value="1" title="开启" ' + (config.register_enabled === 1 ? 'checked' : '') + '>' +
'</div>' +
'</div>' +
'<div class="layui-form-item" pane>' +
'<label class="layui-form-label">注册限制</label>' +
'<div class="layui-input-block">' +
'<input type="radio" name="register_limit_enabled" value="0" title="关闭" ' + (config.register_limit_enabled === 0 ? 'checked' : '') + '>' +
'<input type="radio" name="register_limit_enabled" value="1" title="开启" ' + (config.register_limit_enabled === 1 ? 'checked' : '') + '>' +
'</div>' +
'</div>' +
'<div class="layui-form-item" pane>' +
'<label class="layui-form-label">限制时间</label>' +
'<div class="layui-input-block">' +
'<input type="radio" name="register_limit_time" value="0" title="每天" ' + (config.register_limit_time === 0 ? 'checked' : '') + '>' +
'<input type="radio" name="register_limit_time" value="1" title="永久" ' + (config.register_limit_time === 1 ? 'checked' : '') + '>' +
'</div>' +
'</div>' +
'<div class="layui-form-item">' +
'<label class="layui-form-label">注册次数</label>' +
'<div class="layui-input-block">' +
'<input type="number" name="register_count" class="layui-input" value="' + config.register_count + '" placeholder="请输入" lay-verify="required|number" min="1">' +
'</div>' +
'</div>' +
// 领取试用设置
'<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">' +
'<legend>领取试用设置</legend>' +
'</fieldset>' +
'<div class="layui-form-item" pane>' +
'<label class="layui-form-label">领取试用</label>' +
'<div class="layui-input-block">' +
'<input type="radio" name="trial_enabled" value="0" title="关闭" ' + (config.trial_enabled === 0 ? 'checked' : '') + '>' +
'<input type="radio" name="trial_enabled" value="1" title="开启" ' + (config.trial_enabled === 1 ? 'checked' : '') + '>' +
'</div>' +
'</div>' +
'<div class="layui-form-item" pane>' +
'<label class="layui-form-label">限制时间</label>' +
'<div class="layui-input-block">' +
'<input type="radio" name="trial_limit_time" value="0" title="每天" ' + (config.trial_limit_time === 0 ? 'checked' : '') + '>' +
'<input type="radio" name="trial_limit_time" value="1" title="永久" ' + (config.trial_limit_time === 1 ? 'checked' : '') + '>' +
'</div>' +
'</div>' +
'<div class="layui-form-item">' +
'<label class="layui-form-label">试用时间</label>' +
'<div class="layui-input-block">' +
'<input type="number" name="trial_duration" class="layui-input" value="' + config.trial_duration + '" placeholder="请输入试用时间(分钟)" lay-verify="number" min="0">' +
'</div>' +
'</div>' +
'</form>' +
'</div>',
btn: ['保存', '取消'],
yes: function(index, layero) {
var formData = {
uuid: obj.data.uuid,
register_enabled: parseInt($('input[name="register_enabled"]:checked').val()),
register_limit_enabled: parseInt($('input[name="register_limit_enabled"]:checked').val()),
register_limit_time: parseInt($('input[name="register_limit_time"]:checked').val()),
register_count: parseInt($('input[name="register_count"]').val()) || 1,
trial_enabled: parseInt($('input[name="trial_enabled"]:checked').val()),
trial_limit_time: parseInt($('input[name="trial_limit_time"]:checked').val()),
trial_duration: parseInt($('input[name="trial_duration"]').val()) || 0
};
// 验证数据
if (isNaN(formData.register_enabled) || formData.register_enabled < 0 || formData.register_enabled > 1) {
layer.msg('请选择账号注册选项', {icon: 2});
return;
}
if (isNaN(formData.register_limit_enabled) || formData.register_limit_enabled < 0 || formData.register_limit_enabled > 1) {
layer.msg('请选择注册限制选项', {icon: 2});
return;
}
if (isNaN(formData.register_limit_time) || formData.register_limit_time < 0 || formData.register_limit_time > 1) {
layer.msg('请选择限制时间选项', {icon: 2});
return;
}
if (isNaN(formData.register_count) || formData.register_count < 1) {
layer.msg('注册次数必须大于0', {icon: 2});
return;
}
if (isNaN(formData.trial_enabled) || formData.trial_enabled < 0 || formData.trial_enabled > 1) {
layer.msg('请选择领取试用选项', {icon: 2});
return;
}
if (isNaN(formData.trial_limit_time) || formData.trial_limit_time < 0 || formData.trial_limit_time > 1) {
layer.msg('请选择试用限制时间选项', {icon: 2});
return;
}
if (isNaN(formData.trial_duration) || formData.trial_duration < 0) {
layer.msg('试用时间不能小于0', {icon: 2});
return;
}
// 发送更新请求
$.ajax({
url: '/admin/api/apps/update_register_config',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(formData),
success: function(res) {
if (res.code === 0) {
layer.msg('注册设置更新成功', {icon: 1});
layer.close(index);
table.reload('appsTable');
} else {
layer.msg(res.msg || '更新注册设置失败', {icon: 2});
}
},
error: function() {
layer.msg('网络错误,请稍后重试', {icon: 2});
}
});
},
btn2: function(index) {
layer.close(index);
},
success: function() {
// 重新渲染表单
form.render();
}
});
},
error: function() {
layer.msg('获取注册设置失败,请稍后重试', {icon: 2});
}
});
} }
}, },
align: 'right', // 右对齐弹出 align: 'right', // 右对齐弹出