fix-4944
into V20240129
2 months ago
@@ -16,7 +16,6 @@ import ( | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/git" | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/structs" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
) | |||
@@ -148,7 +147,13 @@ type AITaskDetailInfo struct { | |||
} | |||
func (a *AITaskDetailInfo) Tr(language string) { | |||
a.AICenter = getAiCenterShow(a.AICenter, language) | |||
aiCenterInfo := strings.Split(a.AICenter, "+") | |||
aiCenterCode := aiCenterInfo[0] | |||
aiCenterName := "" | |||
if len(aiCenterCode) >= 2 { | |||
aiCenterName = aiCenterInfo[1] | |||
} | |||
a.AICenter = models.GetAiCenterShow(aiCenterCode, aiCenterName, language) | |||
} | |||
func (a *AITaskDetailInfo) TryToRemoveDatasets(currentUser *models.User) { | |||
@@ -167,28 +172,6 @@ func (a *AITaskDetailInfo) TryToRemoveSDKCode(currentUser *models.User) { | |||
} | |||
} | |||
func getAiCenterShow(aiCenter string, language string) string { | |||
aiCenterInfo := strings.Split(aiCenter, "+") | |||
if len(aiCenterInfo) == 2 { | |||
if setting.AiCenterCodeAndNameAndLocMapInfo != nil { | |||
if info, ok := setting.AiCenterCodeAndNameAndLocMapInfo[aiCenterInfo[0]]; ok { | |||
if language == defaultLanguage { | |||
return info.Content | |||
} else { | |||
return info.ContentEN | |||
} | |||
} else { | |||
return aiCenterInfo[1] | |||
} | |||
} else { | |||
return aiCenterInfo[1] | |||
} | |||
} | |||
return "" | |||
} | |||
var defaultLanguage = "zh-CN" | |||
type CreateTaskRes struct { | |||
ID int64 `json:"id"` | |||
Status string `json:"status"` | |||
@@ -231,7 +214,13 @@ type AITaskBriefInfo struct { | |||
} | |||
func (a *AITaskBriefInfo) Tr(language string) { | |||
a.AICenter = getAiCenterShow(a.AICenter, language) | |||
aiCenterInfo := strings.Split(a.AICenter, "+") | |||
aiCenterCode := aiCenterInfo[0] | |||
aiCenterName := "" | |||
if len(aiCenterCode) >= 2 { | |||
aiCenterName = aiCenterInfo[1] | |||
} | |||
a.AICenter = models.GetAiCenterShow(aiCenterCode, aiCenterName, language) | |||
} | |||
type AITaskListRes struct { | |||
@@ -34,6 +34,7 @@ type CardRequest struct { | |||
Contact string | |||
PhoneNumber string | |||
EmailAddress string | |||
Wechat string | |||
Org string `xorm:"varchar(500)"` | |||
Description string `xorm:"varchar(3000)"` | |||
Status int | |||
@@ -59,6 +60,7 @@ type CardRequestSpecRes struct { | |||
Contact string | |||
PhoneNumber string | |||
EmailAddress string | |||
Wechat string | |||
Org string | |||
Description string | |||
Status int | |||
@@ -118,6 +120,7 @@ type CardRequestSpecShow struct { | |||
Contact string `json:"contact"` | |||
PhoneNumber string `json:"phone_number"` | |||
EmailAddress string `json:"email_address"` | |||
Wechat string `json:"wechat"` | |||
Org string `json:"org"` | |||
Description string `json:"description"` | |||
Status int `json:"status"` | |||
@@ -282,8 +285,8 @@ func SearchCardRequest(opts *CardRequestOptions) (int64, []*CardRequestSpecRes, | |||
cond = cond.And(builder.Or(builder.Like{"LOWER(card_request.contact)", lowerKeyWord}, | |||
builder.Like{"LOWER(card_request.acc_cards_num)", lowerKeyWord}, | |||
builder.Like{"LOWER(card_request.description)", lowerKeyWord}, builder.Like{"LOWER(card_request.description)", lowerKeyWord}, | |||
builder.Like{"LOWER(card_request.phone_number)", lowerKeyWord}, builder.Like{"LOWER(card_request.org)", lowerKeyWord}, | |||
builder.Like{"LOWER(\"user\".name)", lowerKeyWord})) | |||
builder.Like{"LOWER(card_request.phone_number)", lowerKeyWord}, builder.Like{"LOWER(card_request.wechat)", lowerKeyWord}, | |||
builder.Like{"LOWER(card_request.org)", lowerKeyWord}, builder.Like{"LOWER(\"user\".name)", lowerKeyWord})) | |||
} | |||
if opts.UserID != 0 { | |||
cond = cond.And(builder.Eq{"\"user\".id": opts.UserID}) | |||
@@ -331,7 +334,7 @@ func SearchCardRequest(opts *CardRequestOptions) (int64, []*CardRequestSpecRes, | |||
cond = cond.And(builder.NewCond().Or(builder.Eq{"card_request.delete_unix": 0}).Or(builder.IsNull{"card_request.delete_unix"})) | |||
cols := []string{"card_request.id", "card_request.compute_resource", "card_request.contact", "card_request.card_type", "card_request.acc_cards_num", | |||
"card_request.disk_capacity", "card_request.resource_type", "card_request.begin_date", "card_request.end_date", "card_request.uid", | |||
"card_request.phone_number", "card_request.email_address", "card_request.org", "card_request.description", "card_request.status", "card_request.review", | |||
"card_request.phone_number", "card_request.email_address", "card_request.wechat", "card_request.org", "card_request.description", "card_request.status", "card_request.review", | |||
"card_request.created_unix"} | |||
var count int64 | |||
var err error | |||
@@ -437,6 +440,6 @@ func SearchCardRequest(opts *CardRequestOptions) (int64, []*CardRequestSpecRes, | |||
} | |||
func UpdateCardRequest(cardRequest *CardRequest) error { | |||
_, err := x.ID(cardRequest.ID).Cols("compute_resource", "contact", "card_type", "acc_cards_num", "disk_capacity", "resource_type", "begin_date", "end_date", "phone_number", "email_address", "org", "description", "begin_unix", "end_unix").Update(cardRequest) | |||
_, err := x.ID(cardRequest.ID).Cols("compute_resource", "contact", "card_type", "acc_cards_num", "disk_capacity", "resource_type", "begin_date", "end_date", "phone_number", "wechat", "email_address", "org", "description", "begin_unix", "end_unix").Update(cardRequest) | |||
return err | |||
} |
@@ -17,8 +17,6 @@ type ResourceExclusivePool struct { | |||
CreatedBy int64 | |||
UpdatedTime timeutil.TimeStamp `xorm:"updated"` | |||
UpdatedBy int64 | |||
DeleteTime timeutil.TimeStamp `xorm:"deleted"` | |||
DeletedBy int64 | |||
} | |||
func FindExclusivePools() ([]*ResourceExclusivePool, error) { | |||
@@ -42,7 +40,7 @@ func IsQueueInExclusivePool(queueId int64) bool { | |||
func FindExclusiveQueueIds() []int64 { | |||
existsIds := make([]int64, 0) | |||
err := x.Table("resource_exclusive_pool").Distinct("queue_id").Where("delete_time=? OR delete_time IS NULL", 0).Find(&existsIds) | |||
err := x.Table("resource_exclusive_pool").Distinct("queue_id").Find(&existsIds) | |||
if err != nil { | |||
log.Error("FindQueuesExclusiveMap err.%v", err) | |||
return existsIds | |||
@@ -2,6 +2,7 @@ package models | |||
import ( | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"errors" | |||
"strconv" | |||
@@ -27,6 +28,7 @@ type ResourceQueue struct { | |||
CardsTotalNum int | |||
HasInternet int //0 unknown;1 no internet;2 has internet | |||
IsAutomaticSync bool | |||
IsAvailable bool | |||
Remark string | |||
DeletedTime timeutil.TimeStamp `xorm:"deleted"` | |||
CreatedTime timeutil.TimeStamp `xorm:"created"` | |||
@@ -50,6 +52,7 @@ func (r ResourceQueue) ConvertToRes() *ResourceQueueRes { | |||
UpdatedTime: r.UpdatedTime, | |||
Remark: r.Remark, | |||
HasInternet: AICenterInternetStatus(r.HasInternet), | |||
IsAvailable: r.IsAvailable, | |||
} | |||
} | |||
@@ -66,9 +69,14 @@ type ResourceQueueReq struct { | |||
Remark string | |||
QueueName string | |||
QueueType string | |||
IsAvailable int | |||
} | |||
func (r ResourceQueueReq) ToDTO() ResourceQueue { | |||
isAvailable := false | |||
if r.IsAvailable == 2 { | |||
isAvailable = true | |||
} | |||
q := ResourceQueue{ | |||
QueueCode: r.QueueCode, | |||
Cluster: r.Cluster, | |||
@@ -83,6 +91,7 @@ func (r ResourceQueueReq) ToDTO() ResourceQueue { | |||
UpdatedBy: r.CreatorId, | |||
QueueName: r.QueueName, | |||
QueueType: r.QueueType, | |||
IsAvailable: isAvailable, | |||
} | |||
if r.Cluster == OpenICluster { | |||
if r.AiCenterCode == AICenterOfCloudBrainOne { | |||
@@ -104,6 +113,7 @@ type SearchResourceQueueOptions struct { | |||
AccCardType string | |||
HasInternet SpecInternetQuery | |||
QueueType string | |||
IsAvailable int | |||
IsQueueExclusive int | |||
} | |||
@@ -133,6 +143,10 @@ type ResourceAiCenterRes struct { | |||
AiCenterName string | |||
} | |||
func (r *ResourceAiCenterRes) Tr(language string) { | |||
r.AiCenterName = GetAiCenterShow(r.AiCenterCode, r.AiCenterName, language) | |||
} | |||
type GetQueueCodesOptions struct { | |||
Cluster string | |||
} | |||
@@ -166,6 +180,7 @@ type ResourceQueueRes struct { | |||
UpdatedTime timeutil.TimeStamp | |||
Remark string | |||
HasInternet AICenterInternetStatus | |||
IsAvailable bool | |||
IsQueueExclusive bool | |||
} | |||
@@ -176,8 +191,54 @@ func InsertResourceQueue(queue ResourceQueue) (int64, error) { | |||
func UpdateResourceQueueById(queueId int64, queue ResourceQueue) (int64, error) { | |||
return x.ID(queueId).Update(&queue) | |||
} | |||
func UpdateResourceCardsTotalNumAndInternetStatus(queueId int64, queue ResourceQueue) (int64, error) { | |||
return x.ID(queueId).Cols("cards_total_num", "remark", "has_internet", "queue_type", "queue_name").Update(&queue) | |||
func UpdateResourceCardsTotalNumAndInternetStatus(queueId int64, queue ResourceQueue, isAvailable int) (int64, error) { | |||
sess := x.NewSession() | |||
if err := sess.Begin(); err != nil { | |||
sess.Close() | |||
return 0, err | |||
} | |||
var err error | |||
defer func() { | |||
if err != nil { | |||
sess.Rollback() | |||
} | |||
sess.Close() | |||
}() | |||
cols := []string{"cards_total_num", "remark", "has_internet", "queue_type", "queue_name"} | |||
if isAvailable > 0 { | |||
if isAvailable == 1 { | |||
cols = append(cols, "is_available") | |||
queue.IsAvailable = false | |||
} else if isAvailable == 2 { | |||
cols = append(cols, "is_available") | |||
queue.IsAvailable = true | |||
} | |||
} | |||
n, err := sess.ID(queueId).Cols(cols...).Update(&queue) | |||
if err != nil { | |||
return 0, err | |||
} | |||
specIds := make([]int64, 0) | |||
if err = sess.Cols("resource_specification.id").Table("resource_specification"). | |||
In("queue_id", queueId).Find(&specIds); err != nil { | |||
return 0, err | |||
} | |||
if len(specIds) == 0 { | |||
return n, nil | |||
} | |||
if isAvailable == 1 { | |||
if _, err = sess.Cols("status", "is_available").Table("resource_specification").In("id", specIds).Update(&ResourceSpecification{Status: SpecOffShelf, IsAvailable: false}); err != nil { | |||
return 0, err | |||
} | |||
} else if isAvailable == 2 { | |||
if _, err = sess.Cols("is_available").Table("resource_specification").In("id", specIds).Update(&ResourceSpecification{IsAvailable: true}); err != nil { | |||
return 0, err | |||
} | |||
} | |||
sess.Commit() | |||
return n, nil | |||
} | |||
func SearchResourceQueue(opts SearchResourceQueueOptions) (int64, []ResourceQueue, error) { | |||
@@ -205,6 +266,13 @@ func SearchResourceQueue(opts SearchResourceQueueOptions) (int64, []ResourceQueu | |||
if opts.QueueType != "" { | |||
cond = cond.And(builder.Eq{"queue_type": opts.QueueType}) | |||
} | |||
if opts.IsAvailable > 0 { | |||
if opts.IsAvailable == 1 { | |||
cond = cond.And(builder.Eq{"is_available": false}) | |||
} else if opts.IsAvailable == 2 { | |||
cond = cond.And(builder.Eq{"is_available": true}) | |||
} | |||
} | |||
if opts.IsQueueExclusive > 0 { | |||
queueIds := FindExclusiveQueueIds() | |||
if opts.IsQueueExclusive == 1 { | |||
@@ -348,10 +416,7 @@ func SyncGrampusQueues(updateList []ResourceQueue, insertList []ResourceQueue, e | |||
} | |||
if len(deleteQueueIds) > 0 { | |||
if _, err = sess.In("id", deleteQueueIds).Update(&ResourceQueue{Remark: "自动同步时被下架"}); err != nil { | |||
return err | |||
} | |||
if _, err = sess.In("id", deleteQueueIds).Delete(&ResourceQueue{}); err != nil { | |||
if _, err = sess.Cols("is_available").Table("resource_queue").In("id", deleteQueueIds).Update(&ResourceQueue{IsAvailable: false}); err != nil { | |||
return err | |||
} | |||
@@ -362,7 +427,7 @@ func SyncGrampusQueues(updateList []ResourceQueue, insertList []ResourceQueue, e | |||
return err | |||
} | |||
if len(deleteSpcIds) > 0 { | |||
if _, err = sess.In("id", deleteSpcIds).Update(&ResourceSpecification{Status: SpecOffShelf}); err != nil { | |||
if _, err = sess.Cols("status", "is_available").Table("resource_specification").In("id", deleteSpcIds).Update(&ResourceSpecification{Status: SpecOffShelf, IsAvailable: false}); err != nil { | |||
return err | |||
} | |||
} | |||
@@ -375,6 +440,9 @@ func SyncGrampusQueues(updateList []ResourceQueue, insertList []ResourceQueue, e | |||
if _, err = sess.ID(v.ID).Update(&v); err != nil { | |||
return err | |||
} | |||
if _, err = sess.ID(v.ID).Cols("is_available").Table("resource_queue").Update(&v); err != nil { | |||
return err | |||
} | |||
} | |||
} | |||
@@ -399,6 +467,17 @@ func GetResourceAiCenters() ([]ResourceAiCenterRes, error) { | |||
return r, nil | |||
} | |||
func GetAvailableResourceAiCenters() ([]*ResourceAiCenterRes, error) { | |||
r := make([]*ResourceAiCenterRes, 0) | |||
sql := "SELECT t.ai_center_code, t.ai_center_name FROM (SELECT DISTINCT resource_queue.ai_center_code, resource_queue.ai_center_name,resource_queue.cluster FROM resource_queue inner join resource_specification on resource_queue.id = resource_specification.queue_id inner join resource_scene_spec on resource_specification.id = resource_scene_spec.spec_id WHERE (resource_queue.deleted_time IS NULL OR resource_queue.deleted_time=0) and resource_queue.is_available = true and resource_specification.status = 2 ) t ORDER BY cluster desc,ai_center_code asc" | |||
err := x.SQL(sql).Find(&r) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return r, nil | |||
} | |||
func GetExclusiveQueueIds(opts FindSpecsOptions) []*ResourceExclusivePool { | |||
pools, err := FindExclusivePools() | |||
if err != nil { | |||
@@ -446,3 +525,28 @@ func IsUserInExclusivePool(userId int64) bool { | |||
} | |||
return false | |||
} | |||
var defaultLanguage = "zh-CN" | |||
func GetAiCenterShow(aiCenterCode, aiCenterName, language string) string { | |||
if aiCenterCode == "" { | |||
return aiCenterName | |||
} | |||
if aiCenterName == "" { | |||
aiCenterName = aiCenterCode | |||
} | |||
if setting.AiCenterCodeAndNameAndLocMapInfo != nil { | |||
if info, ok := setting.AiCenterCodeAndNameAndLocMapInfo[aiCenterCode]; ok { | |||
if language == defaultLanguage { | |||
return info.Content | |||
} else { | |||
return info.ContentEN | |||
} | |||
} else { | |||
return aiCenterName | |||
} | |||
} else { | |||
return aiCenterName | |||
} | |||
return "" | |||
} |
@@ -909,3 +909,269 @@ func GetGrampusSpecs() (map[string]*Specification, error) { | |||
} | |||
return grampusSpecs, nil | |||
} | |||
type GetResourceListOpts struct { | |||
ListOptions | |||
Resource []string | |||
AccCardType string | |||
AccCardNum int | |||
ExcludeAccCardNums []int | |||
AICenterCode string | |||
MinPrice int | |||
MaxPrice int | |||
} | |||
type ResourceDetailInfo struct { | |||
Spec ResourceSpecificationRes | |||
IsQueueExclusive bool | |||
AICenterList []ResourceAiCenterRes | |||
} | |||
type ResourceInfo4CardRequest struct { | |||
ComputeResource string | |||
AccCardType string | |||
AccCardsNum int | |||
CpuCores int | |||
MemGiB float32 | |||
GPUMemGiB float32 | |||
ShareMemGiB float32 | |||
UnitPrice int | |||
IsExclusive bool | |||
IsSpecExclusive string | |||
AICenterList []*ResourceAiCenterRes | |||
} | |||
func (r *ResourceInfo4CardRequest) Tr(language string) { | |||
if r.AICenterList == nil { | |||
return | |||
} | |||
for i := 0; i < len(r.AICenterList); i++ { | |||
r.AICenterList[i].Tr(language) | |||
} | |||
} | |||
type ResourceWithAICenter4CardRequest struct { | |||
Cluster string | |||
AICenterCode string | |||
AICenterName string | |||
ComputeResource string | |||
AccCardType string | |||
AccCardsNum int | |||
CpuCores int | |||
MemGiB float32 | |||
GPUMemGiB float32 | |||
ShareMemGiB float32 | |||
UnitPrice int | |||
IsExclusive bool | |||
IsSpecExclusive string | |||
} | |||
func GetResourceListPaging(opts GetResourceListOpts) ([]*ResourceInfo4CardRequest, int64, error) { | |||
cond := builder.NewCond() | |||
resourceList := make([]string, 0) | |||
for i := 0; i < len(opts.Resource); i++ { | |||
if opts.Resource[i] != "" { | |||
resourceList = append(resourceList, opts.Resource[i]) | |||
} | |||
} | |||
if len(resourceList) > 0 { | |||
cond = cond.And(builder.In("resource_queue.compute_resource", resourceList)) | |||
} | |||
if opts.AccCardType != "" { | |||
cond = cond.And(builder.Eq{"resource_queue.acc_card_type": opts.AccCardType}) | |||
} | |||
if opts.AccCardNum >= 0 { | |||
if opts.AccCardNum > 999 { | |||
cond = cond.And(builder.NotIn("resource_specification.acc_cards_num", opts.ExcludeAccCardNums)) | |||
} else { | |||
cond = cond.And(builder.Eq{"resource_specification.acc_cards_num": opts.AccCardNum}) | |||
} | |||
} | |||
if opts.AICenterCode != "" { | |||
cond = cond.And(builder.Eq{"resource_queue.ai_center_code": opts.AICenterCode}) | |||
} | |||
if opts.MaxPrice >= 0 && opts.MinPrice >= 0 && opts.MaxPrice < opts.MinPrice { | |||
opts.MaxPrice = -1 | |||
opts.MinPrice = -1 | |||
} | |||
if opts.MaxPrice >= 0 { | |||
cond = cond.And(builder.Lte{"resource_specification.unit_price": opts.MaxPrice}) | |||
} | |||
if opts.MinPrice >= 0 { | |||
cond = cond.And(builder.Gte{"resource_specification.unit_price": opts.MinPrice}) | |||
} | |||
cond = cond.And(builder.Or(builder.Eq{"resource_queue.deleted_time": 0}, builder.IsNull{"resource_queue.deleted_time"})) | |||
cond = cond.And(builder.Eq{"resource_specification.status": 2}) | |||
//先按多字段去重分页查询资源规格 | |||
//再基于结果查询智算中心信息 | |||
resourceInfos := make([]*ResourceInfo4CardRequest, 0) | |||
err := x.Table("resource_specification"). | |||
Join("LEFT", "resource_exclusive_pool", "resource_specification.queue_id = resource_exclusive_pool.queue_id"). | |||
Join("INNER", "resource_queue", "resource_specification.queue_id = resource_queue.id"). | |||
Join("INNER", "resource_scene_spec", "resource_specification.id = resource_scene_spec.spec_id"). | |||
Join("INNER", "resource_scene", "resource_scene.id = resource_scene_spec.scene_id"). | |||
Select("Distinct resource_queue.compute_resource, resource_queue.acc_card_type," + | |||
"resource_specification.acc_cards_num, resource_specification.cpu_cores, resource_specification.mem_gi_b, " + | |||
"resource_specification.gpu_mem_gi_b, resource_specification.share_mem_gi_b, resource_specification.unit_price," + | |||
"COALESCE(resource_exclusive_pool.queue_id IS NOT NULL, false) AS is_exclusive,resource_scene.is_spec_exclusive"). | |||
Where(cond). | |||
OrderBy(" resource_queue.compute_resource DESC,resource_queue.acc_card_type ,is_exclusive," + | |||
"resource_specification.acc_cards_num DESC,resource_specification.gpu_mem_gi_b DESC," + | |||
"resource_specification.cpu_cores DESC,resource_specification.mem_gi_b DESC"). | |||
Find(&resourceInfos) | |||
if err != nil { | |||
return nil, 0, err | |||
} | |||
tmpResourceInfos := make([]*ResourceInfo4CardRequest, 0) | |||
for i := 0; i < len(resourceInfos); i++ { | |||
//此处是为了过滤那些专属池中的规格又被配置到共享场景中的情况 | |||
if !resourceInfos[i].IsExclusive || (resourceInfos[i].IsExclusive && resourceInfos[i].IsSpecExclusive == "") { | |||
tmpResourceInfos = append(tmpResourceInfos, resourceInfos[i]) | |||
} | |||
} | |||
resourceInfos = tmpResourceInfos | |||
if len(resourceInfos) == 0 { | |||
return []*ResourceInfo4CardRequest{}, 0, nil | |||
} | |||
total := int64(len(resourceInfos)) | |||
startIndex := int64((opts.Page - 1) * opts.PageSize) | |||
endIndex := int64(opts.Page * opts.PageSize) | |||
if startIndex >= total { | |||
return []*ResourceInfo4CardRequest{}, 0, nil | |||
} | |||
if endIndex > total { | |||
endIndex = total | |||
} | |||
resourceInfos = resourceInfos[startIndex:endIndex] | |||
newCond := builder.NewCond() | |||
for _, spec := range resourceInfos { | |||
if spec.IsExclusive { | |||
newCond = newCond.Or(builder.And(builder.Eq{"resource_queue.compute_resource": spec.ComputeResource}, | |||
builder.Eq{"resource_queue.acc_card_type": spec.AccCardType}, | |||
builder.Eq{"resource_specification.acc_cards_num": spec.AccCardsNum}, | |||
builder.Eq{"resource_specification.cpu_cores": spec.CpuCores}, | |||
builder.Eq{"resource_specification.mem_gi_b": spec.MemGiB}, | |||
builder.Eq{"resource_specification.gpu_mem_gi_b": spec.GPUMemGiB}, | |||
builder.Eq{"resource_specification.share_mem_gi_b": spec.ShareMemGiB}, | |||
builder.Eq{"resource_specification.unit_price": spec.UnitPrice}, | |||
builder.NotNull{"resource_exclusive_pool.queue_id"})) | |||
} else if spec.IsSpecExclusive == SpecExclusive { | |||
newCond = newCond.Or(builder.And(builder.Eq{"resource_queue.compute_resource": spec.ComputeResource}, | |||
builder.Eq{"resource_queue.acc_card_type": spec.AccCardType}, | |||
builder.Eq{"resource_specification.acc_cards_num": spec.AccCardsNum}, | |||
builder.Eq{"resource_specification.cpu_cores": spec.CpuCores}, | |||
builder.Eq{"resource_specification.mem_gi_b": spec.MemGiB}, | |||
builder.Eq{"resource_specification.gpu_mem_gi_b": spec.GPUMemGiB}, | |||
builder.Eq{"resource_specification.share_mem_gi_b": spec.ShareMemGiB}, | |||
builder.Eq{"resource_specification.unit_price": spec.UnitPrice}, | |||
builder.Eq{"resource_scene.is_spec_exclusive": SpecExclusive}, | |||
builder.IsNull{"resource_exclusive_pool.queue_id"})) | |||
} else { | |||
newCond = newCond.Or(builder.And(builder.Eq{"resource_queue.compute_resource": spec.ComputeResource}, | |||
builder.Eq{"resource_queue.acc_card_type": spec.AccCardType}, | |||
builder.Eq{"resource_specification.acc_cards_num": spec.AccCardsNum}, | |||
builder.Eq{"resource_specification.cpu_cores": spec.CpuCores}, | |||
builder.Eq{"resource_specification.mem_gi_b": spec.MemGiB}, | |||
builder.Eq{"resource_specification.gpu_mem_gi_b": spec.GPUMemGiB}, | |||
builder.Eq{"resource_specification.share_mem_gi_b": spec.ShareMemGiB}, | |||
builder.Eq{"resource_specification.unit_price": spec.UnitPrice}, | |||
builder.Or(builder.Eq{"resource_scene.is_spec_exclusive": SpecPublic}, builder.IsNull{"resource_scene.is_spec_exclusive"}), | |||
builder.IsNull{"resource_exclusive_pool.queue_id"})) | |||
} | |||
} | |||
newCond = newCond.And(builder.Or(builder.Eq{"resource_queue.deleted_time": 0}, builder.IsNull{"resource_queue.deleted_time"})) | |||
newCond = newCond.And(builder.Eq{"resource_specification.status": 2}) | |||
withCenterInfos := make([]ResourceWithAICenter4CardRequest, 0) | |||
err = x.Table("resource_specification"). | |||
Join("LEFT", "resource_exclusive_pool", "resource_specification.queue_id = resource_exclusive_pool.queue_id"). | |||
Join("INNER", "resource_queue", "resource_specification.queue_id = resource_queue.id"). | |||
Join("INNER", "resource_scene_spec", "resource_specification.id = resource_scene_spec.spec_id"). | |||
Join("INNER", "resource_scene", "resource_scene.id = resource_scene_spec.scene_id"). | |||
Select("resource_queue.cluster,resource_queue.ai_center_code,resource_queue.ai_center_name,resource_queue.compute_resource, resource_queue.acc_card_type," + | |||
"resource_specification.acc_cards_num, resource_specification.cpu_cores, resource_specification.mem_gi_b, " + | |||
"resource_specification.gpu_mem_gi_b, resource_specification.share_mem_gi_b, resource_specification.unit_price," + | |||
"COALESCE(resource_exclusive_pool.queue_id IS NOT NULL, false) AS is_exclusive,resource_scene.is_spec_exclusive"). | |||
Where(newCond). | |||
Find(&withCenterInfos) | |||
if err != nil { | |||
return nil, 0, err | |||
} | |||
tmpMap := make(map[string][]*ResourceAiCenterRes, 0) | |||
for i := 0; i < len(withCenterInfos); i++ { | |||
t := withCenterInfos[i] | |||
key := fmt.Sprintf("%s_%s_%d_%d_%f_%f_%f_%d_%t_%s", t.ComputeResource, t.AccCardType, t.AccCardsNum, | |||
t.CpuCores, t.MemGiB, t.GPUMemGiB, t.ShareMemGiB, t.UnitPrice, t.IsExclusive, t.IsSpecExclusive) | |||
if _, exists := tmpMap[key]; exists { | |||
centerExists := false | |||
for _, center := range tmpMap[key] { | |||
if center.AiCenterCode == t.AICenterCode { | |||
centerExists = true | |||
} | |||
} | |||
if centerExists { | |||
continue | |||
} | |||
tmpMap[key] = append(tmpMap[key], &ResourceAiCenterRes{ | |||
AiCenterCode: t.AICenterCode, | |||
AiCenterName: t.AICenterName, | |||
}) | |||
} else { | |||
tmpMap[key] = []*ResourceAiCenterRes{{ | |||
AiCenterCode: t.AICenterCode, | |||
AiCenterName: t.AICenterName, | |||
}} | |||
} | |||
} | |||
for i := 0; i < len(resourceInfos); i++ { | |||
t := resourceInfos[i] | |||
key := fmt.Sprintf("%s_%s_%d_%d_%f_%f_%f_%d_%t_%s", t.ComputeResource, t.AccCardType, t.AccCardsNum, | |||
t.CpuCores, t.MemGiB, t.GPUMemGiB, t.ShareMemGiB, t.UnitPrice, t.IsExclusive, t.IsSpecExclusive) | |||
resourceInfos[i].AICenterList = tmpMap[key] | |||
} | |||
return resourceInfos, total, nil | |||
} | |||
type AccCardInfo struct { | |||
ComputeSource string | |||
CardList []string | |||
} | |||
func GetAccCardList() ([]AccCardInfo, error) { | |||
res := make([]AccCardInfo, 0) | |||
r := make([]*Specification, 0) | |||
err := x.Where("resource_specification.status = ? and (resource_queue.deleted_time = 0 or resource_queue.deleted_time is null)", SpecOnShelf). | |||
Join("INNER", "resource_queue", "resource_queue.id = resource_specification.queue_id"). | |||
Join("INNER", "resource_scene_spec", "resource_scene_spec.spec_id = resource_specification.id"). | |||
Join("INNER", "resource_scene", "resource_scene_spec.scene_id = resource_scene.id"). | |||
OrderBy("resource_queue.compute_resource asc,resource_queue.acc_card_type asc"). | |||
Unscoped().Distinct("resource_queue.compute_resource,resource_queue.acc_card_type").Find(&r) | |||
if err != nil { | |||
return nil, err | |||
} | |||
tmpMap := make(map[string][]string, 0) | |||
keys := make([]string, 0) | |||
for i := 0; i < len(r); i++ { | |||
spec := r[i] | |||
if _, exists := tmpMap[spec.ComputeResource]; exists { | |||
tmpMap[spec.ComputeResource] = append(tmpMap[spec.ComputeResource], spec.AccCardType) | |||
} else { | |||
keys = append(keys, spec.ComputeResource) | |||
tmpMap[spec.ComputeResource] = []string{spec.AccCardType} | |||
} | |||
} | |||
for i := 0; i < len(keys); i++ { | |||
res = append(res, AccCardInfo{ | |||
ComputeSource: keys[i], | |||
CardList: tmpMap[keys[i]], | |||
}) | |||
} | |||
return res, nil | |||
} |
@@ -12,6 +12,7 @@ type CardReq struct { | |||
Contact string `json:"contact" binding:"Required"` | |||
PhoneNumber string `json:"phone_number" binding:"Required"` | |||
EmailAddress string `json:"email_address" binding:"Required;Email;MaxSize(254)"` | |||
Wechat string `json:"wechat" binding:"Required;MaxSize(254)"` | |||
Org string `json:"org" binding:"MaxSize(500)"` | |||
Description string `json:"description" binding:"MaxSize(3000)"` | |||
Review string `json:"review"` | |||
@@ -49,6 +49,7 @@ func GetResourceQueueList(ctx *context.Context) { | |||
accCardType := ctx.Query("card") | |||
hasInternet := ctx.QueryInt("hasInternet") | |||
queueType := ctx.Query("queueType") | |||
isAvailable := ctx.QueryInt("isAvailable") | |||
isQueueExclusive := ctx.QueryInt("isQueueExclusive") | |||
if pageSize > 1000 { | |||
@@ -64,6 +65,7 @@ func GetResourceQueueList(ctx *context.Context) { | |||
AccCardType: accCardType, | |||
HasInternet: models.SpecInternetQuery(hasInternet), | |||
QueueType: queueType, | |||
IsAvailable: isAvailable, | |||
IsQueueExclusive: isQueueExclusive, | |||
}) | |||
if err != nil { | |||
@@ -59,6 +59,7 @@ | |||
package v1 | |||
import ( | |||
"code.gitea.io/gitea/routers/resources" | |||
"net/http" | |||
"strings" | |||
@@ -1491,6 +1492,11 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("/wechat/material", authentication.GetMaterial) | |||
m.Get("/cloudbrain/get_newest_job", repo.GetNewestJobs) | |||
m.Get("/cloudbrain/get_center_info", repo.GetAICenterInfo) | |||
m.Group("/resources", func() { | |||
m.Get("/acc_card/list", resources.GetAccCardList) | |||
m.Get("/ai_center/available", resources.GetAvailableAICenterList) | |||
}) | |||
}, securityHeaders(), context.APIContexter(), sudo()) | |||
} | |||
@@ -1,7 +1,10 @@ | |||
package card_request | |||
import ( | |||
"code.gitea.io/gitea/routers/response" | |||
"code.gitea.io/gitea/services/cloudbrain/resource" | |||
"net/http" | |||
"strconv" | |||
"strings" | |||
"time" | |||
@@ -52,6 +55,67 @@ func GetCardRequestList(ctx *context.Context) { | |||
getRequestShowList(ctx, opts, false) | |||
} | |||
func GetResourceList(ctx *context.Context) { | |||
page := ctx.QueryInt("page") | |||
pageSize := ctx.QueryInt("pageSize") | |||
r := ctx.QueryStrings("resource") | |||
accCardType := ctx.Query("accCardType") | |||
accCardNum := ctx.QueryInt("accCardNum") | |||
excludeAccCardNumStr := ctx.Query("excludeAccCardNums") | |||
centerCode := ctx.Query("centerCode") | |||
minPrice := ctx.QueryInt("minPrice") | |||
maxPrice := ctx.QueryInt("maxPrice") | |||
if page < 1 { | |||
page = 1 | |||
} | |||
if pageSize < 1 { | |||
pageSize = 15 | |||
} | |||
excludeAccCardNums := make([]int, 0) | |||
if excludeAccCardNumStr != "" { | |||
numStrArray := strings.Split(excludeAccCardNumStr, "|") | |||
for _, s := range numStrArray { | |||
if s == "" { | |||
continue | |||
} | |||
n, err := strconv.Atoi(s) | |||
if err == nil { | |||
excludeAccCardNums = append(excludeAccCardNums, n) | |||
} | |||
} | |||
} | |||
opts := models.GetResourceListOpts{ | |||
ListOptions: models.ListOptions{ | |||
Page: page, | |||
PageSize: pageSize, | |||
}, | |||
Resource: r, | |||
AccCardType: accCardType, | |||
AccCardNum: accCardNum, | |||
ExcludeAccCardNums: excludeAccCardNums, | |||
AICenterCode: centerCode, | |||
MinPrice: minPrice, | |||
MaxPrice: maxPrice, | |||
} | |||
res, total, err := resource.GetResourceListPaging(opts) | |||
if err != nil { | |||
log.Error("GetResourceList err.opts=%+v,%v", opts, err) | |||
ctx.JSON(http.StatusOK, response.OuterResponseError(err)) | |||
return | |||
} | |||
if res != nil { | |||
for i := 0; i < len(res); i++ { | |||
res[i].Tr(ctx.Language()) | |||
} | |||
} | |||
resultMap := make(map[string]interface{}) | |||
resultMap["list"] = res | |||
resultMap["total"] = total | |||
resultMap["page"] = page | |||
resultMap["pageSize"] = pageSize | |||
ctx.JSON(http.StatusOK, response.OuterSuccessWithData(resultMap)) | |||
} | |||
func GetMyCardRequestList(ctx *context.Context) { | |||
page := ctx.QueryInt("page") | |||
@@ -241,6 +305,7 @@ func getRequestShowList(ctx *context.Context, opts *models.CardRequestOptions, c | |||
customShow.Review = v.Review | |||
customShow.PhoneNumber = v.PhoneNumber | |||
customShow.EmailAddress = v.EmailAddress | |||
customShow.Wechat = v.Wechat | |||
customShow.Contact = v.Contact | |||
customShow.Specs = v.Specs | |||
customShow.Org = v.Org | |||
@@ -0,0 +1,35 @@ | |||
package resources | |||
import ( | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/routers/response" | |||
"code.gitea.io/gitea/services/cloudbrain/resource" | |||
"net/http" | |||
) | |||
func GetAccCardList(ctx *context.Context) { | |||
list, err := resource.GetAccCardList() | |||
if err != nil { | |||
log.Error("GetAccCardList error.%v", err) | |||
ctx.JSON(http.StatusOK, response.OuterResponseError(err)) | |||
return | |||
} | |||
m := map[string]interface{}{"list": list} | |||
ctx.JSON(http.StatusOK, response.OuterSuccessWithData(m)) | |||
} | |||
func GetAvailableAICenterList(ctx *context.Context) { | |||
list, err := resource.GetAvailableAICenter() | |||
if err != nil { | |||
log.Error("GetAvailableAICenterList error.%v", err) | |||
ctx.JSON(http.StatusOK, response.OuterResponseError(err)) | |||
return | |||
} | |||
for i := 0; i < len(list); i++ { | |||
list[i].Tr(ctx.Language()) | |||
} | |||
m := map[string]interface{}{"list": list} | |||
ctx.JSON(http.StatusOK, response.OuterSuccessWithData(m)) | |||
} |
@@ -451,7 +451,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Group("/card_request", func() { | |||
m.Get("/creation/required", card_request.GetCreationInfo) | |||
m.Get("/list", card_request.GetCardRequestList) | |||
m.Get("/resource/list", card_request.GetResourceList) | |||
}, ignSignIn) | |||
m.Group("/card_request", func() { | |||
@@ -21,9 +21,9 @@ func GetCreationInfo() (map[string][]string, error) { | |||
for _, xpuInfo := range xpuInfoBase { | |||
if _, ok := xpuInfoMap[xpuInfo.ResourceType]; ok { | |||
xpuInfoMap[xpuInfo.ResourceType] = append(xpuInfoMap[xpuInfo.ResourceType], xpuInfo.CardTypeShow) | |||
xpuInfoMap[xpuInfo.ResourceType] = append(xpuInfoMap[xpuInfo.ResourceType], xpuInfo.CardType) | |||
} else { | |||
xpuInfoMap[xpuInfo.ResourceType] = []string{xpuInfo.CardTypeShow} | |||
xpuInfoMap[xpuInfo.ResourceType] = []string{xpuInfo.CardType} | |||
} | |||
} | |||
return xpuInfoMap, nil | |||
@@ -53,6 +53,7 @@ func UpdateCardRequestAdmin(cardReq api.CardReq) error { | |||
DiskCapacity: cardReq.DiskCapacity, | |||
Contact: cardReq.Contact, | |||
PhoneNumber: cardReq.PhoneNumber, | |||
Wechat: cardReq.Wechat, | |||
BeginDate: cardReq.BeginDate, | |||
EndDate: cardReq.EndDate, | |||
Description: cardReq.Description, | |||
@@ -91,6 +92,7 @@ func UpdateCardRequest(cardReq api.CardReq, request *models.CardRequest) error { | |||
request.Contact = cardReq.Contact | |||
request.EmailAddress = cardReq.EmailAddress | |||
request.PhoneNumber = cardReq.PhoneNumber | |||
request.Wechat = cardReq.Wechat | |||
beginTime, err := time.Parse(DATE_LAYOUT, cardReq.BeginDate) | |||
if err != nil { | |||
@@ -121,6 +123,7 @@ func CreateCardRequest(cardReq api.CardReq, uid int64) error { | |||
DiskCapacity: cardReq.DiskCapacity, | |||
Contact: cardReq.Contact, | |||
PhoneNumber: cardReq.PhoneNumber, | |||
Wechat: cardReq.Wechat, | |||
BeginDate: cardReq.BeginDate, | |||
EndDate: cardReq.EndDate, | |||
Description: cardReq.Description, | |||
@@ -23,7 +23,7 @@ func UpdateResourceQueue(queueId int64, req models.ResourceQueueReq) error { | |||
QueueName: req.QueueName, | |||
Remark: req.Remark, | |||
HasInternet: req.HasInternet, | |||
}); err != nil { | |||
}, req.IsAvailable); err != nil { | |||
return err | |||
} | |||
return nil | |||
@@ -159,6 +159,7 @@ func SyncGrampusQueue(doerId int64) error { | |||
QueueCode: queue.QueueCode, | |||
QueueName: queue.QueueName, | |||
QueueType: queue.QueueType, | |||
IsAvailable: true, | |||
}) | |||
} else { | |||
existIds = append(existIds, oldQueue.ID) | |||
@@ -171,6 +172,7 @@ func SyncGrampusQueue(doerId int64) error { | |||
HasInternet: hasInternet, | |||
QueueName: queue.QueueName, | |||
QueueType: queue.QueueType, | |||
IsAvailable: true, | |||
}) | |||
} | |||
@@ -210,7 +210,7 @@ func ResourceSpecOnShelf(doerId int64, id int64, unitPrice int) *response.BizErr | |||
if spec == nil { | |||
return response.SPECIFICATION_NOT_EXIST | |||
} | |||
if q, err := models.GetResourceQueue(&models.ResourceQueue{ID: spec.QueueId}); err != nil || q == nil { | |||
if q, err := models.GetResourceQueue(&models.ResourceQueue{ID: spec.QueueId}); err != nil || q == nil || !q.IsAvailable { | |||
return response.RESOURCE_QUEUE_NOT_AVAILABLE | |||
} | |||
if !spec.IsAvailable { | |||
@@ -700,3 +700,15 @@ func InitQueueAndSpec(opt models.FindSpecsOptions, aiCenterName string, remark s | |||
IsAvailable: true, | |||
}) | |||
} | |||
func GetResourceListPaging(opts models.GetResourceListOpts) ([]*models.ResourceInfo4CardRequest, int64, error) { | |||
return models.GetResourceListPaging(opts) | |||
} | |||
func GetAccCardList() ([]models.AccCardInfo, error) { | |||
return models.GetAccCardList() | |||
} | |||
func GetAvailableAICenter() ([]*models.ResourceAiCenterRes, error) { | |||
return models.GetAvailableResourceAiCenters() | |||
} |
@@ -93,7 +93,7 @@ | |||
margin-right: 10px !important; | |||
border: 1px solid #d4d4d5; | |||
border-radius: 4px; | |||
box-shadow: 0 1px 2px 0 rgb(34 36 38 / 15%); | |||
box-shadow: 0 1px 2px 0 rgba(34, 36, 38, 15%); | |||
background-color: #fafafa !important; | |||
.item { | |||
align-self: flex-start !important; | |||
@@ -1,6 +1,67 @@ | |||
import service from "../service"; | |||
import Qs from 'qs'; | |||
// 算力需求-算力资源查询智算中心列表 | |||
export const getAvailableAiCenterList = () => { | |||
return service({ | |||
url: `/api/v1/resources/ai_center/available`, | |||
method: 'get', | |||
params: {}, | |||
data: {}, | |||
}); | |||
} | |||
// 查询智算列表 | |||
export const getAiCenterList = () => { | |||
return service({ | |||
url: `/explore/card_request/resources/queue/centers`, | |||
method: 'get', | |||
params: {}, | |||
data: {}, | |||
}); | |||
} | |||
// 查询所有资源队列名称列表 | |||
export const getResQueueCode = (params) => { // cluster | |||
return service({ | |||
url: `/explore/card_request/resources/queue/codes`, | |||
method: 'get', | |||
params, | |||
}); | |||
} | |||
// 获取资源规格清单 | |||
// params -cluster,resource,available, | |||
export const getSpecificationList = (params) => { | |||
return service({ | |||
url: `/explore/card_request/specification/list`, | |||
method: 'get', | |||
params, | |||
}); | |||
}; | |||
/* 算力资源 */ | |||
// 查询卡类型数据 | |||
export const getAccCardList = () => { | |||
return service({ | |||
url: `/api/v1/resources/acc_card/list`, | |||
method: 'get', | |||
params: {} | |||
}); | |||
}; | |||
// 查询算力资源列表 | |||
// params-page,pageSize,resource-GPU|NPU...,accCardType-ASCEND910|...,accCardNum:-1|1|2|4|8...,excludeAccCardNums-"1|2|4|8",centerCode,minPrice,maxPrice-积分值,未填请传-1 | |||
export const getResourceList = (params) => { | |||
return service({ | |||
url: `/explore/card_request/resource/list`, | |||
method: 'get', | |||
params: { ...params }, | |||
paramsSerializer: _params => Qs.stringify(_params, { arrayFormat: 'repeat' }), | |||
}); | |||
}; | |||
/* 算力需求 */ | |||
// 获取创建算力计算资源和卡类型信息 | |||
export const getDemandCreationRequired = (params) => { | |||
return service({ | |||
@@ -143,6 +143,8 @@ const en = { | |||
resQueueCode: 'Resources Queue Code', | |||
resQueueName: 'Resources Queue Name', | |||
resQueueType: "Resources Queue Type", | |||
resQueueIsAvailable: "Resources Queue Is Available", | |||
resQueueIsAvailableAll: "Resources Queue Is Available(All)", | |||
allResQueueType: "All Resources Queue Type", | |||
whichCluster: 'Cluster', | |||
allCluster: 'All Clusters', | |||
@@ -142,6 +142,8 @@ const zh = { | |||
resQueueCode: "资源池(队列)编码", | |||
resQueueName: "资源池(队列)名称", | |||
resQueueType: "资源池(队列)类型", | |||
resQueueIsAvailable: "资源池(队列)是否可用", | |||
resQueueIsAvailableAll: "资源池(队列)是否可用(全部)", | |||
allResQueueType: "全部资源池(队列)类型", | |||
whichCluster: "所属集群", | |||
allCluster: "全部集群", | |||
@@ -15,7 +15,8 @@ | |||
</el-select> | |||
</el-form-item> | |||
<el-form-item label="卡数(卡)" prop="acc_cards_num"> | |||
<el-input :disabled="disabledEdit" v-model="form.acc_cards_num" placeholder="请输入卡数,数值(4)或范围(8-16)"></el-input> | |||
<el-input :disabled="disabledEdit" ref="accCardsNumRef" v-model="form.acc_cards_num" | |||
placeholder="请输入卡数,例如数值(4)或者范围(8-16)"></el-input> | |||
</el-form-item> | |||
<el-form-item label="存储容量(GB)" prop="disk_capacity"> | |||
<el-input :disabled="disabledEdit" v-model.number="form.disk_capacity" placeholder="请输入存储容量"></el-input> | |||
@@ -33,6 +34,9 @@ | |||
<el-form-item label="联系人姓名" prop="contact"> | |||
<el-input :disabled="disabledEdit" v-model="form.contact" placeholder="请输入" maxlength="255"></el-input> | |||
</el-form-item> | |||
<el-form-item label="微信" prop="wechat"> | |||
<el-input :disabled="disabledEdit" v-model="form.wechat" placeholder="请输入" maxlength="127"></el-input> | |||
</el-form-item> | |||
<el-form-item label="电话" prop="phone_number"> | |||
<el-input :disabled="disabledEdit" v-model="form.phone_number" placeholder="请输入" maxlength="255"></el-input> | |||
</el-form-item> | |||
@@ -69,6 +73,9 @@ | |||
<script> | |||
import { getDemandCreationRequired, postDemand, updateDemand } from '~/apis/modules/computingpower'; | |||
import { formatDate } from 'element-ui/lib/utils/date-util'; | |||
import { ACC_CARD_TYPE } from '~/const'; | |||
import { getListValueWithKey } from '~/utils'; | |||
export default { | |||
name: "DemandForm", | |||
props: { | |||
@@ -85,6 +92,7 @@ export default { | |||
resource_type: '', | |||
use_time: '', | |||
contact: '', | |||
wechat: '', | |||
phone_number: '', | |||
email_address: '', | |||
org: '', | |||
@@ -135,6 +143,7 @@ export default { | |||
resource_type: [{ required: true, message: ' ' }], | |||
use_time: [{ required: true, message: ' ' }], | |||
contact: [{ required: true, message: ' ' }], | |||
wechat: [{ required: true, message: ' ' }], | |||
phone_number: [ | |||
{ required: true, message: ' ' }, | |||
{ | |||
@@ -191,7 +200,7 @@ export default { | |||
this.cardTypeList = []; | |||
}, | |||
changeComputeResource() { | |||
this.cardTypeList = this.computeResourceCardTypeMap[this.form.compute_resource].map(itm => ({ k: itm, v: itm })); | |||
this.cardTypeList = this.computeResourceCardTypeMap[this.form.compute_resource].map(itm => ({ k: itm, v: getListValueWithKey(ACC_CARD_TYPE, itm) })); | |||
this.form.card_type = this.cardTypeList.length ? this.cardTypeList[0].k : ''; | |||
}, | |||
initEdit() { | |||
@@ -203,6 +212,22 @@ export default { | |||
this.changeComputeResource(); | |||
this.form.card_type = this.data['card_type']; | |||
}, | |||
initApply(data) { | |||
this.form.compute_resource = ''; | |||
this.form.card_type = ''; | |||
this.cardTypeList = []; | |||
this.form.acc_cards_num = ''; | |||
const computeResource = data.ComputeResource.indexOf('-GPGPU') >= 0 ? 'GPGPU' : data.ComputeResource; | |||
if (this.computeResourceList.find(item => item.k == computeResource)) { | |||
this.form.compute_resource = computeResource; | |||
this.changeComputeResource(); | |||
} | |||
if (this.cardTypeList.find(item => item.k == data.AccCardType)) { | |||
this.form.card_type = data.AccCardType; | |||
} | |||
this.form.acc_cards_num = data.AccCardsNum.toString(); | |||
this.$refs['accCardsNumRef'].focus(); | |||
}, | |||
onSubmit() { | |||
if (this.submitLoading) return; | |||
for (let key in this.form) { | |||
@@ -0,0 +1,560 @@ | |||
<template> | |||
<div class="resources-c"> | |||
<div class="conds-c"> | |||
<div class="conds-item"> | |||
<div class="conds-item-tit">计算资源:</div> | |||
<div class="conds-item-content"> | |||
<div class="sel-item" :class="item.k == conds.compute_resource ? 'active' : ''" | |||
v-for="(item, index) in computeResourceList" :key="index" @click="changeConds(item.k, 'compute_resource')"> | |||
{{ item.v }} | |||
</div> | |||
</div> | |||
</div> | |||
<div class="conds-item"> | |||
<div class="conds-item-tit">卡类型:</div> | |||
<div class="conds-item-content"> | |||
<div class="sel-item" :class="item.k == conds.card_type ? 'active' : ''" v-for="(item, index) in cardTypeList" | |||
:key="index" @click="changeConds(item.k, 'card_type')"> | |||
{{ item.v }} | |||
</div> | |||
</div> | |||
</div> | |||
<div class="conds-item"> | |||
<div class="conds-item-tit">卡数:</div> | |||
<div class="conds-item-content"> | |||
<div class="sel-item" :class="item.k == conds.acc_cards_num ? 'active' : ''" | |||
v-for="(item, index) in cardNumList" :key="index" @click="changeConds(item.k, 'acc_cards_num')"> | |||
{{ item.v }} | |||
</div> | |||
</div> | |||
</div> | |||
<div class="conds-item"> | |||
<div class="conds-item-tit">算力中心:</div> | |||
<div class="conds-item-content"> | |||
<div class="sel-item" :class="item.k == conds.ai_center ? 'active' : ''" v-for="(item, index) in aiCenterList" | |||
:key="index" @click="changeConds(item.k, 'ai_center')"> | |||
{{ item.v }} | |||
</div> | |||
</div> | |||
</div> | |||
<div class="conds-item"> | |||
<div class="conds-item-tit">价格区间:</div> | |||
<div class="conds-item-content"> | |||
<el-input class="price-s" v-model="conds.price_start" @input="inputPrice('price_start')" | |||
@blur="checkPrice('price_start')"></el-input><span class="to">至</span><el-input v-model="conds.price_end" | |||
@input="inputPrice('price_end')" @blur="checkPrice('price_end')" class="price-e"></el-input><span | |||
class="unit">积分/卡时</span> | |||
<el-button type="primary" size="mini" v-if="conds.price_start != '' || conds.price_end != ''" | |||
@click="clearPriceConds">清除</el-button> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="content-c"> | |||
<div class="list-c" v-loading="loading"> | |||
<div class="list-item" v-for="(item, index) in list" :key="index"> | |||
<div class="top"> | |||
<div class="left"> | |||
<div class="title"> | |||
<div class="name">{{ item.AccCardTypeShow || item.AccCardType }}</div> | |||
<div v-if="!item.IsExclusive" class="type">共享池</div> | |||
<div v-if="item.IsExclusive" class="type exclusive">专属池</div> | |||
</div> | |||
<div class="attributes"> | |||
<div class="attribute"> | |||
<span class="tit">{{ item.ComputeResource }}:</span><span class="val">{{ item.AccCardsNum }} * {{ | |||
item.AccCardTypeShow || item.AccCardType }} | |||
</span> | |||
</div> | |||
<div class="attribute" v-if="item.CpuCores"> | |||
<span class="tit">CPU:</span><span class="val">{{ item.CpuCores }}</span> | |||
</div> | |||
<div class="attribute" v-if="item.GPUMemGiB"> | |||
<span class="tit">显存:</span><span class="val">{{ item.GPUMemGiB }}GB</span> | |||
</div> | |||
<div class="attribute" v-if="item.MemGiB"> | |||
<span class="tit">内存:</span><span class="val">{{ item.MemGiB }}GB</span> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="right"> | |||
<span class="price">{{ item.UnitPrice }}</span> 积分/卡时 | |||
</div> | |||
</div> | |||
<div class="bottom"> | |||
<div class="left"> | |||
<div class="ai-center" v-for="(center) in item.AICenterList" :key="center.AiCenterCode"> | |||
{{ center.AiCenterName }} | |||
</div> | |||
</div> | |||
<div class="right"> | |||
<div class="apply" | |||
v-if="item.IsExclusive || (item.IsExclusive == false && item.IsSpecExclusive == 'exclusive')" | |||
@click="applyUse(item)">需申请使用</div> | |||
<div class="available" v-else>可直接使用</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="demand-item no-data" v-if="(!list.length && !loading)"> | |||
<div class="item-empty"> | |||
<div class="item-empty-icon"></div> | |||
<div class="item-empty-tips">{{ $t('modelObj.model_square_empty') }}</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="pagination-c"> | |||
<el-pagination background layout="total, sizes, prev, pager, next, jumper" :current-page.sync="conds.page" | |||
:page-size.sync="conds.page_size" :page-sizes="paginationInfo.pageSizes" :total="paginationInfo.total" | |||
@current-change="currentChange" @size-change="sizeChange"> | |||
</el-pagination> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import { getAccCardList, getAvailableAiCenterList, getResourceList } from '~/apis/modules/computingpower'; | |||
import { ACC_CARD_TYPE } from '~/const'; | |||
import { getListValueWithKey } from '~/utils'; | |||
export default { | |||
name: "Resources", | |||
props: { | |||
condtions: { type: Object, default: () => ({}) }, | |||
active: { type: Boolean, defalut: false }, | |||
}, | |||
data() { | |||
return { | |||
computeResourceList: [{ k: '', v: '全部' }], | |||
cardTypeList: [{ k: '', v: '全部' }], | |||
cardNumList: [{ k: '', v: '全部' }, ...[1, 2, 4, 8].map(itm => ({ k: itm, v: itm })), { k: 9999, v: '其它' }], | |||
aiCenterList: [{ k: '', v: '全部' }], | |||
computeResourceMap: {}, | |||
cardTypeMap: {}, | |||
conds: { | |||
compute_resource: '', | |||
card_type: '', | |||
acc_cards_num: '', | |||
ai_center: '', | |||
price_start: '', | |||
price_end: '', | |||
page: 1, | |||
page_size: 15, | |||
}, | |||
_price_start: '', | |||
_price_end: '', | |||
list: [1, 2, 3, 4, 5, 6], | |||
paginationInfo: { | |||
pageSizes: [15, 30, 50], | |||
total: 0, | |||
}, | |||
loading: false, | |||
}; | |||
}, | |||
computed: {}, | |||
watch: { | |||
active: { | |||
handler(newValue, oValue) { | |||
if (newValue) { | |||
this.search(); | |||
} | |||
} | |||
} | |||
}, | |||
methods: { | |||
changeConds(value, type) { | |||
if (type == 'compute_resource') { | |||
this.cardTypeList.splice(1, Infinity); | |||
for (let key in this.cardTypeMap) { | |||
if (value && value != key) continue; | |||
this.cardTypeMap[key].forEach(item => { | |||
this.cardTypeList.push({ | |||
k: item, | |||
v: getListValueWithKey(ACC_CARD_TYPE, item), | |||
}); | |||
}) | |||
} | |||
this.conds['card_type'] = ''; | |||
} | |||
this.conds[type] = value; | |||
this.conds.page = 1; | |||
this.search(); | |||
}, | |||
inputPrice(type) { | |||
if (!Number.isInteger(Number(this.conds[type])) || this.conds[type].length > 3) { | |||
this.conds[type] = this.conds[type].slice(0, this.conds[type].length - 1); | |||
} | |||
}, | |||
checkPrice(type) { | |||
if (this.conds.price_start && this.conds.price_end && Number(this.conds.price_start) > Number(this.conds.price_end)) { | |||
this.conds[type] = ''; | |||
} | |||
if (this._price_start != this.conds.price_start || this._price_end != this.conds.price_end) { | |||
this.conds.page = 1; | |||
this.search(); | |||
} | |||
this._price_start = this.conds.price_start; | |||
this._price_end = this.conds.price_end; | |||
}, | |||
clearPriceConds() { | |||
this._price_start = this.conds.price_start = ''; | |||
this._price_end = this.conds.price_end = ''; | |||
this.conds.page = 1; | |||
this.search(); | |||
}, | |||
currentChange(page) { | |||
this.conds.page = page; | |||
this.search(); | |||
}, | |||
sizeChange(pageSize) { | |||
this.conds.page_size = pageSize; | |||
this.search(); | |||
}, | |||
search() { | |||
const params = { | |||
page: this.conds.page, | |||
pageSize: this.conds.page_size, | |||
resource: this.conds.compute_resource === '' ? '' : this.computeResourceMap[this.conds.compute_resource] || [this.conds.compute_resource], | |||
accCardType: this.conds.card_type, | |||
accCardNum: this.conds.acc_cards_num === '' ? -1 : Number(this.conds.acc_cards_num), | |||
excludeAccCardNums: this.conds.acc_cards_num == 9999 ? this.cardNumList.slice(1, this.cardNumList.length - 1).map(itm => itm.k).join('|') : undefined, | |||
centerCode: this.conds.ai_center, | |||
minPrice: this.conds.price_start === '' ? -1 : Number(this.conds.price_start), | |||
maxPrice: this.conds.price_end === '' ? -1 : Number(this.conds.price_end), | |||
}; | |||
// console.log('search conds', this.conds); | |||
// console.log('search params', params); | |||
this.loading = true; | |||
getResourceList(params).then(res => { | |||
this.loading = false; | |||
res = res.data; | |||
if (res.code == 0) { | |||
const data = res.data || {}; | |||
this.paginationInfo.total = data.total; | |||
this.list = (data.list || []).map(item => { | |||
return { | |||
AccCardTypeShow: getListValueWithKey(ACC_CARD_TYPE, item.AccCardType), | |||
...item, | |||
} | |||
}); | |||
} | |||
}).catch(err => { | |||
this.loading = false; | |||
console.log(err); | |||
}); | |||
}, | |||
applyUse(data) { | |||
this.$emit('apply', data); | |||
}, | |||
setConds() { | |||
for (let key in this.conds) { | |||
if (this.condtions[key]) { | |||
this.conds[key] = this.condtions[key]; | |||
} | |||
} | |||
this._price_start = this.conds.price_start || ''; | |||
this._price_end = this.conds.price_end || ''; | |||
} | |||
}, | |||
created() { | |||
// this.setConds(); | |||
getAccCardList().then(res => { | |||
res = res.data; | |||
if (res.code == 0) { | |||
this.computeResourceList.splice(1, Infinity); | |||
this.cardTypeList.splice(1, Infinity); | |||
const data = res.data.list || []; | |||
for (let i = 0, iLen = data.length; i < iLen; i++) { | |||
const item = data[i]; | |||
const computeSource = item.ComputeSource; | |||
const cardList = item.CardList; | |||
const computeSourceKey = computeSource.indexOf('-GPGPU') > 0 ? 'GPGPU' : computeSource; | |||
if (this.computeResourceMap[computeSourceKey]) { | |||
this.computeResourceMap[computeSourceKey].push(computeSource); | |||
} else { | |||
this.computeResourceMap[computeSourceKey] = [computeSource]; | |||
} | |||
if (this.cardTypeMap[computeSourceKey]) { | |||
this.cardTypeMap[computeSourceKey].push(...cardList); | |||
} else { | |||
this.cardTypeMap[computeSourceKey] = cardList; | |||
} | |||
} | |||
for (let key in this.computeResourceMap) { | |||
this.computeResourceMap[key] = Array.from(new Set(this.computeResourceMap[key])); | |||
this.computeResourceList.push({ | |||
k: key, | |||
v: key, | |||
}); | |||
} | |||
for (let key in this.cardTypeMap) { | |||
this.cardTypeMap[key] = Array.from(new Set(this.cardTypeMap[key])); | |||
this.cardTypeMap[key].forEach(item => { | |||
this.cardTypeList.push({ | |||
k: item, | |||
v: getListValueWithKey(ACC_CARD_TYPE, item), | |||
}); | |||
}) | |||
} | |||
} | |||
}).catch(err => { | |||
console.log(err); | |||
}); | |||
getAvailableAiCenterList().then(res => { | |||
res = res.data; | |||
if (res.code == 0) { | |||
this.aiCenterList.splice(1, Infinity); | |||
const data = res?.data?.list || []; | |||
for (let i = 0, iLen = data.length; i < iLen; i++) { | |||
const item = data[i]; | |||
this.aiCenterList.push({ | |||
k: item.AiCenterCode, | |||
v: item.AiCenterName, | |||
}); | |||
} | |||
} | |||
}).catch(err => { | |||
console.log(err); | |||
}); | |||
}, | |||
mounted() { | |||
this.search(); | |||
}, | |||
}; | |||
</script> | |||
<style scoped lang="less"> | |||
.resources-c { | |||
margin-top: 20px; | |||
} | |||
.conds-c { | |||
.conds-item { | |||
display: flex; | |||
.conds-item-tit { | |||
width: 100px; | |||
display: flex; | |||
padding-top: 7px; | |||
justify-content: flex-end; | |||
padding-right: 10px; | |||
} | |||
.conds-item-content { | |||
display: flex; | |||
flex-wrap: wrap; | |||
width: 0; | |||
flex: 1; | |||
align-items: center; | |||
.sel-item { | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
height: 30px; | |||
border-radius: 4px; | |||
background-color: rgba(248, 249, 250, 1); | |||
color: rgba(65, 80, 88, 1); | |||
font-size: 12px; | |||
padding: 0 14px; | |||
cursor: pointer; | |||
margin-right: 12px; | |||
margin-bottom: 16px; | |||
&.active { | |||
background-color: rgba(3, 102, 214, 1); | |||
color: rgba(255, 255, 255, 1); | |||
} | |||
} | |||
.price-s, | |||
.price-e { | |||
width: 52px; | |||
/deep/.el-input__inner { | |||
text-align: center; | |||
padding: 0 8px; | |||
height: 30px; | |||
} | |||
} | |||
.to, | |||
.unit { | |||
margin: 0 10px; | |||
} | |||
} | |||
} | |||
} | |||
.content-c { | |||
margin-top: 20px; | |||
.list-c { | |||
.list-item { | |||
padding: 18px 22px; | |||
border-radius: 15px; | |||
background-color: rgba(255, 255, 255, 1); | |||
box-shadow: 0px 5px 10px 0px rgba(157, 197, 226, 0.2); | |||
border: 1px solid rgba(157, 197, 226, 0.4); | |||
margin-bottom: 20px; | |||
.top { | |||
display: flex; | |||
.left { | |||
width: 0; | |||
flex: 1; | |||
.title { | |||
display: flex; | |||
align-items: center; | |||
.name { | |||
color: rgba(16, 16, 16, 1); | |||
font-size: 16px; | |||
margin-right: 10px; | |||
font-weight: bold; | |||
} | |||
.type { | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
padding: 0 4px; | |||
height: 18px; | |||
border-radius: 2px; | |||
background-color: rgba(91, 185, 115, 1); | |||
color: rgba(251, 251, 251, 1); | |||
font-size: 12px; | |||
text-align: center; | |||
&.exclusive { | |||
background-color: rgba(50, 145, 248, 1); | |||
} | |||
} | |||
} | |||
.attributes { | |||
display: flex; | |||
align-items: center; | |||
margin-top: 13px; | |||
.attribute { | |||
margin-right: 16px; | |||
.tit { | |||
color: rgb(136, 136, 136); | |||
} | |||
} | |||
} | |||
} | |||
.right { | |||
width: 100px; | |||
padding-top: 14px; | |||
text-align: right; | |||
font-size: 14px; | |||
.price { | |||
color: rgba(16, 16, 16, 1); | |||
font-size: 20px; | |||
margin-right: 2px; | |||
} | |||
} | |||
} | |||
.bottom { | |||
border-top: 1px solid rgba(157, 197, 226, 0.2); | |||
margin-top: 14px; | |||
padding-top: 6px; | |||
display: flex; | |||
align-items: center; | |||
.left { | |||
width: 0; | |||
flex: 1; | |||
display: flex; | |||
flex-wrap: wrap; | |||
.ai-center { | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
padding: 0 12px; | |||
margin-right: 10px; | |||
margin-top: 10px; | |||
height: 30px; | |||
border-radius: 4px; | |||
background-color: rgba(50, 145, 248, 0.1); | |||
color: rgba(50, 145, 248, 1); | |||
font-size: 12px; | |||
text-align: center; | |||
border: 1px solid rgba(50, 145, 248, 0.6); | |||
} | |||
} | |||
.right { | |||
width: 100px; | |||
display: flex; | |||
align-items: center; | |||
justify-content: flex-end; | |||
.available { | |||
color: rgba(39, 177, 72, 1); | |||
font-size: 12px; | |||
} | |||
.apply { | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
height: 30px; | |||
padding: 0 12px; | |||
border-radius: 4px; | |||
color: rgba(50, 145, 248, 1); | |||
font-size: 12px; | |||
border: 1px solid rgba(50, 145, 248, 1); | |||
cursor: pointer; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
.no-data { | |||
display: flex; | |||
justify-content: center; | |||
padding: 0 0; | |||
width: 100%; | |||
.item-empty { | |||
height: 391px; | |||
width: 100%; | |||
overflow: hidden; | |||
padding: 15px; | |||
background: transparent; | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: center; | |||
background-color: rgba(245, 245, 246, 0.5); | |||
.item-empty-icon { | |||
height: 80px; | |||
width: 100%; | |||
background: url(/img/empty-box.svg) center center no-repeat; | |||
} | |||
.item-empty-tips { | |||
text-align: center; | |||
margin-top: 20px; | |||
font-size: 18px; | |||
color: rgb(63, 63, 64); | |||
} | |||
} | |||
} | |||
.pagination-c { | |||
text-align: center; | |||
margin: 10px 0; | |||
} | |||
</style> |
@@ -1,27 +1,33 @@ | |||
<template> | |||
<div class="ui container"> | |||
<div class="top-head"> | |||
<div class="title">算力需求</div> | |||
<div class="title">算力资源</div> | |||
<div class="descr">为了满足用户的个性化算力需求,启智社区可以根据用户的需求定制算力池,欢迎提交您的算力需求。</div> | |||
</div> | |||
<div class="main-content"> | |||
<div class="top-area"> | |||
<div class="tab-c"> | |||
<div class="tab-item" :class="activeTab == 0 ? 'active' : ''" @click="changeTab(0)">算力需求广场</div> | |||
<div class="tab-item" v-if="isLogin" :class="activeTab == 1 ? 'active' : ''" @click="changeTab(1)">我的需求</div> | |||
<div class="tab-item" :class="activeTab == 0 ? 'active' : ''" @click="changeTab(0)">算力资源</div> | |||
<div class="tab-item" :class="activeTab == 1 ? 'active' : ''" @click="changeTab(1)">算力需求广场</div> | |||
<div class="tab-item" v-if="isLogin" :class="activeTab == 2 ? 'active' : ''" @click="changeTab(2)">我的需求</div> | |||
</div> | |||
<div class="operate-c"> | |||
<el-button size="default" v-if="isOperator" type="primary" @click="goOperate">需求处理</el-button> | |||
</div> | |||
</div> | |||
<div class="middle-area"> | |||
<div class="left-area"> | |||
<div class="tab-content" v-if="activeTab == 0"> | |||
<div class="left-area" v-loading="loading"> | |||
<div class="tab-content" v-show="activeTab == 0"> | |||
<Resources :active="activeTab == 0" @apply="applyUse"> | |||
</Resources> | |||
</div> | |||
<div class="tab-content" v-if="activeTab == 1"> | |||
<div class="demand-item demand-item-all" v-for="(item, index) in dataAll" :key="index"> | |||
<div class="demand-item-top"> | |||
<div class="demand-item-line"> | |||
<div class="demand-item-line-block"><span>计算资源:</span><span>{{ item.compute_resource }}</span></div> | |||
<div class="demand-item-line-block"><span>卡类型:</span><span>{{ item.card_type }}</span></div> | |||
<div class="demand-item-line-block"><span>卡类型:</span><span>{{ item.card_type_show || item.card_type | |||
}}</span></div> | |||
<div class="demand-item-line-block"><span>卡数(卡):</span><span>{{ item.acc_cards_num }}</span></div> | |||
</div> | |||
<div class="demand-item-line"> | |||
@@ -54,12 +60,13 @@ | |||
</div> | |||
</div> | |||
</div> | |||
<div class="tab-content" v-if="activeTab == 1"> | |||
<div class="tab-content" v-if="activeTab == 2"> | |||
<div class="demand-item demand-item-my" v-for="(item, index) in dataMy" :key="index"> | |||
<div class="demand-item-top"> | |||
<div class="demand-item-line"> | |||
<div class="demand-item-line-block"><span>计算资源:</span><span>{{ item.compute_resource }}</span></div> | |||
<div class="demand-item-line-block"><span>卡类型:</span><span>{{ item.card_type }}</span></div> | |||
<div class="demand-item-line-block"><span>卡类型:</span><span>{{ item.card_type_show || item.card_type | |||
}}</span></div> | |||
<div class="demand-item-line-block"><span>卡数(卡):</span><span>{{ item.acc_cards_num }}</span></div> | |||
</div> | |||
<div class="demand-item-line"> | |||
@@ -106,7 +113,7 @@ | |||
</div> | |||
</div> | |||
</div> | |||
<div class="pagination-c"> | |||
<div class="pagination-c" v-if="activeTab != 0"> | |||
<el-pagination background layout="total, sizes, prev, pager, next, jumper" | |||
:current-page.sync="paginationInfo.page" :page-sizes="paginationInfo.pageSizes" | |||
:page-size.sync="paginationInfo.pageSize" :total="paginationInfo.total" @current-change="currentChange" | |||
@@ -125,12 +132,15 @@ | |||
</template> | |||
<script> | |||
import Resources from '../components/Resources.vue'; | |||
import DemandForm from '../components/DemandForm.vue'; | |||
import DemandEditDialog from '../components/DemandEditDialog.vue'; | |||
import { getDemandList, getDemandMyList } from '~/apis/modules/computingpower'; | |||
import dayjs from 'dayjs'; | |||
import { lang } from '~/langs'; | |||
import { timeSinceUnix } from '~/utils'; | |||
import { ACC_CARD_TYPE } from '~/const'; | |||
import { getListValueWithKey } from '~/utils'; | |||
export default { | |||
data() { | |||
@@ -149,7 +159,7 @@ export default { | |||
}, | |||
}; | |||
}, | |||
components: { DemandForm, DemandEditDialog }, | |||
components: { Resources, DemandForm, DemandEditDialog }, | |||
methods: { | |||
changeTab(tab) { | |||
if (tab == this.activeTab) return; | |||
@@ -158,7 +168,7 @@ export default { | |||
this.paginationInfo.total = 0; | |||
this.getData(); | |||
this.$nextTick(() => { | |||
this.$refs['demandFormRef'].resetForm(); | |||
this.$refs['demandFormRef']?.resetForm(); | |||
}); | |||
}, | |||
getData() { | |||
@@ -166,7 +176,8 @@ export default { | |||
pageSize: this.paginationInfo.pageSize, | |||
page: this.paginationInfo.page, | |||
} | |||
const subApi = this.activeTab == 0 ? getDemandList : getDemandMyList; | |||
const subApi = this.activeTab == 1 ? getDemandList : this.activeTab == 2 ? getDemandMyList : ''; | |||
if (!subApi) return; | |||
this.loading = true; | |||
subApi(params).then(res => { | |||
this.loading = false; | |||
@@ -174,10 +185,16 @@ export default { | |||
if (res.code == 0) { | |||
const data = res.data; | |||
this.paginationInfo.total = data.total; | |||
if (this.activeTab == 0) { | |||
this.dataAll = data.cardRequestList || []; | |||
} else { | |||
this.dataMy = data.cardRequestList || []; | |||
const cardRequestList = (data.cardRequestList || []).map(item => { | |||
return { | |||
...item, | |||
card_type_show: getListValueWithKey(ACC_CARD_TYPE, item.card_type), | |||
} | |||
}) | |||
if (this.activeTab == 1) { | |||
this.dataAll = cardRequestList; | |||
} else if (this.activeTab == 2) { | |||
this.dataMy = cardRequestList; | |||
} | |||
} | |||
}).catch(err => { | |||
@@ -193,7 +210,7 @@ export default { | |||
this.getData(); | |||
}, | |||
sizeChange(pageSize) { | |||
this.pageSize = pageSize; | |||
this.paginationInfo.pageSize = pageSize; | |||
this.getData(); | |||
}, | |||
calcFromNow(unix) { | |||
@@ -214,6 +231,15 @@ export default { | |||
this.getData(); | |||
}, | |||
demandUpdateError() { }, | |||
applyUse(data) { | |||
if (!this.isLogin) { | |||
window.location.href = `/user/login?redirect_to=${encodeURIComponent(window.location.href)}`; | |||
return; | |||
} | |||
this.$nextTick(() => { | |||
this.$refs['demandFormRef']?.initApply(data); | |||
}); | |||
}, | |||
}, | |||
created() { | |||
this.getData(); | |||
@@ -306,6 +332,8 @@ export default { | |||
padding-top: 22px; | |||
.form-container { | |||
top: 10px; | |||
position: sticky; | |||
border: 1px solid rgb(229, 231, 235); | |||
background: rgb(249, 250, 251); | |||
border-radius: 10px; | |||
@@ -91,6 +91,16 @@ | |||
</el-select> | |||
</div> | |||
</div> | |||
<div class="form-row"> | |||
<div class="title required"> | |||
<span>{{ $t('resourcesManagement.resQueueIsAvailable') }}</span> | |||
</div> | |||
<div class="content"> | |||
<el-select v-model="dataInfo.IsAvailable"> | |||
<el-option v-for="item in isAvailableList" :key="item.k" :label="item.v" :value="item.k" /> | |||
</el-select> | |||
</div> | |||
</div> | |||
<div class="form-row" style="margin-top: 10px"> | |||
<div class="title"><span>{{ $t('resourcesManagement.remark') }}</span></div> | |||
<div class="content" style="width: 400px"> | |||
@@ -111,6 +121,7 @@ | |||
</BaseDialog> | |||
</div> | |||
</template> | |||
<script> | |||
import BaseDialog from '~/components/BaseDialog.vue'; | |||
import { addResQueue, updateResQueue } from '~/apis/modules/resources'; | |||
@@ -136,6 +147,7 @@ export default { | |||
computingTypeList: [...COMPUTER_RESOURCES], | |||
cardTypeList: [...ACC_CARD_TYPE], | |||
networkTypeList: [...NETWORK_TYPE_VALUE], | |||
isAvailableList: [{ k: 1, v: this.$t('resourcesManagement.notAvailable') }, { k: 2, v: this.$t('resourcesManagement.available') }], | |||
dataInfo: {}, | |||
}; | |||
}, | |||
@@ -157,6 +169,7 @@ export default { | |||
AccCardType: '', | |||
CardsTotalNum: '', | |||
HasInternet: '', | |||
IsAvailable: '', | |||
Remark: '', | |||
} | |||
}, | |||
@@ -166,6 +179,7 @@ export default { | |||
// | |||
} else if (this.type === 'edit') { | |||
this.dataInfo = Object.assign(this.dataInfo, { ...this.data }); | |||
this.dataInfo.IsAvailable = this.data.IsAvailable ? 2 : 1; | |||
} | |||
this.$emit("open"); | |||
}, | |||
@@ -181,7 +195,7 @@ export default { | |||
}, | |||
confirm() { | |||
if (!this.dataInfo.QueueCode || !this.dataInfo.Cluster || !this.dataInfo.AiCenterCode || !this.dataInfo.ComputeResource | |||
|| !this.dataInfo.AccCardType || !this.dataInfo.CardsTotalNum || this.dataInfo.HasInternet === '') { | |||
|| !this.dataInfo.AccCardType || !this.dataInfo.CardsTotalNum || this.dataInfo.HasInternet === '' || this.dataInfo.IsAvailable === '') { | |||
this.$message({ | |||
type: 'info', | |||
message: this.$t('pleaseCompleteTheInformationFirst'), | |||
@@ -228,6 +242,7 @@ export default { | |||
}, | |||
}; | |||
</script> | |||
<style scoped lang="less"> | |||
.dlg-content { | |||
margin: 20px 0 25px 0; | |||
@@ -24,8 +24,11 @@ | |||
<el-select class="select" size="medium" v-model="selNetworkType" @change="selectChange"> | |||
<el-option v-for="item in networkTypeList" :key="item.k" :label="item.v" :value="item.k" /> | |||
</el-select> | |||
<el-select class="select" size="medium" v-model="selIsAvailable" @change="selectChange"> | |||
<el-option v-for="item in isAvailableList" :key="item.k" :label="item.v" :value="item.k" /> | |||
</el-select> | |||
</div> | |||
<div class="right"> | |||
<div class="tools-bar-btn-c"> | |||
<el-button size="medium" icon="el-icon-refresh" @click="syncComputerNetwork" v-loading="syncLoading"> | |||
{{ $t('resourcesManagement.syncAiNetwork') }}</el-button> | |||
<el-button type="primary" icon="el-icon-plus" size="medium" @click="showDialog('add')"> | |||
@@ -56,6 +59,7 @@ | |||
</el-table-column> | |||
<el-table-column prop="ClusterName" :label="$t('resourcesManagement.whichCluster')" align="center" | |||
header-align="center"> | |||
<template slot-scope="scope"> | |||
<span :title="scope.row.Cluster">{{ scope.row.ClusterName }}</span> | |||
</template> | |||
@@ -73,12 +77,22 @@ | |||
header-align="center"></el-table-column> | |||
<el-table-column prop="HasInternetStr" :label="$t('cloudbrainObj.networkType')" align="center" | |||
header-align="center"></el-table-column> | |||
<el-table-column prop="IsAvailableStr" :label="$t('resourcesManagement.resQueueIsAvailable')" align="center" | |||
header-align="center"> | |||
<template slot-scope="scope"> | |||
<span :style="{ color: scope.row.IsAvailable ? 'rgb(82, 196, 26)' : 'rgb(245, 34, 45)' }">{{ | |||
scope.row.IsAvailableStr | |||
}}</span> | |||
</template> | |||
</el-table-column> | |||
<el-table-column prop="UpdatedTimeStr" :label="$t('resourcesManagement.lastUpdateTime')" align="center" | |||
header-align="center"></el-table-column> | |||
<el-table-column prop="Remark" :label="$t('resourcesManagement.remark')" align="left" header-align="center" | |||
min-width="160"> | |||
</el-table-column> | |||
<el-table-column :label="$t('operation')" align="center" header-align="center" width="80"> | |||
<template slot-scope="scope"> | |||
<span v-if="scope.row.Cluster !== 'C2Net'" class="op-btn" @click="showDialog('edit', scope.row)">{{ | |||
$t('edit') | |||
@@ -88,6 +102,7 @@ | |||
}}</span> | |||
</template> | |||
</el-table-column> | |||
<template slot="empty"> | |||
<span style="font-size: 12px">{{ | |||
loading ? $t('loading') : $t('noData') | |||
@@ -135,6 +150,8 @@ export default { | |||
cardTypeList: [{ k: '', v: this.$t('resourcesManagement.allAccCardType') }, ...ACC_CARD_TYPE], | |||
selNetworkType: 0, | |||
networkTypeList: [{ k: 0, v: this.$t('resourcesManagement.allNetworkType') }, ...NETWORK_TYPE], | |||
selIsAvailable: 0, | |||
isAvailableList: [{ k: 0, v: this.$t('resourcesManagement.resQueueIsAvailableAll') }, { k: 1, v: this.$t('resourcesManagement.notAvailable') }, { k: 2, v: this.$t('resourcesManagement.available') }], | |||
syncLoading: false, | |||
loading: false, | |||
tableData: [], | |||
@@ -177,6 +194,7 @@ export default { | |||
resource: this.selComputingType, | |||
card: this.selCardType, | |||
hasInternet: this.selNetworkType, | |||
isAvailable: this.selIsAvailable, | |||
page: this.pageInfo.curpage, | |||
pageSize: this.pageInfo.pageSize, | |||
}; | |||
@@ -195,6 +213,7 @@ export default { | |||
ComputeResourceName: getListValueWithKey(this.computingTypeList, item.ComputeResource), | |||
AccCardTypeName: getListValueWithKey(this.cardTypeList, item.AccCardType), | |||
HasInternetStr: getListValueWithKey(NETWORK_TYPE_VALUE, item.HasInternet), | |||
IsAvailableStr: item.IsAvailable ? this.$t('resourcesManagement.available') : this.$t('resourcesManagement.notAvailable'), | |||
UpdatedTimeStr: formatDate(new Date(item.UpdatedTime * 1000), 'yyyy-MM-dd HH:mm:ss'), | |||
} | |||
}); | |||
@@ -294,7 +313,7 @@ export default { | |||
} | |||
} | |||
.right { | |||
.tools-bar-btn-c { | |||
display: flex; | |||
} | |||
} | |||
Dear OpenI User
Thank you for your continuous support to the Openl Qizhi Community AI Collaboration Platform. In order to protect your usage rights and ensure network security, we updated the Openl Qizhi Community AI Collaboration Platform Usage Agreement in January 2024. The updated agreement specifies that users are prohibited from using intranet penetration tools. After you click "Agree and continue", you can continue to use our services. Thank you for your cooperation and understanding.
For more agreement content, please refer to the《Openl Qizhi Community AI Collaboration Platform Usage Agreement》