optimize and add cdkey
This commit is contained in:
		
							parent
							
								
									bc368e96cf
								
							
						
					
					
						commit
						9675612496
					
				
							
								
								
									
										27
									
								
								admin/apps/game/domain/cdkey.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								admin/apps/game/domain/cdkey.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
package domain
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"admin/apps/game/domain/entity"
 | 
			
		||||
	"admin/apps/game/domain/repo"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type CDKeyService struct {
 | 
			
		||||
	repo repo.ICDKeyRepo
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewCDKeyService(db *gorm.DB) *CDKeyService {
 | 
			
		||||
	return &CDKeyService{repo: repo.NewCDKeyRepo(db)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (svc *CDKeyService) AddCount(id int, delta int) (int, error) {
 | 
			
		||||
	et, err := svc.repo.AddCount(id, delta)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return et.GetCount(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (svc *CDKeyService) Get(id int) (*entity.CDKey, bool, error) {
 | 
			
		||||
	return svc.repo.GetByID(id)
 | 
			
		||||
}
 | 
			
		||||
@ -27,7 +27,7 @@ func initCommonResourcesRepo(db *gorm.DB) {
 | 
			
		||||
	r(consts.ResourcesName_MailRole, "个人邮件", repo.NewCommonResourceRepo(db, &model.RoleMail{}), ShowMethod_Get|ShowMethod_Post)     // 个人邮件发放就没法撤回?
 | 
			
		||||
	r(consts.ResourcesName_MailGlobal, "全服邮件", repo.NewCommonResourceRepo(db, &model.GlobalMail{}), ShowMethod_Get|ShowMethod_Post) // 直接删除,别修改了,玩家收到的更乱
 | 
			
		||||
	r(consts.ResourcesName_Notice, "公告", repo.NewCommonResourceRepo(db, &model.Notice{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete)
 | 
			
		||||
	r(consts.ResourcesName_RewardCode, "奖励码", repo.NewCommonResourceRepo(db, &model.CDKey{}), ShowMethod_Get)
 | 
			
		||||
	r(consts.ResourcesName_CDKey, "礼包码", repo.NewCommonResourceRepo(db, &model.CDKey{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete)
 | 
			
		||||
	r(consts.ResourcesName_DevicePush, "设备推送", repo.NewCommonResourceRepo(db, &model.DevicePush{}), ShowMethod_Get)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@ package entity
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"admin/apps/game/model"
 | 
			
		||||
	"admin/internal/consts"
 | 
			
		||||
	"admin/lib/cdkey"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@ -17,6 +18,25 @@ func NewCDKey(po *model.CDKey) *CDKey {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *CDKey) GetName() string {
 | 
			
		||||
	return c.Po.Name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *CDKey) IsGlobalType() bool {
 | 
			
		||||
	return c.Po.CodeType == consts.CDKeyType_Global
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *CDKey) GenerateKeys() []string {
 | 
			
		||||
	if c.IsGlobalType() {
 | 
			
		||||
		return []string{c.Po.Code}
 | 
			
		||||
	}
 | 
			
		||||
	return cdkey.GenerateAll(c.Po.ID, MaxKeyNum)[:c.Po.CodeNum]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *CDKey) AddCount(delta int) {
 | 
			
		||||
	c.Po.CodeNum += delta
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *CDKey) GetCount() int {
 | 
			
		||||
	return c.Po.CodeNum
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ import (
 | 
			
		||||
	"admin/apps/game/model"
 | 
			
		||||
	"admin/apps/game/model/dto"
 | 
			
		||||
	"admin/lib/xlog"
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"reflect"
 | 
			
		||||
@ -31,6 +32,13 @@ func poToCommonDtoNo(po any) dto.CommonDtoValues {
 | 
			
		||||
 | 
			
		||||
		if ft.Type.Name() == "Time" && ft.Type.PkgPath() == "time" {
 | 
			
		||||
			obj[ft.Name] = fo.Interface().(time.Time).Format("2006/01/02 15:04:05")
 | 
			
		||||
		} else if ft.Type.Name() == "NullTime" {
 | 
			
		||||
			t := fo.Interface().(sql.NullTime)
 | 
			
		||||
			if t.Valid {
 | 
			
		||||
				obj[ft.Name] = t.Time.Format("2006/01/02 15:04:05")
 | 
			
		||||
			} else {
 | 
			
		||||
				obj[ft.Name] = ""
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -62,6 +70,9 @@ func getFieldTypeDtoDescInfo(project *Project, poValue reflect.Value, fieldType
 | 
			
		||||
	if tagType := fieldType.Tag.Get("type"); tagType != "" {
 | 
			
		||||
		f1.Type = tagType
 | 
			
		||||
	}
 | 
			
		||||
	if f1.Type == "NullTime" {
 | 
			
		||||
		f1.Type = "Time"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cf := fieldType.Tag.Get("choices")
 | 
			
		||||
	if cf != "" {
 | 
			
		||||
@ -128,6 +139,12 @@ func parseStr2FieldValue(field reflect.StructField, rawValue any) (realSetValue
 | 
			
		||||
			xlog.Debugf("time content:%v", setValue)
 | 
			
		||||
			t, _ := time.ParseInLocation("2006/01/02 15:04:05", setValue, time.Local)
 | 
			
		||||
			return reflect.ValueOf(t)
 | 
			
		||||
		} else if typeName == "NullTime" {
 | 
			
		||||
			t, err := time.ParseInLocation("2006/01/02 15:04:05", setValue, time.Local)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return reflect.ValueOf(sql.NullTime{Time: t})
 | 
			
		||||
			}
 | 
			
		||||
			return reflect.ValueOf(sql.NullTime{Time: t, Valid: true})
 | 
			
		||||
		}
 | 
			
		||||
		if typeName == "DeletedAt" {
 | 
			
		||||
			return reflect.ValueOf(gorm.DeletedAt{})
 | 
			
		||||
@ -163,13 +180,15 @@ func parseStr2FieldValue(field reflect.StructField, rawValue any) (realSetValue
 | 
			
		||||
				for _, itemI := range rawValue.([]interface{}) {
 | 
			
		||||
					item := &model.MailAttachItem{}
 | 
			
		||||
					for k, vI := range itemI.(map[string]any) {
 | 
			
		||||
						v := vI.(float64)
 | 
			
		||||
						v, _ := vI.(float64)
 | 
			
		||||
						if k == "id" {
 | 
			
		||||
							item.ID = int32(v)
 | 
			
		||||
						} else if k == "num" {
 | 
			
		||||
							item.Num = int64(v)
 | 
			
		||||
						} else if k == "item_type" {
 | 
			
		||||
							item.ItemType = int(v)
 | 
			
		||||
						} else if k == "desc" {
 | 
			
		||||
							item.Desc = vI.(string)
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					items = append(items, item)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										49
									
								
								admin/apps/game/domain/repo/cdkey.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								admin/apps/game/domain/repo/cdkey.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
			
		||||
package repo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"admin/apps/game/domain/entity"
 | 
			
		||||
	"admin/apps/game/model"
 | 
			
		||||
	"admin/internal/errcode"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ICDKeyRepo interface {
 | 
			
		||||
	GetByID(id int) (*entity.CDKey, bool, error)
 | 
			
		||||
	AddCount(id int, delta int) (*entity.CDKey, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewCDKeyRepo(db *gorm.DB) ICDKeyRepo {
 | 
			
		||||
	return &cdKeyRepoImpl{db: db}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type cdKeyRepoImpl struct {
 | 
			
		||||
	db *gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (impl *cdKeyRepoImpl) AddCount(id int, delta int) (*entity.CDKey, error) {
 | 
			
		||||
	po := new(model.CDKey)
 | 
			
		||||
	err := impl.db.Where("id = ?", id).First(po).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errcode.New(errcode.ParamsInvalid, "not found cdkey conf:%v", id)
 | 
			
		||||
	}
 | 
			
		||||
	et := entity.NewCDKey(po)
 | 
			
		||||
	et.AddCount(delta)
 | 
			
		||||
	err = impl.db.Where("id = ?", id).Updates(po).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errcode.New(errcode.DBError, "update data:%+v error:%v", po, id)
 | 
			
		||||
	}
 | 
			
		||||
	return et, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (impl *cdKeyRepoImpl) GetByID(id int) (*entity.CDKey, bool, error) {
 | 
			
		||||
	po := new(model.CDKey)
 | 
			
		||||
	err := impl.db.Where("id = ?", id).First(po).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if errors.Is(err, gorm.ErrRecordNotFound) {
 | 
			
		||||
			return nil, false, nil
 | 
			
		||||
		}
 | 
			
		||||
		return nil, false, errcode.New(errcode.ParamsInvalid, "not found cdkey conf:%v", id)
 | 
			
		||||
	}
 | 
			
		||||
	return entity.NewCDKey(po), true, nil
 | 
			
		||||
}
 | 
			
		||||
@ -102,7 +102,7 @@ func (repo *commonResourceRepoImpl) Create(projectEt *entity.Project, dtoObj dto
 | 
			
		||||
 | 
			
		||||
func (repo *commonResourceRepoImpl) Edit(projectEt *entity.Project, dtoObj dto.CommonDtoValues) error {
 | 
			
		||||
	et := (&entity.CommonResource{}).FromPo(repo.newEmptyPo()).FromDto(dtoObj)
 | 
			
		||||
	err := repo.db.Where("id=?", et.Po.GetId()).Updates(et.Po).Error
 | 
			
		||||
	err := repo.db.Where("id=?", et.Po.GetId()).Save(et.Po).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errcode.New(errcode.DBError, "edit resource:%v obj:%+v error:%v", repo.poTemplate.TableName(), et, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,9 @@ package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"admin/apps/game/model/dto"
 | 
			
		||||
	"admin/internal/consts"
 | 
			
		||||
	"admin/internal/db"
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@ -13,14 +15,14 @@ func init() {
 | 
			
		||||
type CDKey struct {
 | 
			
		||||
	ID             int               `gorm:"primarykey" readonly:"true"`
 | 
			
		||||
	ProjectId      int               `gorm:"index:idx_project_id"`
 | 
			
		||||
	Desc           string            `name:"礼包说明" required:"true"`
 | 
			
		||||
	ServerIDs      []string          `gorm:"type:json;serializer:json" name:"区服" type:"[]string" choices:"GetChoiceServers" multi_choice:"true"`
 | 
			
		||||
	CodeType       int               `name:"礼包类型" required:"true" choices:"GetCodeTypeChoices"`
 | 
			
		||||
	Name           string            `name:"礼包说明" required:"true" uneditable:"true"`
 | 
			
		||||
	ServerIDs      []string          `gorm:"type:json;serializer:json" name:"区服" desc:"不选就是全服通用" type:"[]string" choices:"GetChoiceServers" multi_choice:"true" uneditable:"true""`
 | 
			
		||||
	CodeType       int               `name:"礼包类型" required:"true" choices:"GetCodeTypeChoices" uneditable:"true"`
 | 
			
		||||
	Code           string            `name:"礼包码" desc:"一码通用才配置"`
 | 
			
		||||
	CodeNum        int               `name:"礼包数量" desc:"一码一用才配置"`
 | 
			
		||||
	ValidStartTime time.Time         `name:"生效起始时间"`
 | 
			
		||||
	ValidEndTime   time.Time         `name:"生效结束时间"`
 | 
			
		||||
	RewardList     []*MailAttachItem `gorm:"type:json;serializer:json" name:"邮件附件" type:"items" desc:"搜索道具并点击添加"`
 | 
			
		||||
	ValidStartTime sql.NullTime      `name:"生效起始时间"`
 | 
			
		||||
	ValidEndTime   sql.NullTime      `name:"生效结束时间"`
 | 
			
		||||
	Attach         []*MailAttachItem `gorm:"type:json;serializer:json" name:"礼包码奖励道具" type:"items" desc:"搜索道具并点击添加"`
 | 
			
		||||
 | 
			
		||||
	CreatedAt time.Time `readonly:"true"`
 | 
			
		||||
}
 | 
			
		||||
@ -33,9 +35,13 @@ func (m *CDKey) GetId() int {
 | 
			
		||||
	return m.ID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *CDKey) GetCodeTypeChoices() []*dto.CommonDtoFieldChoice {
 | 
			
		||||
func (m *CDKey) GetCodeTypeChoices(project *Project) []*dto.CommonDtoFieldChoice {
 | 
			
		||||
	return []*dto.CommonDtoFieldChoice{
 | 
			
		||||
		{Desc: "一码通用", Value: 0},
 | 
			
		||||
		{Desc: "一码一用", Value: 1},
 | 
			
		||||
		{Desc: "一码通用", Value: consts.CDKeyType_Global},
 | 
			
		||||
		{Desc: "一码一用", Value: consts.CDKeyType_Private},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *CDKey) GetChoiceServers(project *Project) []*dto.CommonDtoFieldChoice {
 | 
			
		||||
	return getChoiceServers(project)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -54,3 +54,17 @@ type CommandListRsp struct {
 | 
			
		||||
type GetProjectAllItemsRsp struct {
 | 
			
		||||
	Items []*CommonDtoFieldChoice `json:"items"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CDKeyExportFileReq struct {
 | 
			
		||||
	ID int `json:"id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CDKeyAddCountReq struct {
 | 
			
		||||
	ID       int `json:"id"`
 | 
			
		||||
	AddCount int `json:"add_count"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CDKeyAddCountRsp struct {
 | 
			
		||||
	ID       int `json:"id"`
 | 
			
		||||
	NewCount int `json:"new_count"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -11,9 +11,10 @@ func init() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MailAttachItem struct {
 | 
			
		||||
	ID       int32 `json:"id"`
 | 
			
		||||
	Num      int64 `json:"num"`
 | 
			
		||||
	ItemType int   `json:"item_type"`
 | 
			
		||||
	ID       int32  `json:"id"`
 | 
			
		||||
	Num      int64  `json:"num"`
 | 
			
		||||
	Desc     string `json:"desc"`
 | 
			
		||||
	ItemType int    `json:"item_type"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RoleMail struct {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										36
									
								
								admin/apps/game/server/ctl_cdkey.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								admin/apps/game/server/ctl_cdkey.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
			
		||||
package server
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"admin/apps/game/model/dto"
 | 
			
		||||
	"admin/internal/context"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (ctl *controller) CDKeyExportFile(ctx *context.WebContext, params *dto.CDKeyExportFileReq, rsp *dto.NilRsp) error {
 | 
			
		||||
	et, keys, err := ctl.svc.GetCDKeyAllKeys(params.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	content := bytes.NewBuffer(nil)
 | 
			
		||||
	content.WriteString(fmt.Sprintf("礼包码描述:%s\n", et.GetName()))
 | 
			
		||||
	content.WriteString(fmt.Sprintf("礼包码数量:%v\n\n", et.GetCount()))
 | 
			
		||||
	content.WriteString(fmt.Sprintf("礼包码列表:\n"))
 | 
			
		||||
	for _, key := range keys {
 | 
			
		||||
		content.WriteString(fmt.Sprintf("%s\n", key))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.OkFile(fmt.Sprintf("礼包码(%v-%v个).txt", et.GetName(), et.GetCount()), content.String())
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ctl *controller) CDKeyAddCount(ctx *context.WebContext, params *dto.CDKeyAddCountReq, rsp *dto.CDKeyAddCountRsp) error {
 | 
			
		||||
	newCount, err := ctl.svc.CDKeyAddCount(params.ID, params.AddCount)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	rsp.NewCount = newCount
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@ -5,9 +5,14 @@ import (
 | 
			
		||||
	"admin/internal/context"
 | 
			
		||||
	"admin/internal/errcode"
 | 
			
		||||
	"admin/internal/permission"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (srv *Server) CheckToken(ctx *context.WebContext) {
 | 
			
		||||
	if strings.Contains(ctx.GinCtx().Request.URL.Path, "/login") {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := ctx.ExtractHeader()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.Fail(errcode.New(errcode.HeaderParamsInvalid, "header invalid"))
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@ func (srv *Server) Route(engine *web.Engine) {
 | 
			
		||||
	engine.Use(srv.CheckToken)
 | 
			
		||||
 | 
			
		||||
	apiGroup := engine.Group("/api", "")
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	{
 | 
			
		||||
		// 注册项目增删改查接口
 | 
			
		||||
		projectGroup := apiGroup.Group("/"+consts.ResourcesName_Project, "项目")
 | 
			
		||||
@ -28,5 +28,12 @@ func (srv *Server) Route(engine *web.Engine) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		projectGroup.Get("/:projectId/items", "获取项目所有道具列表", consts.WebPathPermit_Read, srv.ctl.GetProjectAllItems)
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			// 礼包码特殊接口
 | 
			
		||||
			cdkeyGroup := projectGroup.Group("/:projectId/cdkey/special", "")
 | 
			
		||||
			cdkeyGroup.Get("/add_count", "礼包码数量追加", consts.WebPathPermit_Write, srv.ctl.CDKeyAddCount)
 | 
			
		||||
			cdkeyGroup.Get("/export", "导出礼包码文件", consts.WebPathPermit_Write, srv.ctl.CDKeyExportFile)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@ type Service struct {
 | 
			
		||||
	db          *gorm.DB
 | 
			
		||||
	resourceSvc *domain.CommonResourceService
 | 
			
		||||
	projectSvc  *domain.ProjectService
 | 
			
		||||
	cdkeySvc    *domain.CDKeyService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func New(db *gorm.DB) (*Service, error) {
 | 
			
		||||
@ -23,6 +24,7 @@ func New(db *gorm.DB) (*Service, error) {
 | 
			
		||||
		db:          db,
 | 
			
		||||
		resourceSvc: domain.NewCommonResourceService(db),
 | 
			
		||||
		projectSvc:  domain.NewProjectService(db),
 | 
			
		||||
		cdkeySvc:    domain.NewCDKeyService(db),
 | 
			
		||||
	}
 | 
			
		||||
	api.RegisterGameApi(svc)
 | 
			
		||||
	//err := svc.ensureProjectsDBData()
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										21
									
								
								admin/apps/game/service/service_cdkey.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								admin/apps/game/service/service_cdkey.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
package service
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"admin/apps/game/domain/entity"
 | 
			
		||||
	"admin/internal/errcode"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (svc *Service) GetCDKeyAllKeys(id int) (*entity.CDKey, []string, error) {
 | 
			
		||||
	et, find, err := svc.cdkeySvc.Get(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if !find {
 | 
			
		||||
		return nil, nil, errcode.New(errcode.ParamsInvalid, "not found cdkey:%v", id)
 | 
			
		||||
	}
 | 
			
		||||
	return et, et.GenerateKeys(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (svc *Service) CDKeyAddCount(id int, deltaCount int) (int, error) {
 | 
			
		||||
	return svc.cdkeySvc.AddCount(id, deltaCount)
 | 
			
		||||
}
 | 
			
		||||
@ -32,7 +32,7 @@ const (
 | 
			
		||||
	ResourcesName_MailRole   = "mail_role"
 | 
			
		||||
	ResourcesName_MailGlobal = "mail_global"
 | 
			
		||||
	ResourcesName_Notice     = "notice"
 | 
			
		||||
	ResourcesName_RewardCode = "reward_code"
 | 
			
		||||
	ResourcesName_CDKey      = "cdkey"
 | 
			
		||||
	ResourcesName_DevicePush = "device_push"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@ -49,3 +49,8 @@ const (
 | 
			
		||||
	BanType_RoleChat    = "role_chat"
 | 
			
		||||
	BanType_Device      = "device"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	CDKeyType_Global  = 0 // 一码通用
 | 
			
		||||
	CDKeyType_Private = 1 // 一码一用
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,12 @@ import (
 | 
			
		||||
	"admin/lib/web"
 | 
			
		||||
	"admin/lib/xlog"
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"github.com/gin-gonic/gin/render"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type WebHeader struct {
 | 
			
		||||
@ -74,6 +79,32 @@ func (ctx *WebContext) Fail(err error) {
 | 
			
		||||
	ctx.alreadySetRsp = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ctx *WebContext) OkFile(fileName string, content string) {
 | 
			
		||||
	if ctx.alreadySetRsp {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	reader := strings.NewReader(string(content))
 | 
			
		||||
	contentLength := len(content)
 | 
			
		||||
	contentType := ""
 | 
			
		||||
 | 
			
		||||
	fileName = url.QueryEscape(fileName)
 | 
			
		||||
	valueName := fmt.Sprintf(`"attachment; filename*=utf-8''%v"`, fileName)
 | 
			
		||||
	extraHeaders := map[string]string{
 | 
			
		||||
		"Content-Disposition":       valueName,
 | 
			
		||||
		"Content-Transfer-Encoding": "binary",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.GinCtx().Render(http.StatusOK, render.Reader{
 | 
			
		||||
		Headers:       extraHeaders,
 | 
			
		||||
		ContentType:   contentType,
 | 
			
		||||
		ContentLength: int64(contentLength),
 | 
			
		||||
		Reader:        reader,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	ctx.alreadySetRsp = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ctx *WebContext) HandleError(path string, err error) {
 | 
			
		||||
	xlog.Errorf("path:%v handle error:%v ", path, err)
 | 
			
		||||
	ctx.Fail(err)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								ui/src/api/cdkey.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								ui/src/api/cdkey.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
import request from '@/utils/request'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export function cdkeyExport(baseUrl, params) {
 | 
			
		||||
    return request({
 | 
			
		||||
        url: baseUrl + '/special/export',
 | 
			
		||||
        method: 'get',
 | 
			
		||||
        params: params,
 | 
			
		||||
        responseType: 'blob',
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										681
									
								
								ui/src/components/restful/tableCDKey.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										681
									
								
								ui/src/components/restful/tableCDKey.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,681 @@
 | 
			
		||||
<script setup>
 | 
			
		||||
import {ElNotification} from "element-plus";
 | 
			
		||||
import {resourceDelete, resourceList, resourcePost, resourcePut, resourceGetAllItems} from "@/api/resource.js";
 | 
			
		||||
import {ref, toRaw} from "vue";
 | 
			
		||||
import {useRoute} from 'vue-router';
 | 
			
		||||
import LocalCache from "@/stores/localCache.js";
 | 
			
		||||
import empty from '@/components/restful/empty.vue';
 | 
			
		||||
import {getWhereConditionDesc} from "@/utils/string.js";
 | 
			
		||||
import {cdkeyExport} from "@/api/cdkey.js";
 | 
			
		||||
 | 
			
		||||
const cachedResource = LocalCache.getCache("resource");
 | 
			
		||||
 | 
			
		||||
const listRsp = ref({fields_desc: [], rows: []})
 | 
			
		||||
const listDataOK = ref(false)
 | 
			
		||||
const projectId = cachedResource.meta.projectId
 | 
			
		||||
const resource_raw_node = cachedResource;
 | 
			
		||||
const hasListPermit = resource_raw_node.meta.methods.get !== undefined && resource_raw_node.meta.methods.get === true;
 | 
			
		||||
 | 
			
		||||
const resource_url = cachedResource.meta.resource_url;
 | 
			
		||||
const fieldsDescInfo = ref([])
 | 
			
		||||
const whereFieldsDescInfo = ref([])
 | 
			
		||||
const calcElColSpan = ref(0)
 | 
			
		||||
const rows = ref([])
 | 
			
		||||
const rules = ref({})
 | 
			
		||||
 | 
			
		||||
const current_page = ref(0)
 | 
			
		||||
const page_size = ref(0)
 | 
			
		||||
 | 
			
		||||
const item = ref({
 | 
			
		||||
  id: '',
 | 
			
		||||
  number: 1,
 | 
			
		||||
  desc: '',
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// console.log("enter table, resource:", cachedResource)
 | 
			
		||||
 | 
			
		||||
const listData = async () => {
 | 
			
		||||
  try {
 | 
			
		||||
    let listParams = {
 | 
			
		||||
      page_no: 0,
 | 
			
		||||
      page_len: 100,
 | 
			
		||||
      where_conditions: "",
 | 
			
		||||
    }
 | 
			
		||||
    let whereReqConditions = {
 | 
			
		||||
      conditions: []
 | 
			
		||||
    }
 | 
			
		||||
    whereFieldsDescInfo.value.forEach((field) => {
 | 
			
		||||
      if (field.value1) {
 | 
			
		||||
        whereReqConditions.conditions.push({
 | 
			
		||||
          key: field.key,
 | 
			
		||||
          op: field.where,
 | 
			
		||||
          value1: field.value1,
 | 
			
		||||
          value2: field.value2,
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
    listParams.where_conditions = JSON.stringify(whereReqConditions)
 | 
			
		||||
    // console.log("list params:", listParams)
 | 
			
		||||
    const rspData = await resourceList(resource_url, listParams);
 | 
			
		||||
    listRsp.value = rspData;
 | 
			
		||||
    if (listRsp.value.code !== 200) throw new Error("请求失败,错误码:", listRsp.code);
 | 
			
		||||
    fieldsDescInfo.value = listRsp.value.data.fields_desc
 | 
			
		||||
    rows.value = listRsp.value.data.rows
 | 
			
		||||
 | 
			
		||||
    for (let i = 0; i < fieldsDescInfo.value.length; i++) {
 | 
			
		||||
      var field = fieldsDescInfo.value[i]
 | 
			
		||||
      dialogAddForm.value[field.key] = ''
 | 
			
		||||
 | 
			
		||||
      if (field.required == true) {
 | 
			
		||||
        rules.value[field.key] = [{required: true, message: field.name + "不能为空", trigger: "blur"}]
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (field.type == "items") {
 | 
			
		||||
        dialogAddForm.value[field.key] = []
 | 
			
		||||
        for (let j = 0; j < rows.value.length; j++) {
 | 
			
		||||
          rows.value[j].jsonValue = JSON.stringify(rows.value[j][field.key])
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (field.where !== "") {
 | 
			
		||||
        field.value1 = ""
 | 
			
		||||
        field.value2 = ""
 | 
			
		||||
        field.whereDesc = getWhereConditionDesc(field.where)
 | 
			
		||||
        let find = false
 | 
			
		||||
        for (let i = 0; i < whereFieldsDescInfo.value.length; i++) {
 | 
			
		||||
          let whereField = whereFieldsDescInfo.value[i]
 | 
			
		||||
          if (whereField.key === field.key) {
 | 
			
		||||
            whereFieldsDescInfo.value[i].type = field.type
 | 
			
		||||
            whereFieldsDescInfo.value[i].where = field.where
 | 
			
		||||
            whereFieldsDescInfo.value[i].whereDesc = getWhereConditionDesc(field.where)
 | 
			
		||||
            find = true
 | 
			
		||||
            break
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        if (!find) {
 | 
			
		||||
          whereFieldsDescInfo.value.push(field)
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    calcElColSpan.value = 0
 | 
			
		||||
    // 计算el-col占用24格子的span数量
 | 
			
		||||
    let calcElColSpanTmp = 2
 | 
			
		||||
    whereFieldsDescInfo.value.forEach((field) => {
 | 
			
		||||
      if (field.where === "range") {
 | 
			
		||||
        calcElColSpanTmp += 2
 | 
			
		||||
      } else {
 | 
			
		||||
        calcElColSpanTmp += 1
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
    calcElColSpan.value = 24 / calcElColSpanTmp
 | 
			
		||||
 | 
			
		||||
    // console.log("where fields:", whereFieldsDescInfo.value)
 | 
			
		||||
    // console.log('await list  rsp:', listRsp.value, fieldsDescInfo.value, toRaw(rows.value), toRaw(rules.value))
 | 
			
		||||
 | 
			
		||||
    listDataOK.value = true
 | 
			
		||||
  } catch (err) {
 | 
			
		||||
    console.log(err)
 | 
			
		||||
  } finally {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  listData();
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const dialogAddVisible = ref(false)
 | 
			
		||||
const dialogLookVisible = ref(false)
 | 
			
		||||
const dialogEditVisible = ref(false)
 | 
			
		||||
const dialogAddFormRef = ref(null)
 | 
			
		||||
const dialogEditFormRef = ref(null)
 | 
			
		||||
 | 
			
		||||
const dialogAddForm = ref({
 | 
			
		||||
  ServerIDs: [],
 | 
			
		||||
  Attach: [],
 | 
			
		||||
})
 | 
			
		||||
const dialogEditForm = ref({})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const submitAdd = async () => {
 | 
			
		||||
  try {
 | 
			
		||||
    await dialogAddFormRef.value.validate(valid => {
 | 
			
		||||
      if (valid) {
 | 
			
		||||
        console.log("commit add form:", dialogAddForm.value)
 | 
			
		||||
        resourcePost(resource_url, dialogAddForm.value).then((res) => {
 | 
			
		||||
          ElNotification({
 | 
			
		||||
            title: "添加结果通知",
 | 
			
		||||
            message: "添加成功!",
 | 
			
		||||
            type: 'success',
 | 
			
		||||
            duration: 4000,
 | 
			
		||||
            "show-close": true,
 | 
			
		||||
          })
 | 
			
		||||
          rows.value.push(res.data.dto)
 | 
			
		||||
          dialogAddVisible.value = false
 | 
			
		||||
          handleCloseDialog()
 | 
			
		||||
        }, (err) => {
 | 
			
		||||
          console.log("添加报错:", err)
 | 
			
		||||
        })
 | 
			
		||||
        console.log("提交数据:", dialogAddForm.value)
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.log("校验失败:", error)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const submitEdit = async () => {
 | 
			
		||||
  try {
 | 
			
		||||
    await dialogEditFormRef.value.validate(valid => {
 | 
			
		||||
      if (valid) {
 | 
			
		||||
        resourcePut(resource_url, dialogEditForm.value).then((res) => {
 | 
			
		||||
          ElNotification({
 | 
			
		||||
            title: "编辑结果通知",
 | 
			
		||||
            message: "编辑成功!",
 | 
			
		||||
            type: 'success',
 | 
			
		||||
            duration: 4000,
 | 
			
		||||
            "show-close": true,
 | 
			
		||||
          })
 | 
			
		||||
          dialogEditVisible.value = false
 | 
			
		||||
          rows.value[dialogEditForm.value.oldIndex] = res.data.dto
 | 
			
		||||
          handleCloseDialog()
 | 
			
		||||
        }, (err) => {
 | 
			
		||||
          console.log("添加报错:", err)
 | 
			
		||||
        })
 | 
			
		||||
        console.log("提交数据:", dialogEditForm.value)
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.log("校验失败:", error)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const handleExport = (index, row) => {
 | 
			
		||||
  cdkeyExport(resource_url, {id: row.ID}).then((res) => {
 | 
			
		||||
    console.log("导出cdkey返回:", res)
 | 
			
		||||
 | 
			
		||||
    // 从响应头解析文件名
 | 
			
		||||
    const contentDisposition = res.headers['content-disposition'];
 | 
			
		||||
    let filename = 'default_filename.ext'; // 默认文件名
 | 
			
		||||
 | 
			
		||||
    // 正则提取文件名(处理编码情况)
 | 
			
		||||
    const filenameRegex = /filename\*?=(?:UTF-8'')?"?([^";]+)"?/i;
 | 
			
		||||
    const matches = contentDisposition.match(filenameRegex);
 | 
			
		||||
 | 
			
		||||
    if (matches && matches[1]) {
 | 
			
		||||
      filename = decodeURIComponent(matches[1]); // 解码特殊字符
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 创建临时链接触发下载
 | 
			
		||||
    const blob = new Blob([res.data]);
 | 
			
		||||
    const link = document.createElement('a');
 | 
			
		||||
    link.href = window.URL.createObjectURL(blob);
 | 
			
		||||
    link.download = filename;
 | 
			
		||||
    link.click();
 | 
			
		||||
 | 
			
		||||
    // 释放内存
 | 
			
		||||
    window.URL.revokeObjectURL(link.href);
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const handleLook = (index, row) => {
 | 
			
		||||
  dialogEditForm.value.oldData = row
 | 
			
		||||
  dialogEditForm.value.oldIndex = index
 | 
			
		||||
  dialogEditForm.value = row
 | 
			
		||||
  console.log("look data:", row)
 | 
			
		||||
  dialogLookVisible.value = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const handleEdit = (index, row) => {
 | 
			
		||||
  dialogEditForm.value.oldData = row
 | 
			
		||||
  dialogEditForm.value.oldIndex = index
 | 
			
		||||
  dialogEditForm.value = row
 | 
			
		||||
  console.log("edit data:", row)
 | 
			
		||||
  dialogEditVisible.value = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const handleDelete = (index, row) => {
 | 
			
		||||
  ElMessageBox.confirm("确定要删除吗?").then(() => {
 | 
			
		||||
    resourceDelete(resource_url, {id: row.ID}).then((res) => {
 | 
			
		||||
      ElNotification({
 | 
			
		||||
        title: "删除结果通知",
 | 
			
		||||
        message: "删除数据[" + row.ID + "]成功!",
 | 
			
		||||
        type: 'success',
 | 
			
		||||
        duration: 4000,
 | 
			
		||||
        "show-close": true,
 | 
			
		||||
      })
 | 
			
		||||
      rows.value.splice(index, 1)
 | 
			
		||||
    }, (err) => {
 | 
			
		||||
      console.log("delet error:", err)
 | 
			
		||||
    })
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function addItem() {
 | 
			
		||||
  if (item.value.id == null || item.value.id == '' || item.value.id < 0) {
 | 
			
		||||
    ElMessage('请选择道具!')
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if (item.value.num == null || item.value.num == '' || item.value.num <= 0) {
 | 
			
		||||
    ElMessage('请输入有效道具数量!')
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let d = {id: item.value.id, num: Number(item.value.num), desc: item.value.desc, item_type: item.value.item_type};
 | 
			
		||||
 | 
			
		||||
  console.log("add item:", d)
 | 
			
		||||
 | 
			
		||||
  if (typeof dialogAddForm.value.Attach === typeof "") {
 | 
			
		||||
    dialogAddForm.value.Attach = [];
 | 
			
		||||
  }
 | 
			
		||||
  dialogAddForm.value.Attach.push(d);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function deleteItem(row) {
 | 
			
		||||
  // 移除该对象
 | 
			
		||||
  let number = form.value.Attach.findIndex(item => item === row);
 | 
			
		||||
  dialogAddForm.value.Attach.splice(number, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const handleCloseDialog = () => {
 | 
			
		||||
  console.log("关闭添加/编辑弹窗")
 | 
			
		||||
  dialogAddVisible.value = false
 | 
			
		||||
  dialogLookVisible.value = false
 | 
			
		||||
  dialogEditVisible.value = false
 | 
			
		||||
  dialogAddForm.value = {
 | 
			
		||||
    Attach: [],
 | 
			
		||||
  }
 | 
			
		||||
  dialogEditForm.value = {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const loadingRemoteItems = ref(false)
 | 
			
		||||
const itemChoices = ref({})
 | 
			
		||||
const handleItemOnSelect = (itemOption) => {
 | 
			
		||||
  console.log("选中:", itemOption)
 | 
			
		||||
  item.value.id = itemOption.value
 | 
			
		||||
  item.value.desc = itemOption.desc
 | 
			
		||||
}
 | 
			
		||||
const handleQueryItem = (itemQueryStr) => {
 | 
			
		||||
  if (!itemQueryStr) {
 | 
			
		||||
    itemChoices.value = []
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
  loadingRemoteItems.value = true
 | 
			
		||||
  itemQueryStr = itemQueryStr.replace(/[\s\u3000]/g, "")
 | 
			
		||||
  resourceGetAllItems(projectId).then((res) => {
 | 
			
		||||
    // console.log("获取所有道具返回:", res.data)
 | 
			
		||||
    // console.log("查询字符串:[" + itemQueryStr + "]")
 | 
			
		||||
    itemChoices.value = res.data.items.filter((item) => {
 | 
			
		||||
      return item.desc.includes(itemQueryStr)
 | 
			
		||||
    })
 | 
			
		||||
    loadingRemoteItems.value = false
 | 
			
		||||
  }, (err) => {
 | 
			
		||||
    itemChoices.value = []
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const resetConditionSearch = () => {
 | 
			
		||||
  for (let i = 0; i < whereFieldsDescInfo.value.length; i++) {
 | 
			
		||||
    let field = whereFieldsDescInfo.value[i]
 | 
			
		||||
    field.value1 = null
 | 
			
		||||
    field.value2 = null
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <template v-if="!hasListPermit">
 | 
			
		||||
    <component :is="empty"></component>
 | 
			
		||||
  </template>
 | 
			
		||||
  <template v-else>
 | 
			
		||||
    <el-container v-if="listDataOK">
 | 
			
		||||
      <el-header>
 | 
			
		||||
        <el-row :gutter="20" v-if="(whereFieldsDescInfo.length !== 0)">
 | 
			
		||||
          <template v-for="fieldDescInfo in whereFieldsDescInfo">
 | 
			
		||||
            <template v-if="(fieldDescInfo.where === 'range')">
 | 
			
		||||
              <el-col :span="calcElColSpan">
 | 
			
		||||
                <el-date-picker v-model="fieldDescInfo.value1" type="datetime"
 | 
			
		||||
                                :placeholder="(fieldDescInfo.name + '起始')" format="YYYY/MM/DD HH:mm:ss"
 | 
			
		||||
                                value-format="YYYY/MM/DD HH:mm:ss"></el-date-picker>
 | 
			
		||||
              </el-col>
 | 
			
		||||
              <el-col :span="calcElColSpan">
 | 
			
		||||
                <el-date-picker v-model="fieldDescInfo.value2" type="datetime"
 | 
			
		||||
                                :placeholder="(fieldDescInfo.name + '结束')" format="YYYY/MM/DD HH:mm:ss"
 | 
			
		||||
                                value-format="YYYY/MM/DD HH:mm:ss"></el-date-picker>
 | 
			
		||||
              </el-col>
 | 
			
		||||
            </template>
 | 
			
		||||
            <template v-else>
 | 
			
		||||
              <el-col :span="calcElColSpan">
 | 
			
		||||
                <el-select v-model="fieldDescInfo.value1"
 | 
			
		||||
                           :placeholder="(fieldDescInfo.multi_choice === true ? '--' + fieldDescInfo.name + '--' : '--' + fieldDescInfo.name + '--')"
 | 
			
		||||
                           style="width: 150px"
 | 
			
		||||
                           filterable v-if="(fieldDescInfo.choices.length > 0)">
 | 
			
		||||
                  <el-option v-for="choice in fieldDescInfo.choices" :key="choice.value" :label="choice.desc"
 | 
			
		||||
                             :value="choice.value"></el-option>
 | 
			
		||||
                </el-select>
 | 
			
		||||
                <el-input v-model="fieldDescInfo.value1"
 | 
			
		||||
                          :placeholder="(fieldDescInfo.name + fieldDescInfo.whereDesc)"
 | 
			
		||||
                          style="width: 150px" v-else></el-input>
 | 
			
		||||
              </el-col>
 | 
			
		||||
            </template>
 | 
			
		||||
          </template>
 | 
			
		||||
          <el-col :span="calcElColSpan">
 | 
			
		||||
            <el-button @click="listData" type="primary">条件搜索</el-button>
 | 
			
		||||
          </el-col>
 | 
			
		||||
          <el-col :span="calcElColSpan">
 | 
			
		||||
            <el-button @click="resetConditionSearch">清空条件</el-button>
 | 
			
		||||
          </el-col>
 | 
			
		||||
        </el-row>
 | 
			
		||||
 | 
			
		||||
        <el-row style="margin-top: 10px">
 | 
			
		||||
          <el-button @click="dialogAddVisible = true" size="large" type="primary"
 | 
			
		||||
                     v-if="(resource_raw_node.meta.methods.post === true)">
 | 
			
		||||
            添加
 | 
			
		||||
          </el-button>
 | 
			
		||||
        </el-row>
 | 
			
		||||
      </el-header>
 | 
			
		||||
      <el-main>
 | 
			
		||||
        <el-table :data="rows" style="width: 100%" table-layout="auto" stripe>
 | 
			
		||||
          <template v-for="fieldDescInfo in fieldsDescInfo">
 | 
			
		||||
            <el-table-column prop="jsonValue" :label="fieldDescInfo.name"
 | 
			
		||||
                             v-if="(fieldDescInfo.type === 'items')"></el-table-column>
 | 
			
		||||
            <el-table-column :prop="fieldDescInfo.key" :label="fieldDescInfo.name"
 | 
			
		||||
                             v-else></el-table-column>
 | 
			
		||||
          </template>
 | 
			
		||||
          <el-table-column prop="func" label="功 能">
 | 
			
		||||
            <template #default="scope">
 | 
			
		||||
              <el-button size="default" type="success" @click="handleLook(scope.$index, scope.row)"
 | 
			
		||||
                         v-if="(resource_raw_node.meta.methods.put === true)">
 | 
			
		||||
                <span>查看</span>
 | 
			
		||||
              </el-button>
 | 
			
		||||
              <el-button size="default" type="primary" @click="handleExport( scope.$index, scope.row)"
 | 
			
		||||
                         v-if="(resource_raw_node.meta.methods.put === true)">
 | 
			
		||||
                <span>导出</span>
 | 
			
		||||
              </el-button>
 | 
			
		||||
              <el-button size="default" type="info" @click="handleEdit( scope.$index, scope.row)"
 | 
			
		||||
                         v-if="(resource_raw_node.meta.methods.put === true)">
 | 
			
		||||
                <span>修改</span>
 | 
			
		||||
              </el-button>
 | 
			
		||||
              <el-button size="default" type="danger" @click="handleDelete( scope.$index, scope.row)"
 | 
			
		||||
                         v-if="(resource_raw_node.meta.methods.delete === true)">
 | 
			
		||||
                <span>调试用</span>
 | 
			
		||||
              </el-button>
 | 
			
		||||
            </template>
 | 
			
		||||
          </el-table-column>
 | 
			
		||||
        </el-table>
 | 
			
		||||
 | 
			
		||||
        <!-- 表格数据分页 -->
 | 
			
		||||
        <div class="demo-pagination-block">
 | 
			
		||||
          <div class="demonstration"></div>
 | 
			
		||||
          <el-pagination
 | 
			
		||||
              v-model:current-page="current_page"
 | 
			
		||||
              v-model:page-size="page_size"
 | 
			
		||||
              :page-sizes="[20, 50, 100]"
 | 
			
		||||
              layout="total, sizes, prev, pager, next, jumper"
 | 
			
		||||
              :total="400"
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <el-dialog v-model="dialogAddVisible" :mask="true" title="添加" :modal="true" :before-close="handleCloseDialog"
 | 
			
		||||
                   destroy-on-close>
 | 
			
		||||
          <el-form ref="dialogAddFormRef" :model="dialogAddForm" :rules="rules" label-position="right"
 | 
			
		||||
                   label-width="130px">
 | 
			
		||||
            <template v-for="fieldDescInfo in fieldsDescInfo">
 | 
			
		||||
              <!--如何是items类型,就是物品下拉框+道具组合-->
 | 
			
		||||
              <template v-if="(fieldDescInfo.type === 'items')">
 | 
			
		||||
                <el-form :inline="true" :model="item" label-position="right">
 | 
			
		||||
                  <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key" label-width="130px">
 | 
			
		||||
                    <el-tooltip effect="light" :content="fieldDescInfo.help_text" placement="bottom-start">
 | 
			
		||||
                      <el-select v-model="item" placeholder="--搜索道具--" style="width: 150px"
 | 
			
		||||
                                 filterable remote
 | 
			
		||||
                                 :remote-method="handleQueryItem"
 | 
			
		||||
                                 :loading="loadingRemoteItems"
 | 
			
		||||
                                 value-key="value"
 | 
			
		||||
                                 @change="handleItemOnSelect"
 | 
			
		||||
                      >
 | 
			
		||||
                        <el-option v-for="info in itemChoices" :key="info.value" :label="info.desc"
 | 
			
		||||
                                   :value="info"></el-option>
 | 
			
		||||
                      </el-select>
 | 
			
		||||
                    </el-tooltip>
 | 
			
		||||
                  </el-form-item>
 | 
			
		||||
                  <el-form-item label="数量" prop="num">
 | 
			
		||||
                    <el-input type="number" v-model="item.num" placeholder="请输入数量" style="width: 150px"/>
 | 
			
		||||
                  </el-form-item>
 | 
			
		||||
                  <el-form-item>
 | 
			
		||||
                    <el-button type="primary" @click="addItem()">添加</el-button>
 | 
			
		||||
                  </el-form-item>
 | 
			
		||||
                </el-form>
 | 
			
		||||
                <el-form-item label="奖励列表" prop="Attach">
 | 
			
		||||
                  <el-table :data="dialogAddForm.Attach" border>
 | 
			
		||||
                    <el-table-column label="道具id" prop="id"/>
 | 
			
		||||
                    <el-table-column label="数量" prop="num"/>
 | 
			
		||||
                    <el-table-column label="道具名" prop="desc"/>
 | 
			
		||||
                    <el-table-column label="操作">
 | 
			
		||||
                      <template #default="scope">
 | 
			
		||||
                        <el-button type="danger" size="small" @click="deleteItem(scope.row)">删除</el-button>
 | 
			
		||||
                      </template>
 | 
			
		||||
                    </el-table-column>
 | 
			
		||||
                  </el-table>
 | 
			
		||||
                </el-form-item>
 | 
			
		||||
              </template>
 | 
			
		||||
 | 
			
		||||
              <template v-else-if="(fieldDescInfo.readonly !== true)">
 | 
			
		||||
                <!-- 有可选项的字段,走下拉框或者多选框 -->
 | 
			
		||||
                <template v-if="(fieldDescInfo.choices !== undefined && fieldDescInfo.choices.length > 0)">
 | 
			
		||||
                  <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
 | 
			
		||||
                    <el-tooltip effect="light" :content="fieldDescInfo.help_text" placement="bottom-start">
 | 
			
		||||
                      <el-select :placeholder="(fieldDescInfo.multi_choice === true ? '--多选--' : '--单选--')"
 | 
			
		||||
                                 v-model="dialogAddForm[fieldDescInfo.key]" style="width: 150px"
 | 
			
		||||
                                 :multiple="(fieldDescInfo.multi_choice === true)">
 | 
			
		||||
                        <el-option v-for="info in fieldDescInfo.choices" :key="info.desc" :label="info.desc"
 | 
			
		||||
                                   :value="info.value"></el-option>
 | 
			
		||||
                      </el-select>
 | 
			
		||||
                    </el-tooltip>
 | 
			
		||||
                  </el-form-item>
 | 
			
		||||
                </template>
 | 
			
		||||
 | 
			
		||||
                <!-- 时间戳字段,展示时间选择器 -->
 | 
			
		||||
                <template v-else-if="(fieldDescInfo.type === 'Time')">
 | 
			
		||||
                  <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
 | 
			
		||||
                    <el-date-picker v-model="dialogAddForm[fieldDescInfo.key]" type="datetime"
 | 
			
		||||
                                    placeholder="选个时间" format="YYYY/MM/DD HH:mm:ss"
 | 
			
		||||
                                    value-format="YYYY/MM/DD HH:mm:ss"></el-date-picker>
 | 
			
		||||
                  </el-form-item>
 | 
			
		||||
                </template>
 | 
			
		||||
 | 
			
		||||
                <!-- 否则就是普通字段 -->
 | 
			
		||||
                <template v-else>
 | 
			
		||||
                  <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
 | 
			
		||||
                    <el-input v-model="dialogAddForm[fieldDescInfo.key]"
 | 
			
		||||
                              :placeholder="fieldDescInfo.help_text"></el-input>
 | 
			
		||||
                  </el-form-item>
 | 
			
		||||
                </template>
 | 
			
		||||
              </template>
 | 
			
		||||
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <el-form-item>
 | 
			
		||||
              <el-button @click="submitAdd(dialogAddFormRef)" size="large" type="primary">提交</el-button>
 | 
			
		||||
            </el-form-item>
 | 
			
		||||
 | 
			
		||||
          </el-form>
 | 
			
		||||
        </el-dialog>
 | 
			
		||||
 | 
			
		||||
        <el-dialog v-model="dialogLookVisible" :mask="true" title="编辑" :modal="true" :before-close="handleCloseDialog"
 | 
			
		||||
                   destroy-on-close>
 | 
			
		||||
          <el-form ref="dialogEditFormRef" :model="dialogEditForm" :rules="rules" class="operation_form"
 | 
			
		||||
                   label-width="130px">
 | 
			
		||||
            <template v-for="fieldDescInfo in fieldsDescInfo">
 | 
			
		||||
 | 
			
		||||
              <!--如果是items类型,就是物品下拉框+道具组合-->
 | 
			
		||||
              <template v-if="(fieldDescInfo.type === 'items')">
 | 
			
		||||
                <el-form-item label="奖励列表" prop="attachmentsList">
 | 
			
		||||
                  <el-table :data="dialogEditForm.Attach" border>
 | 
			
		||||
                    <el-table-column label="道具id" prop="id"/>
 | 
			
		||||
                    <el-table-column label="数量" prop="num"/>
 | 
			
		||||
                    <el-table-column label="道具名" prop="desc"/>
 | 
			
		||||
                  </el-table>
 | 
			
		||||
                </el-form-item>
 | 
			
		||||
              </template>
 | 
			
		||||
 | 
			
		||||
              <template v-else>
 | 
			
		||||
                <!-- 有可选项的字段,走下拉框或者多选框 -->
 | 
			
		||||
                <template v-if="(fieldDescInfo.choices !== undefined && fieldDescInfo.choices.length > 0)">
 | 
			
		||||
                  <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
 | 
			
		||||
                    <el-tooltip effect="light" :content="fieldDescInfo.help_text" placement="bottom-start">
 | 
			
		||||
                      <el-select :placeholder="(fieldDescInfo.multi_choice === true ? '--多选--' : '--单选--')"
 | 
			
		||||
                                 disabled
 | 
			
		||||
                                 v-model="dialogEditForm[fieldDescInfo.key]" style="width: 150px"
 | 
			
		||||
                                 :multiple="(fieldDescInfo.multi_choice === true)">
 | 
			
		||||
                        <el-option v-for="info in fieldDescInfo.choices" :key="info.desc" :label="info.desc"
 | 
			
		||||
                                   :value="info.value"></el-option>
 | 
			
		||||
                      </el-select>
 | 
			
		||||
                    </el-tooltip>
 | 
			
		||||
                  </el-form-item>
 | 
			
		||||
                </template>
 | 
			
		||||
 | 
			
		||||
                <!-- 时间戳字段,展示时间选择器 -->
 | 
			
		||||
                <template v-else-if="(fieldDescInfo.type === 'Time')">
 | 
			
		||||
                  <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
 | 
			
		||||
                    <el-date-picker v-model="dialogEditForm[fieldDescInfo.key]" type="datetime"
 | 
			
		||||
                                    disabled
 | 
			
		||||
                                    placeholder="选个时间" format="YYYY/MM/DD HH:mm:ss"
 | 
			
		||||
                                    value-format="YYYY/MM/DD HH:mm:ss"></el-date-picker>
 | 
			
		||||
                  </el-form-item>
 | 
			
		||||
                </template>
 | 
			
		||||
 | 
			
		||||
                <!-- 否则就是普通字段 -->
 | 
			
		||||
                <template v-else>
 | 
			
		||||
                  <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
 | 
			
		||||
                    <el-input v-model="dialogEditForm[fieldDescInfo.key]"
 | 
			
		||||
                              disabled
 | 
			
		||||
                              :placeholder="fieldDescInfo.help_text"></el-input>
 | 
			
		||||
                  </el-form-item>
 | 
			
		||||
                </template>
 | 
			
		||||
              </template>
 | 
			
		||||
 | 
			
		||||
              <!--            <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">-->
 | 
			
		||||
              <!--              <el-input v-model="dialogEditForm[fieldDescInfo.key]"></el-input>-->
 | 
			
		||||
              <!--            </el-form-item>-->
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <el-form-item>
 | 
			
		||||
              <el-button @click="submitEdit(dialogEditFormRef)" size="large" type="primary">提交</el-button>
 | 
			
		||||
            </el-form-item>
 | 
			
		||||
          </el-form>
 | 
			
		||||
        </el-dialog>
 | 
			
		||||
 | 
			
		||||
        <el-dialog v-model="dialogEditVisible" :mask="true" title="编辑" :modal="true" :before-close="handleCloseDialog"
 | 
			
		||||
                   destroy-on-close>
 | 
			
		||||
          <el-form ref="dialogEditFormRef" :model="dialogEditForm" :rules="rules" class="operation_form"
 | 
			
		||||
                   label-width="130px">
 | 
			
		||||
            <template v-for="fieldDescInfo in fieldsDescInfo">
 | 
			
		||||
 | 
			
		||||
              <!--如果是items类型,就是物品下拉框+道具组合-->
 | 
			
		||||
              <template v-if="(fieldDescInfo.type === 'items')">
 | 
			
		||||
                <el-form :inline="true" :model="item" label-position="right"
 | 
			
		||||
                         label-width="130px">
 | 
			
		||||
                  <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
 | 
			
		||||
                    <el-tooltip effect="light" :content="fieldDescInfo.help_text" placement="bottom-start">
 | 
			
		||||
                      <el-select placeholder="--搜索道具--" v-model="item.id" style="width: 150px"
 | 
			
		||||
                                 filterable remote :remote-method="handleQueryItem" :loading="loadingRemoteItems">
 | 
			
		||||
                        <el-option v-for="info in itemChoices" :key="info.value" :label="info.desc"
 | 
			
		||||
                                   :value="info.value"></el-option>
 | 
			
		||||
                      </el-select>
 | 
			
		||||
                    </el-tooltip>
 | 
			
		||||
                  </el-form-item>
 | 
			
		||||
                  <el-form-item label="数量" prop="number">
 | 
			
		||||
                    <el-input type="number" v-model="item.num" placeholder="请输入数量" style="width: 150px"/>
 | 
			
		||||
                  </el-form-item>
 | 
			
		||||
                  <el-form-item>
 | 
			
		||||
                    <el-button type="primary" @click="addItem(fieldDescInfo)">添加</el-button>
 | 
			
		||||
                  </el-form-item>
 | 
			
		||||
                </el-form>
 | 
			
		||||
                <el-form-item label="奖励列表" prop="attachmentsList">
 | 
			
		||||
                  <el-table :data="dialogEditForm.Attach" border>
 | 
			
		||||
                    <el-table-column label="道具id" prop="id"/>
 | 
			
		||||
                    <el-table-column label="数量" prop="num"/>
 | 
			
		||||
                    <el-table-column label="道具名" prop="desc"/>
 | 
			
		||||
                    <el-table-column label="操作">
 | 
			
		||||
                      <template #default="scope">
 | 
			
		||||
                        <el-button type="danger" size="small" @click="deleteItem(scope.row)">删除</el-button>
 | 
			
		||||
                      </template>
 | 
			
		||||
                    </el-table-column>
 | 
			
		||||
                  </el-table>
 | 
			
		||||
                </el-form-item>
 | 
			
		||||
              </template>
 | 
			
		||||
 | 
			
		||||
              <template v-else-if="(fieldDescInfo.readonly !== true)">
 | 
			
		||||
                <template v-if="(fieldDescInfo.uneditable !== true)">
 | 
			
		||||
                  <!-- 有可选项的字段,走下拉框或者多选框 -->
 | 
			
		||||
                  <template v-if="(fieldDescInfo.choices !== undefined && fieldDescInfo.choices.length > 0)">
 | 
			
		||||
                    <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
 | 
			
		||||
                      <el-tooltip effect="light" :content="fieldDescInfo.help_text" placement="bottom-start">
 | 
			
		||||
                        <el-select :placeholder="(fieldDescInfo.multi_choice === true ? '--多选--' : '--单选--')"
 | 
			
		||||
                                   v-model="dialogEditForm[fieldDescInfo.key]" style="width: 150px"
 | 
			
		||||
                                   :multiple="(fieldDescInfo.multi_choice === true)">
 | 
			
		||||
                          <el-option v-for="info in fieldDescInfo.choices" :key="info.desc" :label="info.desc"
 | 
			
		||||
                                     :value="info.value"></el-option>
 | 
			
		||||
                        </el-select>
 | 
			
		||||
                      </el-tooltip>
 | 
			
		||||
                    </el-form-item>
 | 
			
		||||
                  </template>
 | 
			
		||||
 | 
			
		||||
                  <!-- 时间戳字段,展示时间选择器 -->
 | 
			
		||||
                  <template v-else-if="(fieldDescInfo.type === 'Time')">
 | 
			
		||||
                    <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
 | 
			
		||||
                      <el-date-picker v-model="dialogEditForm[fieldDescInfo.key]" type="datetime"
 | 
			
		||||
                                      placeholder="选个时间" format="YYYY/MM/DD HH:mm:ss"
 | 
			
		||||
                                      value-format="YYYY/MM/DD HH:mm:ss"></el-date-picker>
 | 
			
		||||
                    </el-form-item>
 | 
			
		||||
                  </template>
 | 
			
		||||
 | 
			
		||||
                  <!-- 否则就是普通字段 -->
 | 
			
		||||
                  <template v-else>
 | 
			
		||||
                    <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
 | 
			
		||||
                      <el-input v-model="dialogEditForm[fieldDescInfo.key]"
 | 
			
		||||
                                :placeholder="fieldDescInfo.help_text"></el-input>
 | 
			
		||||
                    </el-form-item>
 | 
			
		||||
                  </template>
 | 
			
		||||
                </template>
 | 
			
		||||
 | 
			
		||||
                <template v-else>
 | 
			
		||||
                  <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
 | 
			
		||||
                    <el-input v-model="dialogEditForm[fieldDescInfo.key]"
 | 
			
		||||
                              :placeholder="fieldDescInfo.help_text" disabled></el-input>
 | 
			
		||||
                  </el-form-item>
 | 
			
		||||
                </template>
 | 
			
		||||
 | 
			
		||||
              </template>
 | 
			
		||||
 | 
			
		||||
              <!--            <el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">-->
 | 
			
		||||
              <!--              <el-input v-model="dialogEditForm[fieldDescInfo.key]"></el-input>-->
 | 
			
		||||
              <!--            </el-form-item>-->
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <el-form-item>
 | 
			
		||||
              <el-button @click="submitEdit(dialogEditFormRef)" size="large" type="primary">提交</el-button>
 | 
			
		||||
            </el-form-item>
 | 
			
		||||
          </el-form>
 | 
			
		||||
        </el-dialog>
 | 
			
		||||
 | 
			
		||||
      </el-main>
 | 
			
		||||
    </el-container>
 | 
			
		||||
  </template>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.demo-pagination-block {
 | 
			
		||||
  margin-top: 10px;
 | 
			
		||||
 | 
			
		||||
  .el-pagination {
 | 
			
		||||
    right: 40px;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@ -123,6 +123,9 @@ export function setProjectOperationRoutes(projectList) {
 | 
			
		||||
                component: () => import('@/views/project/project_op.vue'),
 | 
			
		||||
                props: true
 | 
			
		||||
            }
 | 
			
		||||
            if (resource.resource === 'cdkey') {
 | 
			
		||||
                resourceRoute.component = () => import('@/views/project/project_cdkey.vue')
 | 
			
		||||
            }
 | 
			
		||||
            resource.show_methods.forEach((method) => {
 | 
			
		||||
                if (method == "get") {
 | 
			
		||||
                    projectHasAnyResourcePermission = true
 | 
			
		||||
 | 
			
		||||
@ -47,6 +47,15 @@ const reqInterceptor = (config) => {
 | 
			
		||||
 | 
			
		||||
const resInterceptor = (res) => {
 | 
			
		||||
    console.log("res:", res.data)
 | 
			
		||||
    const contentDisposition = res.headers['content-disposition'];
 | 
			
		||||
    const filenameRegex = /filename\*?=(?:UTF-8'')?"?([^";]+)"?/i;
 | 
			
		||||
    if (contentDisposition) {
 | 
			
		||||
        const matches = contentDisposition.match(filenameRegex);
 | 
			
		||||
        if (matches) {
 | 
			
		||||
            return res
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const code = res.data.code
 | 
			
		||||
    if (code != 200) {
 | 
			
		||||
        if (code === 5) {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="login-box">
 | 
			
		||||
    <div :class="{ active: currentModel, container: true,animate__animated :true, animate__flipInX :true}">
 | 
			
		||||
    <div :class="{  container: true,animate__animated :true, animate__flipInX :true}">
 | 
			
		||||
      <div class="form-container sign-in-container">
 | 
			
		||||
        <el-form
 | 
			
		||||
            ref="ruleFormRef"
 | 
			
		||||
@ -72,6 +72,7 @@ const loginRules = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const submitForm = (formEl) => {
 | 
			
		||||
  // console.log("点击登录")
 | 
			
		||||
  if (!formEl) return
 | 
			
		||||
  // 对表单的内容进行验证
 | 
			
		||||
  proxy.$refs.ruleFormRef.validate((valid) => {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								ui/src/views/project/project_cdkey.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								ui/src/views/project/project_cdkey.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
<script setup>
 | 
			
		||||
 | 
			
		||||
import table from "@/components/restful/tableCDKey.vue"
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <component :is="table"></component>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user