mirror of
https://github.com/skyle1995/NetworkAuth.git
synced 2026-05-25 02:24:05 +08:00
Add application variables
This commit is contained in:
@@ -168,7 +168,7 @@ func APIUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var req struct {
|
var req struct {
|
||||||
ID uint `json:"id"`
|
UUID string `json:"uuid"`
|
||||||
Status int `json:"status"`
|
Status int `json:"status"`
|
||||||
SubmitAlgorithm int `json:"submit_algorithm"`
|
SubmitAlgorithm int `json:"submit_algorithm"`
|
||||||
ReturnAlgorithm int `json:"return_algorithm"`
|
ReturnAlgorithm int `json:"return_algorithm"`
|
||||||
@@ -184,8 +184,8 @@ func APIUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 验证必填字段
|
// 验证必填字段
|
||||||
if req.ID == 0 {
|
if strings.TrimSpace(req.UUID) == "" {
|
||||||
http.Error(w, "接口ID不能为空", http.StatusBadRequest)
|
http.Error(w, "接口UUID不能为空", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +209,7 @@ func APIUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// 查找并更新API记录
|
// 查找并更新API记录
|
||||||
var api models.API
|
var api models.API
|
||||||
if err := db.First(&api, req.ID).Error; err != nil {
|
if err := db.Where("uuid = ?", strings.TrimSpace(req.UUID)).First(&api).Error; err != nil {
|
||||||
http.Error(w, "接口不存在", http.StatusNotFound)
|
http.Error(w, "接口不存在", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
429
controllers/admin/variable.go
Normal file
429
controllers/admin/variable.go
Normal file
@@ -0,0 +1,429 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"networkDev/database"
|
||||||
|
"networkDev/models"
|
||||||
|
"networkDev/utils"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// VariableFragmentHandler 变量列表页面片段处理器
|
||||||
|
func VariableFragmentHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
utils.RenderTemplate(w, "variables", map[string]interface{}{
|
||||||
|
"Title": "变量管理",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// VariableListHandler 变量列表API处理器
|
||||||
|
func VariableListHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodGet {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取分页参数
|
||||||
|
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
|
||||||
|
if page <= 0 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
|
if limit <= 0 {
|
||||||
|
limit = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取应用UUID参数(用于按应用筛选变量)
|
||||||
|
appUUID := strings.TrimSpace(r.URL.Query().Get("app_uuid"))
|
||||||
|
|
||||||
|
// 获取别名搜索参数
|
||||||
|
alias := strings.TrimSpace(r.URL.Query().Get("alias"))
|
||||||
|
|
||||||
|
// 构建查询
|
||||||
|
db, err := database.GetDB()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to get database connection")
|
||||||
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建基础查询
|
||||||
|
query := db.Model(&models.Variable{})
|
||||||
|
|
||||||
|
// 如果指定了应用UUID,则按应用筛选
|
||||||
|
if appUUID != "" {
|
||||||
|
query = query.Where("app_uuid = ?", appUUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果指定了别名搜索,则按别名模糊搜索
|
||||||
|
if alias != "" {
|
||||||
|
query = query.Where("alias LIKE ?", "%"+alias+"%")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取总数
|
||||||
|
var total int64
|
||||||
|
if err := query.Count(&total).Error; err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to count variables")
|
||||||
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取分页数据
|
||||||
|
var variables []models.Variable
|
||||||
|
offset := (page - 1) * limit
|
||||||
|
if err := query.Offset(offset).Limit(limit).Order("created_at DESC").Find(&variables).Error; err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to fetch variables")
|
||||||
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取关联的应用信息
|
||||||
|
var appUUIDs []string
|
||||||
|
for _, variable := range variables {
|
||||||
|
appUUIDs = append(appUUIDs, variable.AppUUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
var apps []models.App
|
||||||
|
if len(appUUIDs) > 0 {
|
||||||
|
if err := db.Where("uuid IN ?", appUUIDs).Find(&apps).Error; err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to fetch related apps")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建应用UUID到应用名称的映射
|
||||||
|
appMap := make(map[string]string)
|
||||||
|
for _, app := range apps {
|
||||||
|
appMap[app.UUID] = app.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建响应数据
|
||||||
|
type VariableResponse struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
UUID string `json:"uuid"`
|
||||||
|
Number string `json:"number"`
|
||||||
|
AppUUID string `json:"app_uuid"`
|
||||||
|
AppName string `json:"app_name"`
|
||||||
|
Alias string `json:"alias"`
|
||||||
|
Data string `json:"data"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var responseData []VariableResponse
|
||||||
|
for _, variable := range variables {
|
||||||
|
appName := appMap[variable.AppUUID]
|
||||||
|
if appName == "" {
|
||||||
|
appName = "未知应用"
|
||||||
|
}
|
||||||
|
|
||||||
|
responseData = append(responseData, VariableResponse{
|
||||||
|
ID: variable.ID,
|
||||||
|
UUID: variable.UUID,
|
||||||
|
Number: variable.Number,
|
||||||
|
AppUUID: variable.AppUUID,
|
||||||
|
AppName: appName,
|
||||||
|
Alias: variable.Alias,
|
||||||
|
Data: variable.Data,
|
||||||
|
Remark: variable.Remark,
|
||||||
|
CreatedAt: variable.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||||
|
UpdatedAt: variable.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
response := map[string]interface{}{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "success",
|
||||||
|
"count": total,
|
||||||
|
"data": responseData,
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
utils.WriteJSONResponse(w, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VariableCreateHandler 新增变量API处理器
|
||||||
|
func VariableCreateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var req struct {
|
||||||
|
AppUUID string `json:"app_uuid"`
|
||||||
|
Alias string `json:"alias"`
|
||||||
|
Data string `json:"data"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to decode JSON request")
|
||||||
|
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证必填字段
|
||||||
|
if strings.TrimSpace(req.AppUUID) == "" {
|
||||||
|
http.Error(w, "应用UUID不能为空", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(req.Alias) == "" {
|
||||||
|
http.Error(w, "变量别名不能为空", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证别名格式:必须以英文字母开头,只能包含数字和英文字母
|
||||||
|
aliasPattern := regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9]*$`)
|
||||||
|
if !aliasPattern.MatchString(req.Alias) {
|
||||||
|
http.Error(w, "别名必须以英文字母开头,只能包含数字和英文字母", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := database.GetDB()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to get database connection")
|
||||||
|
http.Error(w, "数据库连接失败", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证应用是否存在
|
||||||
|
var app models.App
|
||||||
|
if err := db.Where("uuid = ?", req.AppUUID).First(&app).Error; err != nil {
|
||||||
|
http.Error(w, "应用不存在", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建变量
|
||||||
|
variable := models.Variable{
|
||||||
|
AppUUID: strings.TrimSpace(req.AppUUID),
|
||||||
|
Alias: strings.TrimSpace(req.Alias),
|
||||||
|
Data: req.Data,
|
||||||
|
Remark: strings.TrimSpace(req.Remark),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Create(&variable).Error; err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to create variable")
|
||||||
|
http.Error(w, "创建变量失败", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response := map[string]interface{}{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "创建成功",
|
||||||
|
"data": variable,
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VariableUpdateHandler 更新变量API处理器
|
||||||
|
func VariableUpdateHandler(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"`
|
||||||
|
AppUUID string `json:"app_uuid"`
|
||||||
|
Alias string `json:"alias"`
|
||||||
|
Data string `json:"data"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证必填字段
|
||||||
|
if strings.TrimSpace(req.UUID) == "" {
|
||||||
|
http.Error(w, "变量UUID不能为空", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(req.AppUUID) == "" {
|
||||||
|
http.Error(w, "应用UUID不能为空", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(req.Alias) == "" {
|
||||||
|
http.Error(w, "变量别名不能为空", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证别名格式:必须以英文字母开头,只能包含数字和英文字母
|
||||||
|
aliasPattern := regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9]*$`)
|
||||||
|
if !aliasPattern.MatchString(req.Alias) {
|
||||||
|
http.Error(w, "别名必须以英文字母开头,只能包含数字和英文字母", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := database.GetDB()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to get database connection")
|
||||||
|
http.Error(w, "数据库连接失败", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证应用是否存在
|
||||||
|
var app models.App
|
||||||
|
if err := db.Where("uuid = ?", req.AppUUID).First(&app).Error; err != nil {
|
||||||
|
http.Error(w, "应用不存在", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过uuid字段查找变量
|
||||||
|
var variable models.Variable
|
||||||
|
if err := db.Where("uuid = ?", strings.TrimSpace(req.UUID)).First(&variable).Error; err != nil {
|
||||||
|
http.Error(w, "变量不存在", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新字段
|
||||||
|
variable.AppUUID = strings.TrimSpace(req.AppUUID)
|
||||||
|
variable.Alias = strings.TrimSpace(req.Alias)
|
||||||
|
variable.Data = req.Data
|
||||||
|
variable.Remark = strings.TrimSpace(req.Remark)
|
||||||
|
|
||||||
|
if err := db.Save(&variable).Error; err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to update variable")
|
||||||
|
http.Error(w, "更新变量失败", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response := map[string]interface{}{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "更新成功",
|
||||||
|
"data": variable,
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VariableDeleteHandler 删除变量API处理器
|
||||||
|
func VariableDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var req struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.ID == 0 {
|
||||||
|
http.Error(w, "变量ID不能为空", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := database.GetDB()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to get database connection")
|
||||||
|
http.Error(w, "数据库连接失败", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除变量
|
||||||
|
if err := db.Delete(&models.Variable{}, req.ID).Error; err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to delete variable")
|
||||||
|
http.Error(w, "删除变量失败", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithField("variable_id", req.ID).Info("Successfully deleted variable")
|
||||||
|
|
||||||
|
response := map[string]interface{}{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "删除成功",
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VariablesBatchDeleteHandler 批量删除变量API处理器
|
||||||
|
func VariablesBatchDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var req struct {
|
||||||
|
IDs []uint `json:"ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.IDs) == 0 {
|
||||||
|
http.Error(w, "请选择要删除的变量", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := database.GetDB()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to get database connection")
|
||||||
|
http.Error(w, "数据库连接失败", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量删除变量
|
||||||
|
if err := db.Delete(&models.Variable{}, req.IDs).Error; err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to batch delete variables")
|
||||||
|
http.Error(w, "批量删除失败", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithField("variable_ids", req.IDs).Info("Successfully batch deleted variables")
|
||||||
|
|
||||||
|
response := map[string]interface{}{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "批量删除成功",
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VariableGetAppsHandler 获取应用列表(用于筛选下拉框)
|
||||||
|
func VariableGetAppsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodGet {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := database.GetDB()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to get database connection")
|
||||||
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var apps []models.App
|
||||||
|
if err := db.Select("uuid, name").Find(&apps).Error; err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to fetch apps")
|
||||||
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response := map[string]interface{}{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "success",
|
||||||
|
"data": apps,
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
utils.WriteJSONResponse(w, http.StatusOK, response)
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ func AutoMigrate() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := db.AutoMigrate(&models.User{}, &models.Settings{}, &models.App{}, &models.API{}); err != nil {
|
if err := db.AutoMigrate(&models.User{}, &models.Settings{}, &models.App{}, &models.API{}, &models.Variable{}); err != nil {
|
||||||
logrus.WithError(err).Error("AutoMigrate 执行失败")
|
logrus.WithError(err).Error("AutoMigrate 执行失败")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// API 接口表模型
|
// API 接口表模型
|
||||||
@@ -13,6 +17,9 @@ type API struct {
|
|||||||
// ID:主键,自增
|
// ID:主键,自增
|
||||||
ID uint `gorm:"primaryKey;comment:API接口ID,自增主键" json:"id"`
|
ID uint `gorm:"primaryKey;comment:API接口ID,自增主键" json:"id"`
|
||||||
|
|
||||||
|
// UUID:API接口唯一标识符,自动生成
|
||||||
|
UUID string `gorm:"uniqueIndex;size:36;not null;comment:API接口UUID,唯一标识符" json:"uuid"`
|
||||||
|
|
||||||
// API类型(int型)
|
// API类型(int型)
|
||||||
APIType int `gorm:"not null;comment:API类型" json:"api_type"`
|
APIType int `gorm:"not null;comment:API类型" json:"api_type"`
|
||||||
|
|
||||||
@@ -47,6 +54,14 @@ type API struct {
|
|||||||
UpdatedAt time.Time `gorm:"comment:更新时间" json:"updated_at"`
|
UpdatedAt time.Time `gorm:"comment:更新时间" json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BeforeCreate 在创建记录前自动生成UUID
|
||||||
|
func (api *API) BeforeCreate(tx *gorm.DB) error {
|
||||||
|
if api.UUID == "" {
|
||||||
|
api.UUID = strings.ToUpper(uuid.New().String())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// TableName 指定表名
|
// TableName 指定表名
|
||||||
func (API) TableName() string {
|
func (API) TableName() string {
|
||||||
return "apis"
|
return "apis"
|
||||||
|
|||||||
61
models/variable.go
Normal file
61
models/variable.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Variable 变量表模型
|
||||||
|
// 用于管理应用程序的变量数据
|
||||||
|
// UUID 为变量的唯一标识符,自动生成并转换为大写
|
||||||
|
// Alias 为变量别名,便于识别和管理
|
||||||
|
// Data 为变量数据内容
|
||||||
|
// Remark 为备注信息,用于描述变量用途
|
||||||
|
// CreatedAt/UpdatedAt 由 GORM 自动维护
|
||||||
|
|
||||||
|
type Variable struct {
|
||||||
|
// ID:主键,自增
|
||||||
|
ID uint `gorm:"primaryKey;comment:变量ID,自增主键" json:"id"`
|
||||||
|
|
||||||
|
// UUID:变量的唯一标识符,36位字符串
|
||||||
|
UUID string `gorm:"uniqueIndex;size:36;not null;comment:变量的唯一标识符" json:"uuid"`
|
||||||
|
|
||||||
|
// Number:变量编号,时间戳+6位随机数字格式
|
||||||
|
Number string `gorm:"uniqueIndex;size:20;not null;comment:变量编号,时间戳+6位随机数字格式" json:"number"`
|
||||||
|
|
||||||
|
// AppUUID:关联的应用UUID
|
||||||
|
AppUUID string `gorm:"size:36;not null;index;comment:关联的应用UUID" json:"app_uuid"`
|
||||||
|
|
||||||
|
// Alias:变量别名,便于识别和管理
|
||||||
|
Alias string `gorm:"size:100;not null;comment:变量别名" json:"alias"`
|
||||||
|
|
||||||
|
// Data:变量数据内容
|
||||||
|
Data string `gorm:"type:text;comment:变量数据" json:"data"`
|
||||||
|
|
||||||
|
// Remark:备注信息,用于描述变量用途
|
||||||
|
Remark string `gorm:"type:text;comment:备注信息" json:"remark"`
|
||||||
|
|
||||||
|
// 时间字段
|
||||||
|
CreatedAt time.Time `gorm:"comment:创建时间" json:"created_at"`
|
||||||
|
UpdatedAt time.Time `gorm:"comment:更新时间" json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeforeCreate 在创建记录前自动生成UUID和Number
|
||||||
|
func (variable *Variable) BeforeCreate(tx *gorm.DB) error {
|
||||||
|
// 生成UUID
|
||||||
|
if variable.UUID == "" {
|
||||||
|
variable.UUID = strings.ToUpper(uuid.New().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成Number:使用时间戳格式
|
||||||
|
variable.Number = time.Now().Format("20060102150405")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TableName 指定表名
|
||||||
|
func (Variable) TableName() string {
|
||||||
|
return "variables"
|
||||||
|
}
|
||||||
@@ -44,12 +44,17 @@ func RegisterAdminRoutes(mux *http.ServeMux) {
|
|||||||
mux.HandleFunc("/admin/settings", adminctl.AdminAuthRequired(adminctl.SettingsFragmentHandler))
|
mux.HandleFunc("/admin/settings", adminctl.AdminAuthRequired(adminctl.SettingsFragmentHandler))
|
||||||
mux.HandleFunc("/admin/apps", adminctl.AdminAuthRequired(adminctl.AppsFragmentHandler))
|
mux.HandleFunc("/admin/apps", adminctl.AdminAuthRequired(adminctl.AppsFragmentHandler))
|
||||||
mux.HandleFunc("/admin/apis", adminctl.AdminAuthRequired(adminctl.APIFragmentHandler))
|
mux.HandleFunc("/admin/apis", adminctl.AdminAuthRequired(adminctl.APIFragmentHandler))
|
||||||
|
mux.HandleFunc("/admin/variables", adminctl.AdminAuthRequired(adminctl.VariableFragmentHandler))
|
||||||
|
|
||||||
|
// 系统信息API(用于仪表盘定时刷新)
|
||||||
|
mux.HandleFunc("/admin/api/system/info", adminctl.AdminAuthRequired(adminctl.SystemInfoHandler))
|
||||||
|
|
||||||
// 个人资料API
|
// 个人资料API
|
||||||
mux.HandleFunc("/admin/api/user/profile", adminctl.AdminAuthRequired(adminctl.UserProfileQueryHandler))
|
mux.HandleFunc("/admin/api/user/profile", adminctl.AdminAuthRequired(adminctl.UserProfileQueryHandler))
|
||||||
mux.HandleFunc("/admin/api/user/profile/update", adminctl.AdminAuthRequired(adminctl.UserProfileUpdateHandler))
|
mux.HandleFunc("/admin/api/user/profile/update", adminctl.AdminAuthRequired(adminctl.UserProfileUpdateHandler))
|
||||||
mux.HandleFunc("/admin/api/user/password", adminctl.AdminAuthRequired(adminctl.UserPasswordUpdateHandler))
|
mux.HandleFunc("/admin/api/user/password", adminctl.AdminAuthRequired(adminctl.UserPasswordUpdateHandler))
|
||||||
// 设置API(需要管理员认证)
|
|
||||||
|
// 系统设置API
|
||||||
mux.HandleFunc("/admin/api/settings", adminctl.AdminAuthRequired(adminctl.SettingsQueryHandler))
|
mux.HandleFunc("/admin/api/settings", adminctl.AdminAuthRequired(adminctl.SettingsQueryHandler))
|
||||||
mux.HandleFunc("/admin/api/settings/update", adminctl.AdminAuthRequired(adminctl.SettingsUpdateHandler))
|
mux.HandleFunc("/admin/api/settings/update", adminctl.AdminAuthRequired(adminctl.SettingsUpdateHandler))
|
||||||
|
|
||||||
@@ -79,6 +84,11 @@ func RegisterAdminRoutes(mux *http.ServeMux) {
|
|||||||
mux.HandleFunc("/admin/api/apis/types", adminctl.AdminAuthRequired(adminctl.APIGetTypesHandler))
|
mux.HandleFunc("/admin/api/apis/types", adminctl.AdminAuthRequired(adminctl.APIGetTypesHandler))
|
||||||
mux.HandleFunc("/admin/api/apis/generate_keys", adminctl.AdminAuthRequired(adminctl.APIGenerateKeysHandler))
|
mux.HandleFunc("/admin/api/apis/generate_keys", adminctl.AdminAuthRequired(adminctl.APIGenerateKeysHandler))
|
||||||
|
|
||||||
// 系统信息API(用于仪表盘定时刷新)
|
// 变量管理API
|
||||||
mux.HandleFunc("/admin/api/system/info", adminctl.AdminAuthRequired(adminctl.SystemInfoHandler))
|
mux.HandleFunc("/admin/variable/list", adminctl.AdminAuthRequired(adminctl.VariableListHandler))
|
||||||
|
mux.HandleFunc("/admin/variable/apps", adminctl.AdminAuthRequired(adminctl.VariableGetAppsHandler))
|
||||||
|
mux.HandleFunc("/admin/variable/create", adminctl.AdminAuthRequired(adminctl.VariableCreateHandler))
|
||||||
|
mux.HandleFunc("/admin/variable/update", adminctl.AdminAuthRequired(adminctl.VariableUpdateHandler))
|
||||||
|
mux.HandleFunc("/admin/variable/delete", adminctl.AdminAuthRequired(adminctl.VariableDeleteHandler))
|
||||||
|
mux.HandleFunc("/admin/variable/batch_delete", adminctl.AdminAuthRequired(adminctl.VariablesBatchDeleteHandler))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,12 +54,13 @@ func (l *Logger) LogRequestWithHeaders(method, path, clientIP string, statusCode
|
|||||||
// 避免Logrus的任何格式化和转义,保持Apache日志格式的原始性
|
// 避免Logrus的任何格式化和转义,保持Apache日志格式的原始性
|
||||||
// logLine: 格式化后的日志行
|
// logLine: 格式化后的日志行
|
||||||
func (l *Logger) writeHTTPLog(logLine string) {
|
func (l *Logger) writeHTTPLog(logLine string) {
|
||||||
// 输出到标准输出
|
// 直接使用logrus的输出目标,避免重复输出
|
||||||
fmt.Fprintln(os.Stdout, logLine)
|
// 如果logrus配置了MultiWriter,会自动输出到所有目标(控制台+文件)
|
||||||
|
// 如果logrus只配置了标准输出,也会正确输出到控制台
|
||||||
// 同时输出到logrus配置的输出目标(包括文件)
|
if l.Logger.Out != nil {
|
||||||
// 使用logrus的输出目标,但不经过格式化器
|
|
||||||
if l.Logger.Out != nil && l.Logger.Out != os.Stdout {
|
|
||||||
fmt.Fprintln(l.Logger.Out, logLine)
|
fmt.Fprintln(l.Logger.Out, logLine)
|
||||||
|
} else {
|
||||||
|
// 如果没有配置输出目标,默认输出到标准输出
|
||||||
|
fmt.Fprintln(os.Stdout, logLine)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-inline">
|
<div class="layui-inline">
|
||||||
<label class="layui-form-label">接口类型</label>
|
<label class="layui-form-label">类型</label>
|
||||||
<div class="layui-input-inline">
|
<div class="layui-input-inline">
|
||||||
<select name="api_type" lay-filter="apiTypeSelect">
|
<select name="api_type" lay-filter="apiTypeSelect">
|
||||||
<option value="">请选择接口类型</option>
|
<option value="">请选择接口类型</option>
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
<!-- 隐藏的表单弹层内容:编辑接口 -->
|
<!-- 隐藏的表单弹层内容:编辑接口 -->
|
||||||
<div id="apiFormModal" style="display:none;padding:16px">
|
<div id="apiFormModal" style="display:none;padding:16px">
|
||||||
<form class="layui-form layui-form-pane" id="apiForm">
|
<form class="layui-form layui-form-pane" id="apiForm">
|
||||||
<input type="hidden" name="id" />
|
<input type="hidden" name="uuid" />
|
||||||
<!-- 关联应用与接口类型为固定项,移除编辑能力 -->
|
<!-- 关联应用与接口类型为固定项,移除编辑能力 -->
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<label class="layui-form-label" style="cursor: pointer;" data-tips="submit-algorithm">提交算法</label>
|
<label class="layui-form-label" style="cursor: pointer;" data-tips="submit-algorithm">提交算法</label>
|
||||||
@@ -209,11 +209,13 @@ layui.use(['table', 'form', 'layer', 'dropdown'], function() {
|
|||||||
limit: 20,
|
limit: 20,
|
||||||
limits: [10, 20, 50, 100],
|
limits: [10, 20, 50, 100],
|
||||||
loading: true,
|
loading: true,
|
||||||
|
done: function(res, curr, count) {
|
||||||
|
// 表格渲染完成后的回调
|
||||||
|
},
|
||||||
cols: [[
|
cols: [[
|
||||||
{ field: 'id', title: 'ID', width: 80, sort: true },
|
{ field: 'id', title: 'ID', width: 80, sort: true },
|
||||||
{ field: 'app_name', title: '应用名称', mixWidth: 180 },
|
{ field: 'app_name', title: '应用名称', minWidth: 150 },
|
||||||
{ field: 'api_type_name', title: '接口类型', mixWidth: 120 },
|
{ field: 'api_type_name', title: '接口类型', minWidth: 120 },
|
||||||
|
|
||||||
{
|
{
|
||||||
field: 'status_name',
|
field: 'status_name',
|
||||||
title: '状态',
|
title: '状态',
|
||||||
@@ -227,27 +229,39 @@ layui.use(['table', 'form', 'layer', 'dropdown'], function() {
|
|||||||
field: 'submit_algorithm',
|
field: 'submit_algorithm',
|
||||||
title: '提交算法',
|
title: '提交算法',
|
||||||
width: 120,
|
width: 120,
|
||||||
templet: (d) => d.algorithm_names ? d.algorithm_names.submit : '-'
|
templet: (d) => {
|
||||||
|
const algorithm = d.algorithm_names ? d.algorithm_names.submit : '-';
|
||||||
|
if (algorithm && algorithm.length > 10) {
|
||||||
|
return '<span title="' + algorithm + '">' + algorithm.substring(0, 10) + '...</span>';
|
||||||
|
}
|
||||||
|
return algorithm;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'return_algorithm',
|
field: 'return_algorithm',
|
||||||
title: '返回算法',
|
title: '返回算法',
|
||||||
width: 120,
|
width: 120,
|
||||||
templet: (d) => d.algorithm_names ? d.algorithm_names.return : '-'
|
templet: (d) => {
|
||||||
|
const algorithm = d.algorithm_names ? d.algorithm_names.return : '-';
|
||||||
|
if (algorithm && algorithm.length > 10) {
|
||||||
|
return '<span title="' + algorithm + '">' + algorithm.substring(0, 10) + '...</span>';
|
||||||
|
}
|
||||||
|
return algorithm;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'created_at',
|
field: 'created_at',
|
||||||
title: '创建时间',
|
title: '创建时间',
|
||||||
width: 180,
|
width: 160,
|
||||||
templet: (d) => formatDateTime(d.created_at)
|
templet: (d) => formatDateTime(d.created_at)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'updated_at',
|
field: 'updated_at',
|
||||||
title: '修改时间',
|
title: '修改时间',
|
||||||
width: 180,
|
width: 160,
|
||||||
templet: (d) => formatDateTime(d.updated_at)
|
templet: (d) => formatDateTime(d.updated_at)
|
||||||
},
|
},
|
||||||
{ fixed: 'right', title: '操作', toolbar: '#tpl-apis-ops', width: 70 }
|
{ fixed: 'right', title: '操作', toolbar: '#tpl-apis-ops', width: 100, align: 'center' }
|
||||||
]]
|
]]
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -533,7 +547,7 @@ layui.use(['table', 'form', 'layer', 'dropdown'], function() {
|
|||||||
if (obj.event === 'edit') {
|
if (obj.event === 'edit') {
|
||||||
// 编辑接口
|
// 编辑接口
|
||||||
$('#apiForm')[0].reset();
|
$('#apiForm')[0].reset();
|
||||||
$('input[name="id"]').val(data.id);
|
$('input[name="uuid"]').val(data.uuid);
|
||||||
$('select[name="submit_algorithm"]').val(data.submit_algorithm);
|
$('select[name="submit_algorithm"]').val(data.submit_algorithm);
|
||||||
$('select[name="return_algorithm"]').val(data.return_algorithm);
|
$('select[name="return_algorithm"]').val(data.return_algorithm);
|
||||||
$('input[name="status"]').prop('checked', data.status === 1);
|
$('input[name="status"]').prop('checked', data.status === 1);
|
||||||
@@ -574,7 +588,6 @@ layui.use(['table', 'form', 'layer', 'dropdown'], function() {
|
|||||||
// 转换数值类型
|
// 转换数值类型
|
||||||
formData.submit_algorithm = parseInt(formData.submit_algorithm);
|
formData.submit_algorithm = parseInt(formData.submit_algorithm);
|
||||||
formData.return_algorithm = parseInt(formData.return_algorithm);
|
formData.return_algorithm = parseInt(formData.return_algorithm);
|
||||||
formData.id = parseInt(formData.id);
|
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/admin/api/apis/update',
|
url: '/admin/api/apis/update',
|
||||||
|
|||||||
@@ -56,6 +56,7 @@
|
|||||||
<dl class="layui-nav-child">
|
<dl class="layui-nav-child">
|
||||||
<dd><a data-path="apps" href="javascript:;">应用列表</a></dd>
|
<dd><a data-path="apps" href="javascript:;">应用列表</a></dd>
|
||||||
<dd><a data-path="apis" href="javascript:;">接口列表</a></dd>
|
<dd><a data-path="apis" href="javascript:;">接口列表</a></dd>
|
||||||
|
<dd><a data-path="variables" href="javascript:;">变量列表</a></dd>
|
||||||
</dl>
|
</dl>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
464
web/template/admin/variables.html
Normal file
464
web/template/admin/variables.html
Normal file
@@ -0,0 +1,464 @@
|
|||||||
|
{{ define "variables" }}
|
||||||
|
<section>
|
||||||
|
<h2>变量管理</h2>
|
||||||
|
<div class="layui-btn-container" style="margin:12px 0">
|
||||||
|
<button class="layui-btn" id="btnAddVariable"><i class="layui-icon layui-icon-add-1"></i> 新增变量</button>
|
||||||
|
<button class="layui-btn layui-btn-danger" id="btnBatchDeleteVariables"><i class="layui-icon layui-icon-delete"></i> 批量删除</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layui-card" style="margin-top:12px">
|
||||||
|
<div class="layui-card-header">筛选</div>
|
||||||
|
<div class="layui-card-body">
|
||||||
|
<form class="layui-form layui-form-pane" id="variableFilterForm" lay-filter="variableFilterForm">
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<div class="layui-inline">
|
||||||
|
<label class="layui-form-label">应用</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<select name="app_uuid" lay-filter="appSelect">
|
||||||
|
<option value="">请选择应用</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-inline">
|
||||||
|
<label class="layui-form-label">搜索</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="text" name="search" placeholder="变量别名/数据" autocomplete="off" class="layui-input" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-inline">
|
||||||
|
<button type="button" class="layui-btn" id="btnSearchVariables">查询</button>
|
||||||
|
<button type="button" class="layui-btn layui-btn-primary" id="btnResetVariables">重置</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layui-card" style="margin-top:12px">
|
||||||
|
<div class="layui-card-header">变量列表</div>
|
||||||
|
<div class="layui-card-body">
|
||||||
|
<table id="variablesTable" lay-filter="variablesTableFilter"></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表格操作模板 -->
|
||||||
|
<script type="text/html" id="tpl-variables-ops">
|
||||||
|
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
|
||||||
|
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- 隐藏的表单弹层内容:新增/编辑变量 -->
|
||||||
|
<div id="variableFormLayer" style="display:none;padding:20px">
|
||||||
|
<form class="layui-form layui-form-pane" lay-filter="variableForm" id="variableForm">
|
||||||
|
<input type="hidden" name="uuid">
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">应用选择</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<select name="app_uuid" lay-verify="required" lay-filter="formAppSelect">
|
||||||
|
<option value="">请选择应用</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">变量别名</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input type="text" name="alias" lay-verify="required|alias" placeholder="请输入变量别名(英文开头,只能包含数字和英文字母)" autocomplete="off" class="layui-input" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">变量数据</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<textarea name="data" placeholder="请输入变量数据" lay-verify="required" class="layui-textarea"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">备注</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<textarea name="remark" placeholder="请输入备注信息" class="layui-textarea"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 等待layui加载完成
|
||||||
|
function waitForLayui(callback) {
|
||||||
|
if (typeof layui !== 'undefined') {
|
||||||
|
callback();
|
||||||
|
} else {
|
||||||
|
setTimeout(() => waitForLayui(callback), 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForLayui(function() {
|
||||||
|
layui.use(['table', 'form', 'layer', 'element'], function() {
|
||||||
|
const table = layui.table;
|
||||||
|
const form = layui.form;
|
||||||
|
const layer = layui.layer;
|
||||||
|
const $ = layui.$;
|
||||||
|
|
||||||
|
// 自定义验证规则
|
||||||
|
form.verify({
|
||||||
|
alias: function(value) {
|
||||||
|
if (!value) return '别名不能为空';
|
||||||
|
// 检查是否以英文字母开头,且只包含数字和英文字母
|
||||||
|
if (!/^[a-zA-Z][a-zA-Z0-9]*$/.test(value)) {
|
||||||
|
return '别名必须以英文字母开头,只能包含数字和英文字母';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 格式化时间函数
|
||||||
|
function formatDateTime(dateStr) {
|
||||||
|
if (!dateStr) return '-';
|
||||||
|
return new Date(dateStr).toLocaleString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载应用列表到下拉框
|
||||||
|
function loadApps() {
|
||||||
|
$.ajax({
|
||||||
|
url: '/admin/variable/apps',
|
||||||
|
type: 'GET',
|
||||||
|
success: function(res) {
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
let options = '<option value="">请选择应用</option>';
|
||||||
|
res.data.forEach(function(app) {
|
||||||
|
options += '<option value="' + app.uuid + '">' + app.name + '</option>';
|
||||||
|
});
|
||||||
|
$('select[name="app_uuid"]').html(options);
|
||||||
|
form.render('select');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
layer.msg('加载应用列表失败', {icon: 2});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化加载应用列表
|
||||||
|
loadApps();
|
||||||
|
|
||||||
|
// 渲染表格
|
||||||
|
const variablesTable = table.render({
|
||||||
|
elem: '#variablesTable',
|
||||||
|
id: 'variablesTable',
|
||||||
|
url: '/admin/variable/list',
|
||||||
|
parseData: function(res) {
|
||||||
|
return {
|
||||||
|
code: res.code,
|
||||||
|
msg: res.msg || '',
|
||||||
|
count: res.count || 0,
|
||||||
|
data: res.data || []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
request: {
|
||||||
|
pageName: 'page',
|
||||||
|
limitName: 'page_size'
|
||||||
|
},
|
||||||
|
method: 'GET',
|
||||||
|
page: true,
|
||||||
|
limit: 20,
|
||||||
|
limits: [10, 20, 50, 100],
|
||||||
|
loading: true,
|
||||||
|
done: function(res, curr, count) {
|
||||||
|
// 表格渲染完成后的回调
|
||||||
|
},
|
||||||
|
cols: [[
|
||||||
|
{type: 'checkbox', width: 50},
|
||||||
|
{field: 'id', title: 'ID', width: 80, sort: true},
|
||||||
|
{field: 'app_name', title: '应用名称', minWidth: 120},
|
||||||
|
{field: 'number', title: '变量编号', width: 180},
|
||||||
|
{field: 'alias', title: '变量别名', minWidth: 150},
|
||||||
|
{
|
||||||
|
field: 'data',
|
||||||
|
title: '变量数据',
|
||||||
|
minWidth: 200,
|
||||||
|
templet: function(d) {
|
||||||
|
// 限制显示长度,避免内容过长影响布局
|
||||||
|
if (d.data && d.data.length > 50) {
|
||||||
|
return '<span title="' + d.data + '">' + d.data.substring(0, 50) + '...</span>';
|
||||||
|
}
|
||||||
|
return d.data || '-';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'remark',
|
||||||
|
title: '备注',
|
||||||
|
minWidth: 150,
|
||||||
|
templet: function(d) {
|
||||||
|
// 限制显示长度,避免内容过长影响布局
|
||||||
|
if (d.remark && d.remark.length > 30) {
|
||||||
|
return '<span title="' + d.remark + '">' + d.remark.substring(0, 30) + '...</span>';
|
||||||
|
}
|
||||||
|
return d.remark || '-';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'created_at',
|
||||||
|
title: '创建时间',
|
||||||
|
width: 180,
|
||||||
|
templet: function(d) {
|
||||||
|
return formatDateTime(d.created_at);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{title: '操作', width: 180, align: 'center', toolbar: '#tpl-variables-ops', fixed: 'right'}
|
||||||
|
]]
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听应用选择变化
|
||||||
|
form.on('select(appSelect)', function(data) {
|
||||||
|
variablesTable.reload({
|
||||||
|
where: {
|
||||||
|
app_uuid: data.value,
|
||||||
|
alias: $('input[name="search"]').val()
|
||||||
|
},
|
||||||
|
page: {
|
||||||
|
curr: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 搜索功能
|
||||||
|
$('#btnSearchVariables').on('click', function() {
|
||||||
|
variablesTable.reload({
|
||||||
|
where: {
|
||||||
|
app_uuid: $('select[name="app_uuid"]').val(),
|
||||||
|
alias: $('input[name="search"]').val()
|
||||||
|
},
|
||||||
|
page: {
|
||||||
|
curr: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 重置搜索
|
||||||
|
$('#btnResetVariables').on('click', function() {
|
||||||
|
$('#variableFilterForm')[0].reset();
|
||||||
|
form.render();
|
||||||
|
variablesTable.reload({
|
||||||
|
where: {},
|
||||||
|
page: {
|
||||||
|
curr: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 新增变量
|
||||||
|
$('#btnAddVariable').on('click', function() {
|
||||||
|
console.log('新增变量按钮被点击');
|
||||||
|
$('#variableForm')[0].reset();
|
||||||
|
$('input[name="id"]').val('');
|
||||||
|
|
||||||
|
// 重新加载应用列表到表单中
|
||||||
|
loadApps();
|
||||||
|
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: '新增变量',
|
||||||
|
content: $('#variableFormLayer'),
|
||||||
|
area: ['500px', '460px'],
|
||||||
|
btn: ['创建', '取消'],
|
||||||
|
yes: function(index, layero) {
|
||||||
|
// 手动收集表单数据
|
||||||
|
var formData = {};
|
||||||
|
$('#variableForm').find('input, select, textarea').each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var name = $this.attr('name');
|
||||||
|
if (name && name !== 'id') {
|
||||||
|
formData[name] = $this.val();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('新增变量 - 收集到的表单数据:', formData);
|
||||||
|
|
||||||
|
// 验证必填字段
|
||||||
|
if (!formData.app_uuid || formData.app_uuid.trim() === '') {
|
||||||
|
layer.msg('应用UUID不能为空', {icon: 2});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!formData.alias || formData.alias.trim() === '') {
|
||||||
|
layer.msg('请输入变量别名', {icon: 2});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!formData.data || formData.data.trim() === '') {
|
||||||
|
layer.msg('请输入变量数据', {icon: 2});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('新增变量 - 发送的JSON数据:', JSON.stringify(formData));
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '/admin/variable/create',
|
||||||
|
type: 'POST',
|
||||||
|
data: JSON.stringify(formData),
|
||||||
|
contentType: 'application/json',
|
||||||
|
success: function(res) {
|
||||||
|
if (res.code === 0) {
|
||||||
|
layer.msg(res.msg, {icon: 1});
|
||||||
|
layer.close(index);
|
||||||
|
variablesTable.reload();
|
||||||
|
} else {
|
||||||
|
layer.msg(res.msg || '操作失败', {icon: 2});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
layer.msg(xhr.responseText || '操作失败', {icon: 2});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
btn2: function(index) {
|
||||||
|
layer.close(index);
|
||||||
|
},
|
||||||
|
success: function() {
|
||||||
|
form.render();
|
||||||
|
},
|
||||||
|
shadeClose: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 批量删除
|
||||||
|
$('#btnBatchDeleteVariables').on('click', function() {
|
||||||
|
const checkStatus = table.checkStatus('variablesTable');
|
||||||
|
const data = checkStatus.data;
|
||||||
|
|
||||||
|
if (data.length === 0) {
|
||||||
|
layer.msg('请选择要删除的变量', {icon: 2});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.confirm('确定删除选中的 ' + data.length + ' 个变量吗?', {icon: 3, title: '提示'}, function(index) {
|
||||||
|
const ids = data.map(item => item.id);
|
||||||
|
$.ajax({
|
||||||
|
url: '/admin/variable/batch_delete',
|
||||||
|
type: 'POST',
|
||||||
|
data: JSON.stringify({ids: ids}),
|
||||||
|
contentType: 'application/json',
|
||||||
|
success: function(res) {
|
||||||
|
if (res.code === 0) {
|
||||||
|
layer.msg(res.msg, {icon: 1});
|
||||||
|
variablesTable.reload();
|
||||||
|
} else {
|
||||||
|
layer.msg(res.msg || '批量删除失败', {icon: 2});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
layer.msg(xhr.responseText || '批量删除失败', {icon: 2});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
layer.close(index);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 表格工具栏事件
|
||||||
|
table.on('tool(variablesTableFilter)', function(obj) {
|
||||||
|
const data = obj.data;
|
||||||
|
|
||||||
|
if (obj.event === 'edit') {
|
||||||
|
// 编辑
|
||||||
|
console.log('编辑按钮被点击', data);
|
||||||
|
$('#variableForm')[0].reset();
|
||||||
|
$('input[name="uuid"]').val(data.uuid);
|
||||||
|
|
||||||
|
// 重新加载应用列表,然后设置选中值
|
||||||
|
loadApps();
|
||||||
|
setTimeout(function() {
|
||||||
|
$('select[name="app_uuid"]').val(data.app_uuid);
|
||||||
|
form.render('select');
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
$('input[name="alias"]').val(data.alias);
|
||||||
|
$('textarea[name="data"]').val(data.data);
|
||||||
|
$('textarea[name="remark"]').val(data.remark);
|
||||||
|
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: '编辑变量',
|
||||||
|
content: $('#variableFormLayer'),
|
||||||
|
area: ['500px', '460px'],
|
||||||
|
btn: ['保存', '取消'],
|
||||||
|
yes: function(index, layero) {
|
||||||
|
// 手动收集表单数据
|
||||||
|
var formData = {};
|
||||||
|
$('#variableForm').find('input, select, textarea').each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var name = $this.attr('name');
|
||||||
|
if (name && name !== 'id') {
|
||||||
|
formData[name] = $this.val();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('编辑变量 - 收集到的表单数据:', formData);
|
||||||
|
|
||||||
|
// 验证必填字段
|
||||||
|
if (!formData.app_uuid || formData.app_uuid.trim() === '') {
|
||||||
|
layer.msg('应用UUID不能为空', {icon: 2});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!formData.alias || formData.alias.trim() === '') {
|
||||||
|
layer.msg('请输入变量别名', {icon: 2});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!formData.data || formData.data.trim() === '') {
|
||||||
|
layer.msg('请输入变量数据', {icon: 2});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('编辑变量 - 发送的JSON数据:', JSON.stringify(formData));
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '/admin/variable/update',
|
||||||
|
type: 'POST',
|
||||||
|
data: JSON.stringify(formData),
|
||||||
|
contentType: 'application/json',
|
||||||
|
success: function(res) {
|
||||||
|
if (res.code === 0) {
|
||||||
|
layer.msg(res.msg, {icon: 1});
|
||||||
|
layer.close(index);
|
||||||
|
variablesTable.reload();
|
||||||
|
} else {
|
||||||
|
layer.msg(res.msg || '操作失败', {icon: 2});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
layer.msg(xhr.responseText || '操作失败', {icon: 2});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
btn2: function(index) {
|
||||||
|
layer.close(index);
|
||||||
|
},
|
||||||
|
success: function() {
|
||||||
|
form.render();
|
||||||
|
},
|
||||||
|
shadeClose: false
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if (obj.event === 'del') {
|
||||||
|
// 删除
|
||||||
|
layer.confirm('确定删除该变量吗?', {icon: 3, title: '提示'}, function(index) {
|
||||||
|
$.ajax({
|
||||||
|
url: '/admin/variable/delete',
|
||||||
|
type: 'POST',
|
||||||
|
data: JSON.stringify({id: data.id}),
|
||||||
|
contentType: 'application/json',
|
||||||
|
success: function(res) {
|
||||||
|
if (res.code === 0) {
|
||||||
|
layer.msg(res.msg, {icon: 1});
|
||||||
|
variablesTable.reload();
|
||||||
|
} else {
|
||||||
|
layer.msg(res.msg || '删除失败', {icon: 2});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
layer.msg(xhr.responseText || '删除失败', {icon: 2});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
layer.close(index);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
Reference in New Issue
Block a user