Reviewed-on: https://git.openi.org.cn/OpenI/aiforge/pulls/2480 Reviewed-by: lewis <747342561@qq.com>fix-2452
@@ -2,6 +2,7 @@ package models | |||||
import ( | import ( | ||||
"fmt" | "fmt" | ||||
"time" | |||||
"code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
@@ -39,6 +40,40 @@ type AiModelManage struct { | |||||
IsCanDelete bool | IsCanDelete bool | ||||
} | } | ||||
type AiModelConvert struct { | |||||
ID string `xorm:"pk"` | |||||
Name string `xorm:"INDEX NOT NULL"` | |||||
Status string `xorm:"NULL"` | |||||
StatusResult string `xorm:"NULL"` | |||||
SrcEngine int `xorm:"NOT NULL DEFAULT 0"` | |||||
RepoId int64 `xorm:"INDEX NULL"` | |||||
ModelId string `xorm:"NOT NULL"` | |||||
ModelName string `xorm:"NULL"` | |||||
ModelVersion string `xorm:"NOT NULL"` | |||||
ModelPath string `xorm:"NULL"` | |||||
DestFormat int `xorm:"NOT NULL DEFAULT 0"` | |||||
NetOutputFormat int `xorm:"NULL"` | |||||
UserId int64 `xorm:"NOT NULL"` | |||||
CloudBrainTaskId string `xorm:"NULL"` | |||||
ModelArtsVersionId string `xorm:"NULL"` | |||||
ContainerID string | |||||
ContainerIp string | |||||
RunTime int64 `xorm:"NULL"` | |||||
TrainJobDuration string | |||||
InputShape string `xorm:"varchar(2000)"` | |||||
InputDataFormat string `xorm:"NOT NULL"` | |||||
Description string `xorm:"varchar(2000)"` | |||||
Path string `xorm:"varchar(400) NOT NULL"` | |||||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||||
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` | |||||
StartTime timeutil.TimeStamp | |||||
EndTime timeutil.TimeStamp | |||||
UserName string | |||||
UserRelAvatarLink string | |||||
IsCanOper bool | |||||
IsCanDelete bool | |||||
} | |||||
type AiModelQueryOptions struct { | type AiModelQueryOptions struct { | ||||
ListOptions | ListOptions | ||||
RepoID int64 // include all repos if empty | RepoID int64 // include all repos if empty | ||||
@@ -47,7 +82,124 @@ type AiModelQueryOptions struct { | |||||
SortType string | SortType string | ||||
New int | New int | ||||
// JobStatus CloudbrainStatus | // JobStatus CloudbrainStatus | ||||
Type int | |||||
Type int | |||||
Status int | |||||
} | |||||
func (a *AiModelConvert) IsGpuTrainTask() bool { | |||||
if a.SrcEngine == 0 || a.SrcEngine == 1 { | |||||
return true | |||||
} | |||||
return false | |||||
} | |||||
func ModelComputeAndSetDuration(task *AiModelConvert, result JobResultPayload) { | |||||
if task.StartTime == 0 { | |||||
task.StartTime = timeutil.TimeStamp(result.JobStatus.CreatedTime / 1000) | |||||
} | |||||
if task.EndTime == 0 { | |||||
if result.JobStatus.CompletedTime > 0 { | |||||
task.EndTime = timeutil.TimeStamp(result.JobStatus.CompletedTime / 1000) | |||||
} | |||||
} | |||||
var d int64 | |||||
if task.StartTime == 0 { | |||||
d = 0 | |||||
} else if task.EndTime == 0 { | |||||
d = time.Now().Unix() - task.StartTime.AsTime().Unix() | |||||
} else { | |||||
d = task.EndTime.AsTime().Unix() - task.StartTime.AsTime().Unix() | |||||
} | |||||
if d < 0 { | |||||
d = 0 | |||||
} | |||||
task.RunTime = d | |||||
task.TrainJobDuration = ConvertDurationToStr(d) | |||||
} | |||||
func ModelConvertSetDuration(task *AiModelConvert) { | |||||
var d int64 | |||||
if task.StartTime == 0 { | |||||
d = 0 | |||||
} else if task.EndTime == 0 { | |||||
d = time.Now().Unix() - task.StartTime.AsTime().Unix() | |||||
} else { | |||||
d = task.EndTime.AsTime().Unix() - task.StartTime.AsTime().Unix() | |||||
} | |||||
if d < 0 { | |||||
d = 0 | |||||
} | |||||
task.RunTime = d | |||||
task.TrainJobDuration = ConvertDurationToStr(d) | |||||
} | |||||
func UpdateModelConvertModelArts(id string, CloudBrainTaskId string, VersionId string) error { | |||||
var sess *xorm.Session | |||||
sess = x.ID(id) | |||||
defer sess.Close() | |||||
re, err := sess.Cols("cloud_brain_task_id,model_arts_version_id").Update(&AiModelConvert{ | |||||
CloudBrainTaskId: CloudBrainTaskId, | |||||
ModelArtsVersionId: VersionId, | |||||
}) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
log.Info("success to update cloud_brain_task_id from db.re=" + fmt.Sprint((re))) | |||||
return nil | |||||
} | |||||
func UpdateModelConvertFailed(id string, status string, statusResult string) error { | |||||
var sess *xorm.Session | |||||
sess = x.ID(id) | |||||
defer sess.Close() | |||||
re, err := sess.Cols("status", "status_result").Update(&AiModelConvert{ | |||||
Status: status, | |||||
StatusResult: statusResult, | |||||
}) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
log.Info("success to update cloud_brain_task_id from db.re=" + fmt.Sprint((re))) | |||||
return nil | |||||
} | |||||
func UpdateModelConvertCBTI(id string, CloudBrainTaskId string) error { | |||||
var sess *xorm.Session | |||||
sess = x.ID(id) | |||||
defer sess.Close() | |||||
re, err := sess.Cols("cloud_brain_task_id").Update(&AiModelConvert{ | |||||
CloudBrainTaskId: CloudBrainTaskId, | |||||
}) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
log.Info("success to update cloud_brain_task_id from db.re=" + fmt.Sprint((re))) | |||||
return nil | |||||
} | |||||
func UpdateModelConvert(job *AiModelConvert) error { | |||||
return updateModelConvert(x, job) | |||||
} | |||||
func updateModelConvert(e Engine, job *AiModelConvert) error { | |||||
var sess *xorm.Session | |||||
sess = e.Where("id = ?", job.ID) | |||||
_, err := sess.Cols("status", "train_job_duration", "run_time", "start_time", "end_time", "updated_unix").Update(job) | |||||
return err | |||||
} | |||||
func SaveModelConvert(modelConvert *AiModelConvert) error { | |||||
sess := x.NewSession() | |||||
defer sess.Close() | |||||
re, err := sess.Insert(modelConvert) | |||||
if err != nil { | |||||
log.Info("insert modelConvert error." + err.Error()) | |||||
return err | |||||
} | |||||
log.Info("success to save modelConvert db.re=" + fmt.Sprint((re))) | |||||
return nil | |||||
} | } | ||||
func SaveModelToDb(model *AiModelManage) error { | func SaveModelToDb(model *AiModelManage) error { | ||||
@@ -63,6 +215,20 @@ func SaveModelToDb(model *AiModelManage) error { | |||||
return nil | return nil | ||||
} | } | ||||
func QueryModelConvertById(id string) (*AiModelConvert, error) { | |||||
sess := x.NewSession() | |||||
defer sess.Close() | |||||
sess.Select("*").Table(new(AiModelConvert)).Where("id='" + id + "'") | |||||
aiModelManageConvertList := make([]*AiModelConvert, 0) | |||||
err := sess.Find(&aiModelManageConvertList) | |||||
if err == nil { | |||||
if len(aiModelManageConvertList) == 1 { | |||||
return aiModelManageConvertList[0], nil | |||||
} | |||||
} | |||||
return nil, err | |||||
} | |||||
func QueryModelById(id string) (*AiModelManage, error) { | func QueryModelById(id string) (*AiModelManage, error) { | ||||
sess := x.NewSession() | sess := x.NewSession() | ||||
defer sess.Close() | defer sess.Close() | ||||
@@ -74,14 +240,28 @@ func QueryModelById(id string) (*AiModelManage, error) { | |||||
if len(aiModelManageList) == 1 { | if len(aiModelManageList) == 1 { | ||||
return aiModelManageList[0], nil | return aiModelManageList[0], nil | ||||
} | } | ||||
} else { | |||||
log.Info("error=" + err.Error()) | |||||
} | } | ||||
return nil, err | return nil, err | ||||
} | } | ||||
func DeleteModelById(id string) error { | |||||
func DeleteModelConvertById(id string) error { | |||||
sess := x.NewSession() | sess := x.NewSession() | ||||
defer sess.Close() | defer sess.Close() | ||||
re, err := sess.Delete(&AiModelConvert{ | |||||
ID: id, | |||||
}) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
log.Info("success to delete AiModelManageConvert from db.re=" + fmt.Sprint((re))) | |||||
return nil | |||||
} | |||||
func DeleteModelById(id string) error { | |||||
sess := x.NewSession() | |||||
defer sess.Close() | |||||
re, err := sess.Delete(&AiModelManage{ | re, err := sess.Delete(&AiModelManage{ | ||||
ID: id, | ID: id, | ||||
}) | }) | ||||
@@ -90,7 +270,6 @@ func DeleteModelById(id string) error { | |||||
} | } | ||||
log.Info("success to delete from db.re=" + fmt.Sprint((re))) | log.Info("success to delete from db.re=" + fmt.Sprint((re))) | ||||
return nil | return nil | ||||
} | } | ||||
func ModifyModelDescription(id string, description string) error { | func ModifyModelDescription(id string, description string) error { | ||||
@@ -201,3 +380,73 @@ func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) { | |||||
return aiModelManages, count, nil | return aiModelManages, count, nil | ||||
} | } | ||||
func QueryModelConvertByRepoID(repoId int64) ([]*AiModelConvert, error) { | |||||
sess := x.NewSession() | |||||
defer sess.Close() | |||||
var cond = builder.NewCond() | |||||
cond = cond.And( | |||||
builder.Eq{"ai_model_convert.repo_id": repoId}, | |||||
) | |||||
sess.OrderBy("ai_model_convert.created_unix DESC") | |||||
aiModelManageConvert := make([]*AiModelConvert, 0) | |||||
if err := sess.Table(new(AiModelConvert)).Where(cond). | |||||
Find(&aiModelManageConvert); err != nil { | |||||
return nil, fmt.Errorf("Find: %v", err) | |||||
} | |||||
return aiModelManageConvert, nil | |||||
} | |||||
func QueryModelConvertByUserID(userID int64) ([]*AiModelConvert, error) { | |||||
sess := x.NewSession() | |||||
defer sess.Close() | |||||
var cond = builder.NewCond() | |||||
cond = cond.And( | |||||
builder.Eq{"ai_model_convert.user_id": userID}, | |||||
) | |||||
sess.OrderBy("ai_model_convert.created_unix DESC") | |||||
aiModelManageConvert := make([]*AiModelConvert, 0) | |||||
if err := sess.Table(new(AiModelConvert)).Where(cond). | |||||
Find(&aiModelManageConvert); err != nil { | |||||
return nil, fmt.Errorf("Find: %v", err) | |||||
} | |||||
return aiModelManageConvert, nil | |||||
} | |||||
func QueryModelConvert(opts *AiModelQueryOptions) ([]*AiModelConvert, int64, error) { | |||||
sess := x.NewSession() | |||||
defer sess.Close() | |||||
var cond = builder.NewCond() | |||||
if opts.RepoID > 0 { | |||||
cond = cond.And( | |||||
builder.Eq{"ai_model_convert.repo_id": opts.RepoID}, | |||||
) | |||||
} | |||||
if opts.UserID > 0 { | |||||
cond = cond.And( | |||||
builder.Eq{"ai_model_convert.user_id": opts.UserID}, | |||||
) | |||||
} | |||||
count, err := sess.Where(cond).Count(new(AiModelConvert)) | |||||
if err != nil { | |||||
return nil, 0, fmt.Errorf("Count: %v", err) | |||||
} | |||||
if opts.Page >= 0 && opts.PageSize > 0 { | |||||
var start int | |||||
if opts.Page == 0 { | |||||
start = 0 | |||||
} else { | |||||
start = (opts.Page - 1) * opts.PageSize | |||||
} | |||||
sess.Limit(opts.PageSize, start) | |||||
} | |||||
sess.OrderBy("ai_model_convert.created_unix DESC") | |||||
aiModelManageConvert := make([]*AiModelConvert, 0, setting.UI.IssuePagingNum) | |||||
if err := sess.Table(new(AiModelConvert)).Where(cond). | |||||
Find(&aiModelManageConvert); err != nil { | |||||
return nil, 0, fmt.Errorf("Find: %v", err) | |||||
} | |||||
return aiModelManageConvert, count, nil | |||||
} |
@@ -164,12 +164,11 @@ type Cloudbrain struct { | |||||
FlavorName string //规格名称 | FlavorName string //规格名称 | ||||
EngineName string //引擎名称 | EngineName string //引擎名称 | ||||
TotalVersionCount int //任务的所有版本数量,包括删除的 | TotalVersionCount int //任务的所有版本数量,包括删除的 | ||||
LabelName string //标签名称 | |||||
ModelName string //模型名称 | |||||
ModelVersion string //模型版本 | |||||
CkptName string //权重文件名称 | |||||
ResultUrl string //推理结果的obs路径 | |||||
LabelName string //标签名称 | |||||
ModelName string //模型名称 | |||||
ModelVersion string //模型版本 | |||||
CkptName string //权重文件名称 | |||||
ResultUrl string //推理结果的obs路径 | |||||
User *User `xorm:"-"` | User *User `xorm:"-"` | ||||
Repo *Repository `xorm:"-"` | Repo *Repository `xorm:"-"` | ||||
@@ -933,6 +932,28 @@ type NotebookDelResult struct { | |||||
InstanceID string `json:"instance_id"` | InstanceID string `json:"instance_id"` | ||||
} | } | ||||
type CreateUserImageTrainJobParams struct { | |||||
JobName string `json:"job_name"` | |||||
Description string `json:"job_desc"` | |||||
Config UserImageConfig `json:"config"` | |||||
WorkspaceID string `json:"workspace_id"` | |||||
} | |||||
type UserImageConfig struct { | |||||
WorkServerNum int `json:"worker_server_num"` | |||||
AppUrl string `json:"app_url"` //训练作业的代码目录 | |||||
BootFileUrl string `json:"boot_file_url"` //训练作业的代码启动文件,需要在代码目录下 | |||||
Parameter []Parameter `json:"parameter"` | |||||
DataUrl string `json:"data_url"` //训练作业需要的数据集OBS路径URL | |||||
TrainUrl string `json:"train_url"` //训练作业的输出文件OBS路径URL | |||||
LogUrl string `json:"log_url"` | |||||
UserImageUrl string `json:"user_image_url"` | |||||
UserCommand string `json:"user_command"` | |||||
CreateVersion bool `json:"create_version"` | |||||
Flavor Flavor `json:"flavor"` | |||||
PoolID string `json:"pool_id"` | |||||
} | |||||
type CreateTrainJobParams struct { | type CreateTrainJobParams struct { | ||||
JobName string `json:"job_name"` | JobName string `json:"job_name"` | ||||
Description string `json:"job_desc"` | Description string `json:"job_desc"` | ||||
@@ -980,6 +1001,11 @@ type CreateTrainJobVersionParams struct { | |||||
Config TrainJobVersionConfig `json:"config"` | Config TrainJobVersionConfig `json:"config"` | ||||
} | } | ||||
type CreateTrainJobVersionUserImageParams struct { | |||||
Description string `json:"job_desc"` | |||||
Config TrainJobVersionUserImageConfig `json:"config"` | |||||
} | |||||
type TrainJobVersionConfig struct { | type TrainJobVersionConfig struct { | ||||
WorkServerNum int `json:"worker_server_num"` | WorkServerNum int `json:"worker_server_num"` | ||||
AppUrl string `json:"app_url"` //训练作业的代码目录 | AppUrl string `json:"app_url"` //训练作业的代码目录 | ||||
@@ -994,6 +1020,21 @@ type TrainJobVersionConfig struct { | |||||
PreVersionId int64 `json:"pre_version_id"` | PreVersionId int64 `json:"pre_version_id"` | ||||
} | } | ||||
type TrainJobVersionUserImageConfig struct { | |||||
WorkServerNum int `json:"worker_server_num"` | |||||
AppUrl string `json:"app_url"` //训练作业的代码目录 | |||||
BootFileUrl string `json:"boot_file_url"` //训练作业的代码启动文件,需要在代码目录下 | |||||
Parameter []Parameter `json:"parameter"` | |||||
DataUrl string `json:"data_url"` //训练作业需要的数据集OBS路径URL | |||||
TrainUrl string `json:"train_url"` //训练作业的输出文件OBS路径URL | |||||
LogUrl string `json:"log_url"` | |||||
Flavor Flavor `json:"flavor"` | |||||
PoolID string `json:"pool_id"` | |||||
PreVersionId int64 `json:"pre_version_id"` | |||||
UserImageUrl string `json:"user_image_url"` | |||||
UserCommand string `json:"user_command"` | |||||
} | |||||
type CreateConfigParams struct { | type CreateConfigParams struct { | ||||
ConfigName string `json:"config_name"` | ConfigName string `json:"config_name"` | ||||
Description string `json:"config_desc"` | Description string `json:"config_desc"` | ||||
@@ -1430,7 +1471,7 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | |||||
return cloudbrains, count, nil | return cloudbrains, count, nil | ||||
} | } | ||||
func QueryModelTrainJobVersionList(jobId string) ([]*CloudbrainInfo, int, error) { | |||||
func QueryModelTrainJobVersionList(jobId string) ([]*Cloudbrain, int, error) { | |||||
sess := x.NewSession() | sess := x.NewSession() | ||||
defer sess.Close() | defer sess.Close() | ||||
@@ -1445,7 +1486,7 @@ func QueryModelTrainJobVersionList(jobId string) ([]*CloudbrainInfo, int, error) | |||||
) | ) | ||||
sess.OrderBy("cloudbrain.created_unix DESC") | sess.OrderBy("cloudbrain.created_unix DESC") | ||||
cloudbrains := make([]*CloudbrainInfo, 0) | |||||
cloudbrains := make([]*Cloudbrain, 0) | |||||
if err := sess.Table(&Cloudbrain{}).Where(cond). | if err := sess.Table(&Cloudbrain{}).Where(cond). | ||||
Find(&cloudbrains); err != nil { | Find(&cloudbrains); err != nil { | ||||
return nil, 0, fmt.Errorf("Find: %v", err) | return nil, 0, fmt.Errorf("Find: %v", err) | ||||
@@ -1467,9 +1508,9 @@ func QueryModelTrainJobList(repoId int64) ([]*CloudbrainInfo, int, error) { | |||||
cond = cond.And( | cond = cond.And( | ||||
builder.Eq{"job_type": "TRAIN"}, | builder.Eq{"job_type": "TRAIN"}, | ||||
) | ) | ||||
cond = cond.And( | |||||
builder.In("type", 0, 1), | |||||
) | |||||
// cond = cond.And( | |||||
// builder.In("type", 0, 1), | |||||
// ) | |||||
cloudbrains := make([]*CloudbrainInfo, 0) | cloudbrains := make([]*CloudbrainInfo, 0) | ||||
if err := sess.Select("job_id,display_job_name").Table(&Cloudbrain{}).Where(cond).OrderBy("created_unix DESC"). | if err := sess.Select("job_id,display_job_name").Table(&Cloudbrain{}).Where(cond).OrderBy("created_unix DESC"). | ||||
@@ -144,6 +144,7 @@ func init() { | |||||
new(WechatBindLog), | new(WechatBindLog), | ||||
new(OrgStatistic), | new(OrgStatistic), | ||||
new(SearchRecord), | new(SearchRecord), | ||||
new(AiModelConvert), | |||||
) | ) | ||||
tablesStatistic = append(tablesStatistic, | tablesStatistic = append(tablesStatistic, | ||||
@@ -362,7 +362,7 @@ func QueryUserStaticDataByTableName(start int, pageSize int, tableName string, q | |||||
var cond = builder.NewCond() | var cond = builder.NewCond() | ||||
if len(userName) > 0 { | if len(userName) > 0 { | ||||
cond = cond.And( | cond = cond.And( | ||||
builder.Like{"name", userName}, | |||||
builder.Like{"lower(name)", strings.ToLower(userName)}, | |||||
) | ) | ||||
} | } | ||||
allCount, err := statictisSess.Where(cond).Count(queryObj) | allCount, err := statictisSess.Where(cond).Count(queryObj) | ||||
@@ -19,14 +19,14 @@ import ( | |||||
const ( | const ( | ||||
//notebook | //notebook | ||||
storageTypeOBS = "obs" | |||||
autoStopDuration = 4 * 60 * 60 | |||||
autoStopDurationMs = 4 * 60 * 60 * 1000 | |||||
DataSetMountPath = "/home/ma-user/work" | |||||
NotebookEnv = "Python3" | |||||
NotebookType = "Ascend" | |||||
FlavorInfo = "Ascend: 1*Ascend 910 CPU: 24 核 96GiB (modelarts.kat1.xlarge)" | |||||
storageTypeOBS = "obs" | |||||
autoStopDuration = 4 * 60 * 60 | |||||
autoStopDurationMs = 4 * 60 * 60 * 1000 | |||||
MORDELART_USER_IMAGE_ENGINE_ID = -1 | |||||
DataSetMountPath = "/home/ma-user/work" | |||||
NotebookEnv = "Python3" | |||||
NotebookType = "Ascend" | |||||
FlavorInfo = "Ascend: 1*Ascend 910 CPU: 24 核 96GiB (modelarts.kat1.xlarge)" | |||||
//train-job | //train-job | ||||
// ResourcePools = "{\"resource_pool\":[{\"id\":\"pool1328035d\", \"value\":\"专属资源池\"}]}" | // ResourcePools = "{\"resource_pool\":[{\"id\":\"pool1328035d\", \"value\":\"专属资源池\"}]}" | ||||
@@ -98,6 +98,8 @@ type GenerateTrainJobReq struct { | |||||
VersionCount int | VersionCount int | ||||
EngineName string | EngineName string | ||||
TotalVersionCount int | TotalVersionCount int | ||||
UserImageUrl string | |||||
UserCommand string | |||||
DatasetName string | DatasetName string | ||||
} | } | ||||
@@ -136,6 +138,7 @@ type VersionInfo struct { | |||||
Version []struct { | Version []struct { | ||||
ID int `json:"id"` | ID int `json:"id"` | ||||
Value string `json:"value"` | Value string `json:"value"` | ||||
Url string `json:"url"` | |||||
} `json:"version"` | } `json:"version"` | ||||
} | } | ||||
@@ -314,15 +317,107 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc | |||||
func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error) { | func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error) { | ||||
createTime := timeutil.TimeStampNow() | createTime := timeutil.TimeStampNow() | ||||
jobResult, err := createTrainJob(models.CreateTrainJobParams{ | |||||
var jobResult *models.CreateTrainJobResult | |||||
var createErr error | |||||
if req.EngineID < 0 { | |||||
jobResult, createErr = createTrainJobUserImage(models.CreateUserImageTrainJobParams{ | |||||
JobName: req.JobName, | |||||
Description: req.Description, | |||||
Config: models.UserImageConfig{ | |||||
WorkServerNum: req.WorkServerNumber, | |||||
AppUrl: req.CodeObsPath, | |||||
BootFileUrl: req.BootFileUrl, | |||||
DataUrl: req.DataUrl, | |||||
TrainUrl: req.TrainUrl, | |||||
LogUrl: req.LogUrl, | |||||
PoolID: req.PoolID, | |||||
CreateVersion: true, | |||||
Flavor: models.Flavor{ | |||||
Code: req.FlavorCode, | |||||
}, | |||||
Parameter: req.Parameters, | |||||
UserImageUrl: req.UserImageUrl, | |||||
UserCommand: req.UserCommand, | |||||
}, | |||||
}) | |||||
} else { | |||||
jobResult, createErr = createTrainJob(models.CreateTrainJobParams{ | |||||
JobName: req.JobName, | |||||
Description: req.Description, | |||||
Config: models.Config{ | |||||
WorkServerNum: req.WorkServerNumber, | |||||
AppUrl: req.CodeObsPath, | |||||
BootFileUrl: req.BootFileUrl, | |||||
DataUrl: req.DataUrl, | |||||
EngineID: req.EngineID, | |||||
TrainUrl: req.TrainUrl, | |||||
LogUrl: req.LogUrl, | |||||
PoolID: req.PoolID, | |||||
CreateVersion: true, | |||||
Flavor: models.Flavor{ | |||||
Code: req.FlavorCode, | |||||
}, | |||||
Parameter: req.Parameters, | |||||
}, | |||||
}) | |||||
} | |||||
if createErr != nil { | |||||
log.Error("CreateJob failed: %v", createErr.Error()) | |||||
return createErr | |||||
} | |||||
jobId := strconv.FormatInt(jobResult.JobID, 10) | |||||
createErr = models.CreateCloudbrain(&models.Cloudbrain{ | |||||
Status: TransTrainJobStatus(jobResult.Status), | |||||
UserID: ctx.User.ID, | |||||
RepoID: ctx.Repo.Repository.ID, | |||||
JobID: jobId, | |||||
JobName: req.JobName, | |||||
DisplayJobName: req.DisplayJobName, | |||||
JobType: string(models.JobTypeTrain), | |||||
Type: models.TypeCloudBrainTwo, | |||||
VersionID: jobResult.VersionID, | |||||
VersionName: jobResult.VersionName, | |||||
Uuid: req.Uuid, | |||||
DatasetName: req.DatasetName, | |||||
CommitID: req.CommitID, | |||||
IsLatestVersion: req.IsLatestVersion, | |||||
ComputeResource: models.NPUResource, | |||||
EngineID: req.EngineID, | |||||
TrainUrl: req.TrainUrl, | |||||
BranchName: req.BranchName, | |||||
Parameters: req.Params, | |||||
BootFile: req.BootFile, | |||||
DataUrl: req.DataUrl, | |||||
LogUrl: req.LogUrl, | |||||
FlavorCode: req.FlavorCode, | |||||
Description: req.Description, | |||||
WorkServerNumber: req.WorkServerNumber, | |||||
FlavorName: req.FlavorName, | |||||
EngineName: req.EngineName, | |||||
VersionCount: req.VersionCount, | |||||
TotalVersionCount: req.TotalVersionCount, | |||||
CreatedUnix: createTime, | |||||
UpdatedUnix: createTime, | |||||
}) | |||||
if createErr != nil { | |||||
log.Error("CreateCloudbrain(%s) failed:%v", req.DisplayJobName, createErr.Error()) | |||||
return createErr | |||||
} | |||||
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, jobId, req.DisplayJobName, models.ActionCreateTrainTask) | |||||
return nil | |||||
} | |||||
func GenerateModelConvertTrainJob(req *GenerateTrainJobReq) (*models.CreateTrainJobResult, error) { | |||||
return createTrainJobUserImage(models.CreateUserImageTrainJobParams{ | |||||
JobName: req.JobName, | JobName: req.JobName, | ||||
Description: req.Description, | Description: req.Description, | ||||
Config: models.Config{ | |||||
Config: models.UserImageConfig{ | |||||
WorkServerNum: req.WorkServerNumber, | WorkServerNum: req.WorkServerNumber, | ||||
AppUrl: req.CodeObsPath, | AppUrl: req.CodeObsPath, | ||||
BootFileUrl: req.BootFileUrl, | BootFileUrl: req.BootFileUrl, | ||||
DataUrl: req.DataUrl, | DataUrl: req.DataUrl, | ||||
EngineID: req.EngineID, | |||||
TrainUrl: req.TrainUrl, | TrainUrl: req.TrainUrl, | ||||
LogUrl: req.LogUrl, | LogUrl: req.LogUrl, | ||||
PoolID: req.PoolID, | PoolID: req.PoolID, | ||||
@@ -330,20 +425,83 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||||
Flavor: models.Flavor{ | Flavor: models.Flavor{ | ||||
Code: req.FlavorCode, | Code: req.FlavorCode, | ||||
}, | }, | ||||
Parameter: req.Parameters, | |||||
Parameter: req.Parameters, | |||||
UserImageUrl: req.UserImageUrl, | |||||
UserCommand: req.UserCommand, | |||||
}, | }, | ||||
}) | }) | ||||
if err != nil { | |||||
log.Error("CreateJob failed: %v", err.Error()) | |||||
return err | |||||
} | |||||
func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, jobId string) (err error) { | |||||
createTime := timeutil.TimeStampNow() | |||||
var jobResult *models.CreateTrainJobResult | |||||
var createErr error | |||||
log.Info(" req.EngineID =" + fmt.Sprint(req.EngineID)) | |||||
if req.EngineID < 0 { | |||||
jobResult, createErr = createTrainJobVersionUserImage(models.CreateTrainJobVersionUserImageParams{ | |||||
Description: req.Description, | |||||
Config: models.TrainJobVersionUserImageConfig{ | |||||
WorkServerNum: req.WorkServerNumber, | |||||
AppUrl: req.CodeObsPath, | |||||
BootFileUrl: req.BootFileUrl, | |||||
DataUrl: req.DataUrl, | |||||
TrainUrl: req.TrainUrl, | |||||
LogUrl: req.LogUrl, | |||||
PoolID: req.PoolID, | |||||
Flavor: models.Flavor{ | |||||
Code: req.FlavorCode, | |||||
}, | |||||
Parameter: req.Parameters, | |||||
PreVersionId: req.PreVersionId, | |||||
UserImageUrl: req.UserImageUrl, | |||||
UserCommand: req.UserCommand, | |||||
}, | |||||
}, jobId) | |||||
} else { | |||||
jobResult, createErr = createTrainJobVersion(models.CreateTrainJobVersionParams{ | |||||
Description: req.Description, | |||||
Config: models.TrainJobVersionConfig{ | |||||
WorkServerNum: req.WorkServerNumber, | |||||
AppUrl: req.CodeObsPath, | |||||
BootFileUrl: req.BootFileUrl, | |||||
DataUrl: req.DataUrl, | |||||
EngineID: req.EngineID, | |||||
TrainUrl: req.TrainUrl, | |||||
LogUrl: req.LogUrl, | |||||
PoolID: req.PoolID, | |||||
Flavor: models.Flavor{ | |||||
Code: req.FlavorCode, | |||||
}, | |||||
Parameter: req.Parameters, | |||||
PreVersionId: req.PreVersionId, | |||||
}, | |||||
}, jobId) | |||||
} | |||||
if createErr != nil { | |||||
log.Error("CreateJob failed: %v", createErr.Error()) | |||||
return createErr | |||||
} | } | ||||
jobId := strconv.FormatInt(jobResult.JobID, 10) | |||||
err = models.CreateCloudbrain(&models.Cloudbrain{ | |||||
var jobTypes []string | |||||
jobTypes = append(jobTypes, string(models.JobTypeTrain)) | |||||
repo := ctx.Repo.Repository | |||||
VersionTaskList, VersionListCount, createErr := models.CloudbrainsVersionList(&models.CloudbrainsOptions{ | |||||
RepoID: repo.ID, | |||||
Type: models.TypeCloudBrainTwo, | |||||
JobTypes: jobTypes, | |||||
JobID: strconv.FormatInt(jobResult.JobID, 10), | |||||
}) | |||||
if createErr != nil { | |||||
ctx.ServerError("Cloudbrain", createErr) | |||||
return createErr | |||||
} | |||||
//将当前版本的isLatestVersion设置为"1"和任务数量更新,任务数量包括当前版本数VersionCount和历史创建的总版本数TotalVersionCount | |||||
createErr = models.CreateCloudbrain(&models.Cloudbrain{ | |||||
Status: TransTrainJobStatus(jobResult.Status), | Status: TransTrainJobStatus(jobResult.Status), | ||||
UserID: ctx.User.ID, | UserID: ctx.User.ID, | ||||
RepoID: ctx.Repo.Repository.ID, | RepoID: ctx.Repo.Repository.ID, | ||||
JobID: jobId, | |||||
JobID: strconv.FormatInt(jobResult.JobID, 10), | |||||
JobName: req.JobName, | JobName: req.JobName, | ||||
DisplayJobName: req.DisplayJobName, | DisplayJobName: req.DisplayJobName, | ||||
JobType: string(models.JobTypeTrain), | JobType: string(models.JobTypeTrain), | ||||
@@ -354,6 +512,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||||
DatasetName: req.DatasetName, | DatasetName: req.DatasetName, | ||||
CommitID: req.CommitID, | CommitID: req.CommitID, | ||||
IsLatestVersion: req.IsLatestVersion, | IsLatestVersion: req.IsLatestVersion, | ||||
PreVersionName: req.PreVersionName, | |||||
ComputeResource: models.NPUResource, | ComputeResource: models.NPUResource, | ||||
EngineID: req.EngineID, | EngineID: req.EngineID, | ||||
TrainUrl: req.TrainUrl, | TrainUrl: req.TrainUrl, | ||||
@@ -362,45 +521,54 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||||
BootFile: req.BootFile, | BootFile: req.BootFile, | ||||
DataUrl: req.DataUrl, | DataUrl: req.DataUrl, | ||||
LogUrl: req.LogUrl, | LogUrl: req.LogUrl, | ||||
PreVersionId: req.PreVersionId, | |||||
FlavorCode: req.FlavorCode, | FlavorCode: req.FlavorCode, | ||||
Description: req.Description, | Description: req.Description, | ||||
WorkServerNumber: req.WorkServerNumber, | WorkServerNumber: req.WorkServerNumber, | ||||
FlavorName: req.FlavorName, | FlavorName: req.FlavorName, | ||||
EngineName: req.EngineName, | EngineName: req.EngineName, | ||||
VersionCount: req.VersionCount, | |||||
TotalVersionCount: req.TotalVersionCount, | |||||
TotalVersionCount: VersionTaskList[0].TotalVersionCount + 1, | |||||
VersionCount: VersionListCount + 1, | |||||
CreatedUnix: createTime, | CreatedUnix: createTime, | ||||
UpdatedUnix: createTime, | UpdatedUnix: createTime, | ||||
}) | }) | ||||
if createErr != nil { | |||||
log.Error("CreateCloudbrain(%s) failed:%v", req.JobName, createErr.Error()) | |||||
return createErr | |||||
} | |||||
if err != nil { | |||||
log.Error("CreateCloudbrain(%s) failed:%v", req.DisplayJobName, err.Error()) | |||||
return err | |||||
//将训练任务的上一版本的isLatestVersion设置为"0" | |||||
createErr = models.SetVersionCountAndLatestVersion(strconv.FormatInt(jobResult.JobID, 10), VersionTaskList[0].VersionName, VersionCount, NotLatestVersion, TotalVersionCount) | |||||
if createErr != nil { | |||||
ctx.ServerError("Update IsLatestVersion failed", createErr) | |||||
return createErr | |||||
} | } | ||||
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, jobId, req.DisplayJobName, models.ActionCreateTrainTask) | |||||
return nil | |||||
return createErr | |||||
} | } | ||||
func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, jobId string) (err error) { | |||||
func GenerateTrainJobVersionByUserImage(ctx *context.Context, req *GenerateTrainJobReq, jobId string) (err error) { | |||||
createTime := timeutil.TimeStampNow() | createTime := timeutil.TimeStampNow() | ||||
jobResult, err := createTrainJobVersion(models.CreateTrainJobVersionParams{ | |||||
jobResult, err := createTrainJobUserImage(models.CreateUserImageTrainJobParams{ | |||||
JobName: req.JobName, | |||||
Description: req.Description, | Description: req.Description, | ||||
Config: models.TrainJobVersionConfig{ | |||||
Config: models.UserImageConfig{ | |||||
WorkServerNum: req.WorkServerNumber, | WorkServerNum: req.WorkServerNumber, | ||||
AppUrl: req.CodeObsPath, | AppUrl: req.CodeObsPath, | ||||
BootFileUrl: req.BootFileUrl, | BootFileUrl: req.BootFileUrl, | ||||
DataUrl: req.DataUrl, | DataUrl: req.DataUrl, | ||||
EngineID: req.EngineID, | |||||
TrainUrl: req.TrainUrl, | TrainUrl: req.TrainUrl, | ||||
LogUrl: req.LogUrl, | LogUrl: req.LogUrl, | ||||
PoolID: req.PoolID, | PoolID: req.PoolID, | ||||
CreateVersion: true, | |||||
Flavor: models.Flavor{ | Flavor: models.Flavor{ | ||||
Code: req.FlavorCode, | Code: req.FlavorCode, | ||||
}, | }, | ||||
Parameter: req.Parameters, | Parameter: req.Parameters, | ||||
PreVersionId: req.PreVersionId, | |||||
UserImageUrl: req.UserImageUrl, | |||||
UserCommand: req.UserCommand, | |||||
}, | }, | ||||
}, jobId) | |||||
}) | |||||
if err != nil { | if err != nil { | ||||
log.Error("CreateJob failed: %v", err.Error()) | log.Error("CreateJob failed: %v", err.Error()) | ||||
return err | return err | ||||
@@ -438,7 +606,8 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job | |||||
IsLatestVersion: req.IsLatestVersion, | IsLatestVersion: req.IsLatestVersion, | ||||
PreVersionName: req.PreVersionName, | PreVersionName: req.PreVersionName, | ||||
ComputeResource: models.NPUResource, | ComputeResource: models.NPUResource, | ||||
EngineID: req.EngineID, | |||||
EngineID: MORDELART_USER_IMAGE_ENGINE_ID, | |||||
Image: req.UserImageUrl, | |||||
TrainUrl: req.TrainUrl, | TrainUrl: req.TrainUrl, | ||||
BranchName: req.BranchName, | BranchName: req.BranchName, | ||||
Parameters: req.Params, | Parameters: req.Params, | ||||
@@ -472,6 +472,62 @@ sendjob: | |||||
return &result, nil | return &result, nil | ||||
} | } | ||||
func createTrainJobUserImage(createJobParams models.CreateUserImageTrainJobParams) (*models.CreateTrainJobResult, error) { | |||||
checkSetting() | |||||
client := getRestyClient() | |||||
var result models.CreateTrainJobResult | |||||
retry := 0 | |||||
sendjob: | |||||
res, err := client.R(). | |||||
SetHeader("Content-Type", "application/json"). | |||||
SetAuthToken(TOKEN). | |||||
SetBody(createJobParams). | |||||
SetResult(&result). | |||||
Post(HOST + "/v1/" + setting.ProjectID + urlTrainJob) | |||||
if err != nil { | |||||
return nil, fmt.Errorf("resty create train-job: %s", err) | |||||
} | |||||
req, _ := json.Marshal(createJobParams) | |||||
log.Info("%s", req) | |||||
if res.StatusCode() == http.StatusUnauthorized && retry < 1 { | |||||
retry++ | |||||
_ = getToken() | |||||
goto sendjob | |||||
} | |||||
if res.StatusCode() != http.StatusOK { | |||||
var temp models.ErrorResult | |||||
if err = json.Unmarshal([]byte(res.String()), &temp); err != nil { | |||||
log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||||
return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||||
} | |||||
log.Error("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||||
BootFileErrorMsg := "Invalid OBS path '" + createJobParams.Config.BootFileUrl + "'." | |||||
DataSetErrorMsg := "Invalid OBS path '" + createJobParams.Config.DataUrl + "'." | |||||
if temp.ErrorMsg == BootFileErrorMsg { | |||||
log.Error("启动文件错误!createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||||
return &result, fmt.Errorf("启动文件错误!") | |||||
} | |||||
if temp.ErrorMsg == DataSetErrorMsg { | |||||
log.Error("数据集错误!createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||||
return &result, fmt.Errorf("数据集错误!") | |||||
} | |||||
return &result, fmt.Errorf("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||||
} | |||||
if !result.IsSuccess { | |||||
log.Error("createTrainJob failed(%s): %s", result.ErrorCode, result.ErrorMsg) | |||||
return &result, fmt.Errorf("createTrainJob failed(%s): %s", result.ErrorCode, result.ErrorMsg) | |||||
} | |||||
return &result, nil | |||||
} | |||||
func createTrainJob(createJobParams models.CreateTrainJobParams) (*models.CreateTrainJobResult, error) { | func createTrainJob(createJobParams models.CreateTrainJobParams) (*models.CreateTrainJobResult, error) { | ||||
checkSetting() | checkSetting() | ||||
client := getRestyClient() | client := getRestyClient() | ||||
@@ -583,6 +639,61 @@ sendjob: | |||||
return &result, nil | return &result, nil | ||||
} | } | ||||
func createTrainJobVersionUserImage(createJobVersionParams models.CreateTrainJobVersionUserImageParams, jobID string) (*models.CreateTrainJobResult, error) { | |||||
checkSetting() | |||||
client := getRestyClient() | |||||
var result models.CreateTrainJobResult | |||||
retry := 0 | |||||
sendjob: | |||||
res, err := client.R(). | |||||
SetHeader("Content-Type", "application/json"). | |||||
SetAuthToken(TOKEN). | |||||
SetBody(createJobVersionParams). | |||||
SetResult(&result). | |||||
Post(HOST + "/v1/" + setting.ProjectID + urlTrainJob + "/" + jobID + "/versions") | |||||
if err != nil { | |||||
return nil, fmt.Errorf("resty create train-job version: %s", err) | |||||
} | |||||
req, _ := json.Marshal(createJobVersionParams) | |||||
log.Info("%s", req) | |||||
if res.StatusCode() == http.StatusUnauthorized && retry < 1 { | |||||
retry++ | |||||
_ = getToken() | |||||
goto sendjob | |||||
} | |||||
if res.StatusCode() != http.StatusOK { | |||||
var temp models.ErrorResult | |||||
if err = json.Unmarshal([]byte(res.String()), &temp); err != nil { | |||||
log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||||
return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||||
} | |||||
BootFileErrorMsg := "Invalid OBS path '" + createJobVersionParams.Config.BootFileUrl + "'." | |||||
DataSetErrorMsg := "Invalid OBS path '" + createJobVersionParams.Config.DataUrl + "'." | |||||
if temp.ErrorMsg == BootFileErrorMsg { | |||||
log.Error("启动文件错误!createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||||
return &result, fmt.Errorf("启动文件错误!") | |||||
} | |||||
if temp.ErrorMsg == DataSetErrorMsg { | |||||
log.Error("数据集错误!createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||||
return &result, fmt.Errorf("数据集错误!") | |||||
} | |||||
return &result, fmt.Errorf("createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||||
} | |||||
if !result.IsSuccess { | |||||
log.Error("createTrainJobVersion failed(%s): %s", result.ErrorCode, result.ErrorMsg) | |||||
return &result, fmt.Errorf("createTrainJobVersion failed(%s): %s", result.ErrorCode, result.ErrorMsg) | |||||
} | |||||
return &result, nil | |||||
} | |||||
func GetResourceSpecs() (*models.GetResourceSpecsResult, error) { | func GetResourceSpecs() (*models.GetResourceSpecsResult, error) { | ||||
checkSetting() | checkSetting() | ||||
client := getRestyClient() | client := getRestyClient() | ||||
@@ -479,9 +479,10 @@ var ( | |||||
TrainResourceSpecs string | TrainResourceSpecs string | ||||
InferenceGpuTypes string | InferenceGpuTypes string | ||||
InferenceResourceSpecs string | InferenceResourceSpecs string | ||||
MaxModelSize float64 | |||||
MaxDatasetNum int | MaxDatasetNum int | ||||
CullIdleTimeout string | |||||
CullInterval string | |||||
CullIdleTimeout string | |||||
CullInterval string | |||||
//benchmark config | //benchmark config | ||||
IsBenchmarkEnabled bool | IsBenchmarkEnabled bool | ||||
@@ -631,6 +632,24 @@ var ( | |||||
OrgName string | OrgName string | ||||
TeamName string | TeamName string | ||||
}{} | }{} | ||||
ModelConvert = struct { | |||||
GPU_PYTORCH_IMAGE string | |||||
GpuQueue string | |||||
GPU_TENSORFLOW_IMAGE string | |||||
NPU_MINDSPORE_16_IMAGE string | |||||
PytorchOnnxBootFile string | |||||
PytorchTrTBootFile string | |||||
MindsporeBootFile string | |||||
TensorFlowNpuBootFile string | |||||
TensorFlowGpuBootFile string | |||||
ConvertRepoPath string | |||||
GPU_Resource_Specs_ID int | |||||
NPU_FlavorCode string | |||||
NPU_PoolID string | |||||
NPU_MINDSPORE_IMAGE_ID int | |||||
NPU_TENSORFLOW_IMAGE_ID int | |||||
}{} | |||||
) | ) | ||||
// DateLang transforms standard language locale name to corresponding value in datetime plugin. | // DateLang transforms standard language locale name to corresponding value in datetime plugin. | ||||
@@ -1330,10 +1349,11 @@ func NewContext() { | |||||
MaxDuration = sec.Key("MAX_DURATION").MustInt64(14400) | MaxDuration = sec.Key("MAX_DURATION").MustInt64(14400) | ||||
TrainGpuTypes = sec.Key("TRAIN_GPU_TYPES").MustString("") | TrainGpuTypes = sec.Key("TRAIN_GPU_TYPES").MustString("") | ||||
TrainResourceSpecs = sec.Key("TRAIN_RESOURCE_SPECS").MustString("") | TrainResourceSpecs = sec.Key("TRAIN_RESOURCE_SPECS").MustString("") | ||||
MaxModelSize = sec.Key("MAX_MODEL_SIZE").MustFloat64(500) | |||||
InferenceGpuTypes = sec.Key("INFERENCE_GPU_TYPES").MustString("") | InferenceGpuTypes = sec.Key("INFERENCE_GPU_TYPES").MustString("") | ||||
InferenceResourceSpecs = sec.Key("INFERENCE_RESOURCE_SPECS").MustString("") | InferenceResourceSpecs = sec.Key("INFERENCE_RESOURCE_SPECS").MustString("") | ||||
SpecialPools = sec.Key("SPECIAL_POOL").MustString("") | SpecialPools = sec.Key("SPECIAL_POOL").MustString("") | ||||
MaxDatasetNum = sec.Key("MAX_DATASET_NUM").MustInt(5) | MaxDatasetNum = sec.Key("MAX_DATASET_NUM").MustInt(5) | ||||
CullIdleTimeout = sec.Key("CULL_IDLE_TIMEOUT").MustString("900") | CullIdleTimeout = sec.Key("CULL_IDLE_TIMEOUT").MustString("900") | ||||
CullInterval = sec.Key("CULL_INTERVAL").MustString("60") | CullInterval = sec.Key("CULL_INTERVAL").MustString("60") | ||||
@@ -1431,6 +1451,27 @@ func NewContext() { | |||||
Course.TeamName = sec.Key("team_name").MustString("") | Course.TeamName = sec.Key("team_name").MustString("") | ||||
GetGrampusConfig() | GetGrampusConfig() | ||||
getModelConvertConfig() | |||||
} | |||||
func getModelConvertConfig() { | |||||
sec := Cfg.Section("model_convert") | |||||
ModelConvert.GPU_PYTORCH_IMAGE = sec.Key("GPU_PYTORCH_IMAGE").MustString("dockerhub.pcl.ac.cn:5000/user-images/openi:tensorRT_7_zouap") | |||||
ModelConvert.GpuQueue = sec.Key("GpuQueue").MustString("openidgx") | |||||
ModelConvert.GPU_TENSORFLOW_IMAGE = sec.Key("GPU_TENSORFLOW_IMAGE").MustString("dockerhub.pcl.ac.cn:5000/user-images/openi:tf2onnx") | |||||
ModelConvert.NPU_MINDSPORE_16_IMAGE = sec.Key("NPU_MINDSPORE_16_IMAGE").MustString("swr.cn-south-222.ai.pcl.cn/openi/mindspore1.6.1_train_v1_openi:v3_ascend") | |||||
ModelConvert.PytorchOnnxBootFile = sec.Key("PytorchOnnxBootFile").MustString("convert_pytorch.py") | |||||
ModelConvert.PytorchTrTBootFile = sec.Key("PytorchTrTBootFile").MustString("convert_pytorch_tensorrt.py") | |||||
ModelConvert.MindsporeBootFile = sec.Key("MindsporeBootFile").MustString("convert_mindspore.py") | |||||
ModelConvert.TensorFlowNpuBootFile = sec.Key("TensorFlowNpuBootFile").MustString("convert_tensorflow.py") | |||||
ModelConvert.TensorFlowGpuBootFile = sec.Key("TensorFlowGpuBootFile").MustString("convert_tensorflow_gpu.py") | |||||
ModelConvert.ConvertRepoPath = sec.Key("ConvertRepoPath").MustString("https://git.openi.org.cn/zouap/npu_test") | |||||
ModelConvert.GPU_Resource_Specs_ID = sec.Key("GPU_Resource_Specs_ID").MustInt(1) | |||||
ModelConvert.NPU_FlavorCode = sec.Key("NPU_FlavorCode").MustString("modelarts.bm.910.arm.public.1") | |||||
ModelConvert.NPU_PoolID = sec.Key("NPU_PoolID").MustString("pool7908321a") | |||||
ModelConvert.NPU_MINDSPORE_IMAGE_ID = sec.Key("NPU_MINDSPORE_IMAGE_ID").MustInt(121) | |||||
ModelConvert.NPU_TENSORFLOW_IMAGE_ID = sec.Key("NPU_TENSORFLOW_IMAGE_ID").MustInt(35) | |||||
} | } | ||||
func GetGrampusConfig() { | func GetGrampusConfig() { | ||||
@@ -217,6 +217,49 @@ func GetOneLevelAllObjectUnderDirMinio(bucket string, prefixRootPath string, rel | |||||
} | } | ||||
func MinioGetFilesSize(bucketName string, Files []string) int64 { | |||||
_, core, err := getClients() | |||||
var fileTotalSize int64 | |||||
fileTotalSize = 0 | |||||
if err != nil { | |||||
log.Error("getClients failed:", err.Error()) | |||||
return fileTotalSize | |||||
} | |||||
for _, file := range Files { | |||||
log.Info("file=" + file) | |||||
meta, err := core.StatObject(bucketName, file, miniov6.StatObjectOptions{}) | |||||
if err != nil { | |||||
log.Info("Get file error:" + err.Error()) | |||||
} | |||||
fileTotalSize += meta.Size | |||||
} | |||||
return fileTotalSize | |||||
} | |||||
func MinioCopyFiles(bucketName string, srcPath string, destPath string, Files []string) (int64, error) { | |||||
_, core, err := getClients() | |||||
var fileTotalSize int64 | |||||
fileTotalSize = 0 | |||||
if err != nil { | |||||
log.Error("getClients failed:", err.Error()) | |||||
return fileTotalSize, err | |||||
} | |||||
for _, file := range Files { | |||||
srcObjectName := srcPath + file | |||||
destObjectName := destPath + file | |||||
log.Info("srcObjectName=" + srcObjectName + " destObjectName=" + destObjectName) | |||||
meta, err := core.StatObject(bucketName, srcObjectName, miniov6.StatObjectOptions{}) | |||||
if err != nil { | |||||
log.Info("Get file error:" + err.Error()) | |||||
} | |||||
core.CopyObject(bucketName, srcObjectName, bucketName, destObjectName, meta.UserMetadata) | |||||
fileTotalSize += meta.Size | |||||
} | |||||
return fileTotalSize, nil | |||||
} | |||||
func MinioPathCopy(bucketName string, srcPath string, destPath string) (int64, error) { | func MinioPathCopy(bucketName string, srcPath string, destPath string) (int64, error) { | ||||
_, core, err := getClients() | _, core, err := getClients() | ||||
var fileTotalSize int64 | var fileTotalSize int64 | ||||
@@ -264,7 +264,47 @@ func ObsModelDownload(JobName string, fileName string) (io.ReadCloser, error) { | |||||
} | } | ||||
} | } | ||||
func ObsCopyManyFile(srcBucket string, srcPath string, destBucket string, destPath string) (int64, error) { | |||||
func ObsGetFilesSize(srcBucket string, Files []string) int64 { | |||||
var fileTotalSize int64 | |||||
for _, file := range Files { | |||||
log.Info("file=" + file) | |||||
out, err := ObsCli.GetObjectMetadata(&obs.GetObjectMetadataInput{ | |||||
Bucket: srcBucket, | |||||
Key: file, | |||||
}) | |||||
if err != nil { | |||||
log.Info("Get File error, error=" + err.Error()) | |||||
continue | |||||
} | |||||
fileTotalSize += out.ContentLength | |||||
} | |||||
return fileTotalSize | |||||
} | |||||
func ObsCopyManyFile(srcBucket string, srcPath string, destBucket string, destPath string, Files []string) (int64, error) { | |||||
var fileTotalSize int64 | |||||
for _, file := range Files { | |||||
srcKey := srcPath + file | |||||
destKey := destPath + file | |||||
log.Info("srcKey=" + srcKey + " destKey=" + destKey) | |||||
out, err := ObsCli.GetObjectMetadata(&obs.GetObjectMetadataInput{ | |||||
Bucket: srcBucket, | |||||
Key: srcKey, | |||||
}) | |||||
if err != nil { | |||||
log.Info("Get File error, error=" + err.Error()) | |||||
continue | |||||
} | |||||
obsCopyFile(srcBucket, srcKey, destBucket, destKey) | |||||
fileTotalSize += out.ContentLength | |||||
} | |||||
return fileTotalSize, nil | |||||
} | |||||
func ObsCopyAllFile(srcBucket string, srcPath string, destBucket string, destPath string) (int64, error) { | |||||
input := &obs.ListObjectsInput{} | input := &obs.ListObjectsInput{} | ||||
input.Bucket = srcBucket | input.Bucket = srcBucket | ||||
// 设置每页100个对象 | // 设置每页100个对象 | ||||
@@ -330,6 +370,7 @@ func GetOneLevelAllObjectUnderDir(bucket string, prefixRootPath string, relative | |||||
output, err := ObsCli.ListObjects(input) | output, err := ObsCli.ListObjects(input) | ||||
fileInfos := make([]FileInfo, 0) | fileInfos := make([]FileInfo, 0) | ||||
prefixLen := len(input.Prefix) | prefixLen := len(input.Prefix) | ||||
fileMap := make(map[string]bool, 0) | |||||
if err == nil { | if err == nil { | ||||
for _, val := range output.Contents { | for _, val := range output.Contents { | ||||
log.Info("val key=" + val.Key) | log.Info("val key=" + val.Key) | ||||
@@ -338,23 +379,51 @@ func GetOneLevelAllObjectUnderDir(bucket string, prefixRootPath string, relative | |||||
if val.Key == input.Prefix { | if val.Key == input.Prefix { | ||||
continue | continue | ||||
} | } | ||||
if strings.Contains(val.Key[prefixLen:len(val.Key)-1], "/") { | |||||
fileName = val.Key[prefixLen:] | |||||
log.Info("fileName =" + fileName) | |||||
files := strings.Split(fileName, "/") | |||||
if fileMap[files[0]] { | |||||
continue | continue | ||||
} else { | |||||
fileMap[files[0]] = true | |||||
} | } | ||||
if strings.HasSuffix(val.Key, "/") { | |||||
ParenDir := relativePath | |||||
fileName = files[0] | |||||
if len(files) > 1 { | |||||
isDir = true | isDir = true | ||||
fileName = val.Key[prefixLen : len(val.Key)-1] | |||||
relativePath += val.Key[prefixLen:] | |||||
ParenDir += fileName + "/" | |||||
} else { | } else { | ||||
isDir = false | isDir = false | ||||
fileName = val.Key[prefixLen:] | |||||
} | } | ||||
// if strings.Contains(val.Key[prefixLen:len(val.Key)-1], "/") { | |||||
// files := strings.Split(fileName, "/") | |||||
// fileName = files[0] | |||||
// isDir = true | |||||
// if fileMap[files[0]] { | |||||
// continue | |||||
// } else { | |||||
// fileMap[files[0]] = true | |||||
// } | |||||
// } else { | |||||
// if strings.HasSuffix(val.Key, "/") { | |||||
// isDir = true | |||||
// fileName = val.Key[prefixLen : len(val.Key)-1] | |||||
// relativePath += val.Key[prefixLen:] | |||||
// } else { | |||||
// isDir = false | |||||
// fileName = val.Key[prefixLen:] | |||||
// } | |||||
// fileMap[fileName] = true | |||||
// } | |||||
fileInfo := FileInfo{ | fileInfo := FileInfo{ | ||||
ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"), | ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"), | ||||
FileName: fileName, | FileName: fileName, | ||||
Size: val.Size, | Size: val.Size, | ||||
IsDir: isDir, | IsDir: isDir, | ||||
ParenDir: relativePath, | |||||
ParenDir: ParenDir, | |||||
} | } | ||||
fileInfos = append(fileInfos, fileInfo) | fileInfos = append(fileInfos, fileInfo) | ||||
} | } | ||||
@@ -424,6 +493,7 @@ func GetObsListObject(jobName, outPutPath, parentDir, versionName string) ([]Fil | |||||
input := &obs.ListObjectsInput{} | input := &obs.ListObjectsInput{} | ||||
input.Bucket = setting.Bucket | input.Bucket = setting.Bucket | ||||
input.Prefix = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, outPutPath, versionName, parentDir), "/") | input.Prefix = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, outPutPath, versionName, parentDir), "/") | ||||
log.Info("bucket=" + input.Bucket + " Prefix=" + input.Prefix) | |||||
strPrefix := strings.Split(input.Prefix, "/") | strPrefix := strings.Split(input.Prefix, "/") | ||||
output, err := ObsCli.ListObjects(input) | output, err := ObsCli.ListObjects(input) | ||||
fileInfos := make([]FileInfo, 0) | fileInfos := make([]FileInfo, 0) | ||||
@@ -1218,6 +1218,14 @@ model.manage.Recall = Recall | |||||
model.manage.sava_model = Sava Model | model.manage.sava_model = Sava Model | ||||
model.manage.model_manage = ModelManage | model.manage.model_manage = ModelManage | ||||
model.manage.model_accuracy = Model Accuracy | model.manage.model_accuracy = Model Accuracy | ||||
model.convert=Model Transformation | |||||
model.list=Model List | |||||
model.manage.create_new_convert_task=Create Model Transformation Task | |||||
modelconvert.manage.create_error1=A model transformation task with the same name already exists. | |||||
modelconvert.manage.create_error2=Only one running model transformation task can be created. | |||||
modelconvert.manage.model_not_exist=The model does not exist. | |||||
modelconvert.manage.no_operate_right=No operation permission. | |||||
grampus.train_job.ai_center = AI Center | grampus.train_job.ai_center = AI Center | ||||
grampus.dataset_path_rule = The code is storaged in /cache/code;the dataset is storaged in /cache/dataset;and please put your model into /cache/output, then you can download it online。 | grampus.dataset_path_rule = The code is storaged in /cache/code;the dataset is storaged in /cache/dataset;and please put your model into /cache/output, then you can download it online。 | ||||
@@ -1230,6 +1230,14 @@ model.manage.Recall = 召回率 | |||||
model.manage.sava_model = 保存模型 | model.manage.sava_model = 保存模型 | ||||
model.manage.model_manage = 模型管理 | model.manage.model_manage = 模型管理 | ||||
model.manage.model_accuracy = 模型精度 | model.manage.model_accuracy = 模型精度 | ||||
model.convert=模型转换任务 | |||||
model.list=模型列表 | |||||
model.manage.create_new_convert_task=创建模型转换任务 | |||||
modelconvert.manage.create_error1=相同的名称模型转换任务已经存在。 | |||||
modelconvert.manage.create_error2=只能创建一个正在运行的模型转换任务。 | |||||
modelconvert.manage.model_not_exist=选择的模型不存在。 | |||||
modelconvert.manage.no_operate_right=无操作权限。 | |||||
grampus.train_job.ai_center=智算中心 | grampus.train_job.ai_center=智算中心 | ||||
grampus.dataset_path_rule = 训练脚本存储在/cache/code中,数据集存储在/cache/dataset中,训练输出请存储在/cache/output中以供后续下载。 | grampus.dataset_path_rule = 训练脚本存储在/cache/code中,数据集存储在/cache/dataset中,训练输出请存储在/cache/output中以供后续下载。 | ||||
@@ -0,0 +1,386 @@ | |||||
/*------------------------------------- | |||||
zTree Style using fontawesome instead of images | |||||
version: 1.1 | |||||
author: Mike King | |||||
email: mikkelking @ hotmail . com | |||||
website: http://code.google.com/p/jquerytree/ | |||||
-------------------------------------*/ | |||||
/* Definitions ----------------------*/ | |||||
/* End of Definitions ---------------*/ | |||||
/* Imports -------------------------*/ | |||||
/* End of Imports ------------------*/ | |||||
.ztree * { | |||||
padding: 0; | |||||
margin: 0; | |||||
font-size: 12px; | |||||
font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif; | |||||
background-color: #af0000; | |||||
} | |||||
.ztree { | |||||
margin: 0; | |||||
padding: 5px; | |||||
color: #ffffff; | |||||
background-color: #af0000; | |||||
} | |||||
.ztree li { | |||||
padding: 0; | |||||
margin: 0; | |||||
list-style: none; | |||||
line-height: 17px; | |||||
text-align: left; | |||||
white-space: nowrap; | |||||
outline: 0; | |||||
} | |||||
.ztree li ul { | |||||
margin: 0px; | |||||
padding: 0 0 0 18px; | |||||
} | |||||
.ztree li a { | |||||
padding-right: 3px; | |||||
margin: 0; | |||||
cursor: pointer; | |||||
height: 17px; | |||||
color: #ffffff; | |||||
background-color: transparent; | |||||
text-decoration: none; | |||||
vertical-align: top; | |||||
display: inline-block; | |||||
} | |||||
.ztree li a input.rename { | |||||
height: 14px; | |||||
width: 80px; | |||||
padding: 0; | |||||
margin: 0; | |||||
color: #af0000; | |||||
background-color: #ffffff; | |||||
font-size: 12px; | |||||
border: 1px #585956 solid; | |||||
*border: 0px; | |||||
} | |||||
.ztree li a:hover { | |||||
text-decoration: underline; | |||||
} | |||||
.ztree li a.curSelectedNode { | |||||
padding-top: 0px; | |||||
background-color: #af4040; | |||||
color: #ffff00; | |||||
height: 17px; | |||||
opacity: 0.8; | |||||
} | |||||
.ztree li a.curSelectedNode_Edit { | |||||
padding-top: 0px; | |||||
background-color: transparent; | |||||
color: #ffff00; | |||||
height: 17px; | |||||
border: 1px #666 solid; | |||||
opacity: 0.8; | |||||
} | |||||
.ztree li a.tmpTargetNode_inner { | |||||
padding-top: 0px; | |||||
background-color: #aaa; | |||||
color: #ffff00; | |||||
height: 17px; | |||||
border: 1px #666 solid; | |||||
opacity: 0.8; | |||||
filter: alpha(opacity=80); | |||||
} | |||||
.ztree li span { | |||||
line-height: 17px; | |||||
margin-right: 2px; | |||||
background-color: transparent; | |||||
} | |||||
.ztree li span.button { | |||||
line-height: 0; | |||||
margin: 0; | |||||
padding: 0; | |||||
width: 15px; | |||||
height: 17px; | |||||
display: inline-block; | |||||
vertical-align: top; | |||||
border: 0px solid; | |||||
cursor: pointer; | |||||
outline: none; | |||||
background-color: transparent; | |||||
background-repeat: no-repeat; | |||||
background-attachment: scroll; | |||||
} | |||||
.ztree li span.button::before { | |||||
color: #ffffff; | |||||
font-family: FontAwesome; | |||||
padding-top: 10px; | |||||
} | |||||
.ztree li span.button.chk { | |||||
margin: 0px; | |||||
cursor: auto; | |||||
width: 12px; | |||||
display: inline-block; | |||||
padding-top: 10px; | |||||
padding-left: 2px; | |||||
} | |||||
.ztree li span.button.chk.checkbox_false_full::before { | |||||
content: "\f096"; | |||||
} | |||||
.ztree li span.button.chk.checkbox_false_full_focus::before { | |||||
content: "\f096"; | |||||
color: #ffff00; | |||||
} | |||||
.ztree li span.button.chk.checkbox_false_part::before { | |||||
content: "\f096"; | |||||
color: #aaaaaa; | |||||
} | |||||
.ztree li span.button.chk.checkbox_false_part_focus::before { | |||||
content: "\f096"; | |||||
color: #cad96c; | |||||
} | |||||
.ztree li span.button.chk.checkbox_false_disable::before { | |||||
content: "\f096"; | |||||
color: #808080; | |||||
} | |||||
.ztree li span.button.chk.checkbox_true_full::before { | |||||
content: "\f046"; | |||||
} | |||||
.ztree li span.button.chk.checkbox_true_full_focus::before { | |||||
content: "\f046"; | |||||
} | |||||
.ztree li span.button.chk.checkbox_true_part::before { | |||||
content: "\f14a"; | |||||
} | |||||
.ztree li span.button.chk.checkbox_true_part_focus::before { | |||||
content: "\f14a"; | |||||
color: #ffff00; | |||||
} | |||||
.ztree li span.button.chk.checkbox_true_full_focus::before { | |||||
content: "\f046"; | |||||
color: #ffff00; | |||||
} | |||||
.ztree li span.button.chk.checkbox_true_part::before { | |||||
content: "\f046"; | |||||
color: #aaaaaa; | |||||
} | |||||
.ztree li span.button.chk.checkbox_true_part_focus::before { | |||||
content: "\f046"; | |||||
color: #cad96c; | |||||
} | |||||
.ztree li span.button.chk.checkbox_true_disable::before { | |||||
content: "\f046"; | |||||
color: #808080; | |||||
} | |||||
.ztree li span.button.chk.radio_false_full::before { | |||||
content: "\f10c"; | |||||
} | |||||
.ztree li span.button.chk.radio_false_full_focus::before { | |||||
content: "\f10c"; | |||||
color: #ffff00; | |||||
} | |||||
.ztree li span.button.chk.radio_false_part::before { | |||||
content: "\f10c"; | |||||
color: #aaaaaa; | |||||
} | |||||
.ztree li span.button.chk.radio_false_part_focus::before { | |||||
content: "\f10c"; | |||||
color: #ffff00; | |||||
} | |||||
.ztree li span.button.chk.radio_false_disable::before { | |||||
content: "\f1db"; | |||||
color: #808080; | |||||
} | |||||
.ztree li span.button.chk.radio_true_full::before { | |||||
content: "\f192"; | |||||
} | |||||
.ztree li span.button.chk.radio_true_full_focus::before { | |||||
content: "\f192"; | |||||
color: #ffff00; | |||||
} | |||||
.ztree li span.button.chk.radio_true_part::before { | |||||
content: "\f192"; | |||||
color: #aaaaaa; | |||||
} | |||||
.ztree li span.button.chk.radio_true_part_focus::before { | |||||
content: "\f192"; | |||||
color: #aaaaaa; | |||||
} | |||||
.ztree li span.button.chk.radio_true_disable::before { | |||||
content: "\f1db"; | |||||
color: #808080; | |||||
} | |||||
.ztree li span.button.switch { | |||||
width: 15px; | |||||
height: 17px; | |||||
} | |||||
.ztree li span.button.root_open::before { | |||||
content: "\f078"; | |||||
padding-top: 10px; | |||||
padding-left: 2px; | |||||
display: inline-block; | |||||
} | |||||
.ztree li span.button.root_close::before { | |||||
content: "\f054"; | |||||
padding-top: 10px; | |||||
padding-left: 2px; | |||||
display: inline-block; | |||||
} | |||||
.ztree li span.button.roots_open::before { | |||||
content: "\f078"; | |||||
padding-top: 10px; | |||||
padding-left: 2px; | |||||
display: inline-block; | |||||
} | |||||
.ztree li span.button.roots_close::before { | |||||
content: "\f054"; | |||||
padding-top: 10px; | |||||
padding-left: 2px; | |||||
display: inline-block; | |||||
} | |||||
.ztree li span.button.center_open::before { | |||||
content: "\f078"; | |||||
padding-top: 10px; | |||||
padding-left: 2px; | |||||
display: inline-block; | |||||
} | |||||
.ztree li span.button.center_close::before { | |||||
content: "\f054"; | |||||
padding-top: 10px; | |||||
padding-left: 2px; | |||||
display: inline-block; | |||||
} | |||||
.ztree li span.button.bottom_open::before { | |||||
content: "\f078"; | |||||
padding-top: 10px; | |||||
padding-left: 2px; | |||||
display: inline-block; | |||||
} | |||||
.ztree li span.button.bottom_close::before { | |||||
content: "\f054"; | |||||
padding-top: 10px; | |||||
padding-left: 2px; | |||||
display: inline-block; | |||||
} | |||||
.ztree li span.button.root_docu { | |||||
background: none; | |||||
} | |||||
.ztree li span.button.roots_docu::before { | |||||
content: "\f022"; | |||||
padding-left: 2px; | |||||
display: inline-block; | |||||
color: #ffffff; | |||||
} | |||||
.ztree li span.button.center_docu::before { | |||||
padding-top: 10px; | |||||
padding-left: 2px; | |||||
display: inline-block; | |||||
color: #ffffff; | |||||
} | |||||
.ztree li span.button.bottom_docu::before { | |||||
padding-top: 10px; | |||||
padding-left: 2px; | |||||
display: inline-block; | |||||
color: #ffffff; | |||||
} | |||||
.ztree li span.button.noline_docu { | |||||
background: none; | |||||
} | |||||
.ztree li span.button.ico_open::before { | |||||
content: "\f115"; | |||||
font-family: FontAwesome; | |||||
padding-top: 10px; | |||||
padding-left: 2px; | |||||
display: inline-block; | |||||
color: #ffffff; | |||||
} | |||||
.ztree li span.button.ico_close::before { | |||||
content: "\f114"; | |||||
font-family: FontAwesome; | |||||
padding-top: 10px; | |||||
padding-left: 2px; | |||||
display: inline-block; | |||||
color: #ffffff; | |||||
} | |||||
.ztree li span.button.ico_docu::before { | |||||
content: "\f022"; | |||||
font-family: FontAwesome; | |||||
padding-top: 10px; | |||||
padding-left: 2px; | |||||
display: inline-block; | |||||
color: #ffffff; | |||||
} | |||||
.ztree li span.button.edit { | |||||
margin-left: 4px; | |||||
margin-right: -1px; | |||||
vertical-align: top; | |||||
*vertical-align: middle; | |||||
padding-top: 10px; | |||||
} | |||||
.ztree li span.button.edit::before { | |||||
content: "\f044"; | |||||
font-family: FontAwesome; | |||||
} | |||||
.ztree li span.button.remove { | |||||
margin-left: 4px; | |||||
margin-right: -1px; | |||||
vertical-align: top; | |||||
*vertical-align: middle; | |||||
padding-top: 10px; | |||||
} | |||||
.ztree li span.button.remove::before { | |||||
content: "\f1f8"; | |||||
font-family: FontAwesome; | |||||
} | |||||
.ztree li span.button.add { | |||||
margin-left: 4px; | |||||
margin-right: -1px; | |||||
vertical-align: top; | |||||
*vertical-align: middle; | |||||
padding-top: 10px; | |||||
} | |||||
.ztree li span.button.add::before { | |||||
content: "\f067"; | |||||
font-family: FontAwesome; | |||||
} | |||||
.ztree li span.button.ico_loading { | |||||
margin-right: 2px; | |||||
background: url(./img/loading.gif) no-repeat scroll 0 0 transparent; | |||||
vertical-align: top; | |||||
*vertical-align: middle; | |||||
} | |||||
ul.tmpTargetzTree { | |||||
background-color: #FFE6B0; | |||||
opacity: 0.8; | |||||
filter: alpha(opacity=80); | |||||
} | |||||
span.tmpzTreeMove_arrow { | |||||
width: 16px; | |||||
height: 17px; | |||||
display: inline-block; | |||||
padding: 0; | |||||
margin: 2px 0 0 1px; | |||||
border: 0 none; | |||||
position: absolute; | |||||
background-color: transparent; | |||||
background-attachment: scroll; | |||||
} | |||||
span.tmpzTreeMove_arrow::before { | |||||
content: "\f04b"; | |||||
font-family: FontAwesome; | |||||
color: #ffff00; | |||||
} | |||||
ul.ztree.zTreeDragUL { | |||||
margin: 0; | |||||
padding: 0; | |||||
position: absolute; | |||||
width: auto; | |||||
height: auto; | |||||
overflow: hidden; | |||||
background-color: #cfcfcf; | |||||
border: 1px #ffff00 dotted; | |||||
opacity: 0.8; | |||||
filter: alpha(opacity=80); | |||||
} | |||||
.ztreeMask { | |||||
z-index: 10000; | |||||
background-color: #cfcfcf; | |||||
opacity: 0.0; | |||||
filter: alpha(opacity=0); | |||||
position: absolute; | |||||
} |
@@ -0,0 +1,146 @@ | |||||
/*------------------------------------- | |||||
zTree Style using fontawesome instead of images | |||||
version: 1.1 | |||||
author: Mike King | |||||
email: mikkelking @ hotmail . com | |||||
website: http://code.google.com/p/jquerytree/ | |||||
-------------------------------------*/ | |||||
/* Definitions ----------------------*/ | |||||
@font-size: 12px; | |||||
// Regular icon and text color is white, which suits any medium -> dark background | |||||
@color-normal: white; | |||||
// Background color | |||||
@color-bg: #af0000; | |||||
// Highlight color | |||||
@color-highlight: yellow; | |||||
// Partially selected (checkboxes, radio buttons) | |||||
@color-partial: #aaaaaa; | |||||
// Partially selected and focused (checkboxes, radio buttons) | |||||
@color-partfocus: #cad96c; | |||||
// Disabled altogether | |||||
@color-disabled: #808080; | |||||
// Editing color | |||||
@color-edit: yellow; | |||||
@w: 15px; | |||||
@h: 17px; | |||||
@pad-left: 2px; | |||||
@pad-top: 10px; | |||||
/* End of Definitions ---------------*/ | |||||
/* Imports -------------------------*/ | |||||
@import "fa.less"; | |||||
/* End of Imports ------------------*/ | |||||
.ztree * {padding:0; margin:0; font-size:@font-size; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif; background-color: @color-bg;} | |||||
.ztree { | |||||
margin:0; padding:5px; color:@color-normal; background-color: @color-bg; | |||||
li { | |||||
padding:0; margin:0; list-style:none; line-height:17px; text-align:left; white-space:nowrap; outline:0; | |||||
ul { | |||||
margin: 0px; padding:0 0 0 18px; | |||||
} | |||||
ul.line { } | |||||
a {padding-right:3px; margin:0; cursor:pointer; height:@h; color:@color-normal; background-color: transparent; | |||||
text-decoration:none; vertical-align:top; display: inline-block; | |||||
input.rename {height:14px; width:80px; padding:0; margin:0; | |||||
color: @color-bg; background-color: @color-normal; | |||||
font-size:@font-size; border:1px #585956 solid; *border:0px} | |||||
} | |||||
a:hover {text-decoration:underline} | |||||
a.curSelectedNode {padding-top:0px; background-color:#af4040; color:@color-highlight; height:@h; opacity:0.8;} | |||||
a.curSelectedNode_Edit {padding-top:0px; background-color:transparent; color:@color-highlight; height:@h; border:1px #666 solid; opacity:0.8;} | |||||
a.tmpTargetNode_inner {padding-top:0px; background-color:#aaa; color:@color-highlight; height:@h; border:1px #666 solid; | |||||
opacity:0.8; filter:alpha(opacity=80)} | |||||
a.tmpTargetNode_prev {} | |||||
a.tmpTargetNode_next {} | |||||
span {line-height:@h; margin-right:2px; background-color:transparent;} | |||||
span.button {line-height:0; margin:0; padding: 0; width:@w; height:@h; display: inline-block; vertical-align:top; | |||||
border:0px solid; cursor: pointer;outline:none; | |||||
background-color:transparent; background-repeat:no-repeat; background-attachment: scroll; | |||||
&::before{color: @color-normal; font-family: FontAwesome; padding-top:@pad-top;} | |||||
&.chk { margin:0px; cursor: auto; width: 12px; | |||||
display: inline-block;padding-top:@pad-top;padding-left:@pad-left; | |||||
&.checkbox_false_full::before {content: @fa-square-o;} | |||||
&.checkbox_false_full_focus::before {content: @fa-square-o; color:@color-highlight;} | |||||
&.checkbox_false_part::before {content: @fa-square-o;color: @color-partial;} | |||||
&.checkbox_false_part_focus::before {content: @fa-square-o; color:@color-partfocus;} | |||||
&.checkbox_false_disable::before {content: @fa-square-o; color:@color-disabled;} | |||||
&.checkbox_true_full::before {content: @fa-check-square-o;} | |||||
&.checkbox_true_full_focus::before {content: @fa-check-square-o;} | |||||
&.checkbox_true_part::before {content: @fa-check-square;} | |||||
&.checkbox_true_part_focus::before {content: @fa-check-square; color: @color-highlight} | |||||
&.checkbox_true_full_focus::before {content: @fa-check-square-o; color: @color-highlight} | |||||
&.checkbox_true_part::before {content: @fa-check-square-o;color: @color-partial} | |||||
&.checkbox_true_part_focus::before {content: @fa-check-square-o;color: @color-partfocus;} | |||||
&.checkbox_true_disable::before {content: @fa-check-square-o;color: @color-disabled} | |||||
&.radio_false_full::before {content: @fa-circle-o;} | |||||
&.radio_false_full_focus::before {content: @fa-circle-o;color: @color-highlight} | |||||
&.radio_false_part::before {content: @fa-circle-o;color: @color-partial} | |||||
&.radio_false_part_focus::before {content: @fa-circle-o;color: @color-highlight} | |||||
&.radio_false_disable::before {content: @fa-circle-thin;color: @color-disabled} | |||||
&.radio_true_full::before {content: @fa-dot-circle-o;} | |||||
&.radio_true_full_focus::before {content: @fa-dot-circle-o;color: @color-highlight} | |||||
&.radio_true_part::before {content: @fa-dot-circle-o;color: @color-partial} | |||||
&.radio_true_part_focus::before {content: @fa-dot-circle-o;color: @color-partial;} | |||||
&.radio_true_disable::before {content: @fa-circle-thin;color: @color-disabled} | |||||
} | |||||
&.switch {width:@w; height:@h} | |||||
&.root_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||||
&.root_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||||
&.roots_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||||
&.roots_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||||
&.center_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||||
&.center_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||||
&.bottom_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||||
&.bottom_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||||
&.noline_open{} | |||||
&.noline_close{} | |||||
&.root_docu{ background:none;} | |||||
&.roots_docu::before{content: @fa-list-alt;padding-left:@pad-left;display: inline-block;color:@color-normal;} | |||||
&.center_docu::before{padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} | |||||
&.bottom_docu::before{padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} | |||||
&.noline_docu{ background:none;} | |||||
&.ico_open::before {content: @fa-folder-open-o;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} | |||||
&.ico_close::before {content: @fa-folder-o;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} | |||||
&.ico_docu::before{content: @fa-list-alt;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} | |||||
&.edit {margin-left:4px; margin-right: -1px; vertical-align:top; *vertical-align:middle;padding-top:@pad-top;} | |||||
&.edit::before{content: @fa-pencil-square-o;font-family: FontAwesome;} | |||||
&.remove {margin-left:4px; margin-right: -1px; vertical-align:top; *vertical-align:middle;padding-top:@pad-top;} | |||||
&.remove::before{content: @fa-trash;font-family: FontAwesome;} | |||||
&.add {margin-left:4px; margin-right: -1px; vertical-align:top; *vertical-align:middle;padding-top:@pad-top;} | |||||
&.add::before{content: @fa-plus;font-family: FontAwesome;} | |||||
&.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle} | |||||
} | |||||
} | |||||
} | |||||
ul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)} | |||||
// this is the arrow that moves | |||||
span.tmpzTreeMove_arrow{width:16px; height:@h; display: inline-block; | |||||
padding:0; margin:2px 0 0 1px; border:0 none; position:absolute; | |||||
background-color:transparent; background-attachment: scroll; | |||||
} | |||||
span.tmpzTreeMove_arrow::before{content: @fa-play;font-family: FontAwesome;color: @color-highlight; | |||||
} | |||||
// outline | |||||
ul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; | |||||
background-color:#cfcfcf; border:1px @color-highlight dotted; opacity:0.8; filter:alpha(opacity=80)} | |||||
.ztreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute} | |||||
@@ -0,0 +1,480 @@ | |||||
@fa-glass: "\f000"; | |||||
@fa-music: "\f001"; | |||||
@fa-search: "\f002"; | |||||
@fa-envelope-o: "\f003"; | |||||
@fa-heart: "\f004"; | |||||
@fa-star: "\f005"; | |||||
@fa-star-o: "\f006"; | |||||
@fa-user: "\f007"; | |||||
@fa-film: "\f008"; | |||||
@fa-th-large: "\f009"; | |||||
@fa-th: "\f00a"; | |||||
@fa-th-list: "\f00b"; | |||||
@fa-check: "\f00c"; | |||||
@fa-times: "\f00d"; | |||||
@fa-search-plus: "\f00e"; | |||||
@fa-search-minus: "\f010"; | |||||
@fa-power-off: "\f011"; | |||||
@fa-signal: "\f012"; | |||||
@fa-cog: "\f013"; | |||||
@fa-trash-o: "\f014"; | |||||
@fa-home: "\f015"; | |||||
@fa-file-o: "\f016"; | |||||
@fa-clock-o: "\f017"; | |||||
@fa-road: "\f018"; | |||||
@fa-download: "\f019"; | |||||
@fa-arrow-circle-o-down: "\f01a"; | |||||
@fa-arrow-circle-o-up: "\f01b"; | |||||
@fa-inbox: "\f01c"; | |||||
@fa-play-circle-o: "\f01d"; | |||||
@fa-repeat: "\f01e"; | |||||
@fa-refresh: "\f021"; | |||||
@fa-list-alt: "\f022"; | |||||
@fa-lock: "\f023"; | |||||
@fa-flag: "\f024"; | |||||
@fa-headphones: "\f025"; | |||||
@fa-volume-off: "\f026"; | |||||
@fa-volume-down: "\f027"; | |||||
@fa-volume-up: "\f028"; | |||||
@fa-qrcode: "\f029"; | |||||
@fa-barcode: "\f02a"; | |||||
@fa-tag: "\f02b"; | |||||
@fa-tags: "\f02c"; | |||||
@fa-book: "\f02d"; | |||||
@fa-bookmark: "\f02e"; | |||||
@fa-print: "\f02f"; | |||||
@fa-camera: "\f030"; | |||||
@fa-font: "\f031"; | |||||
@fa-bold: "\f032"; | |||||
@fa-italic: "\f033"; | |||||
@fa-text-height: "\f034"; | |||||
@fa-text-width: "\f035"; | |||||
@fa-align-left: "\f036"; | |||||
@fa-align-center: "\f037"; | |||||
@fa-align-right: "\f038"; | |||||
@fa-align-justify: "\f039"; | |||||
@fa-list: "\f03a"; | |||||
@fa-outdent: "\f03b"; | |||||
@fa-indent: "\f03c"; | |||||
@fa-video-camera: "\f03d"; | |||||
@fa-picture-o: "\f03e"; | |||||
@fa-pencil: "\f040"; | |||||
@fa-map-marker: "\f041"; | |||||
@fa-adjust: "\f042"; | |||||
@fa-tint: "\f043"; | |||||
@fa-pencil-square-o: "\f044"; | |||||
@fa-share-square-o: "\f045"; | |||||
@fa-check-square-o: "\f046"; | |||||
@fa-arrows: "\f047"; | |||||
@fa-step-backward: "\f048"; | |||||
@fa-fast-backward: "\f049"; | |||||
@fa-backward: "\f04a"; | |||||
@fa-play: "\f04b"; | |||||
@fa-pause: "\f04c"; | |||||
@fa-stop: "\f04d"; | |||||
@fa-forward: "\f04e"; | |||||
@fa-fast-forward: "\f050"; | |||||
@fa-step-forward: "\f051"; | |||||
@fa-eject: "\f052"; | |||||
@fa-chevron-left: "\f053"; | |||||
@fa-chevron-right: "\f054"; | |||||
@fa-plus-circle: "\f055"; | |||||
@fa-minus-circle: "\f056"; | |||||
@fa-times-circle: "\f057"; | |||||
@fa-check-circle: "\f058"; | |||||
@fa-question-circle: "\f059"; | |||||
@fa-info-circle: "\f05a"; | |||||
@fa-crosshairs: "\f05b"; | |||||
@fa-times-circle-o: "\f05c"; | |||||
@fa-check-circle-o: "\f05d"; | |||||
@fa-ban: "\f05e"; | |||||
@fa-arrow-left: "\f060"; | |||||
@fa-arrow-right: "\f061"; | |||||
@fa-arrow-up: "\f062"; | |||||
@fa-arrow-down: "\f063"; | |||||
@fa-share: "\f064"; | |||||
@fa-expand: "\f065"; | |||||
@fa-compress: "\f066"; | |||||
@fa-plus: "\f067"; | |||||
@fa-minus: "\f068"; | |||||
@fa-asterisk: "\f069"; | |||||
@fa-exclamation-circle: "\f06a"; | |||||
@fa-gift: "\f06b"; | |||||
@fa-leaf: "\f06c"; | |||||
@fa-fire: "\f06d"; | |||||
@fa-eye: "\f06e"; | |||||
@fa-eye-slash: "\f070"; | |||||
@fa-exclamation-triangle: "\f071"; | |||||
@fa-plane: "\f072"; | |||||
@fa-calendar: "\f073"; | |||||
@fa-random: "\f074"; | |||||
@fa-comment: "\f075"; | |||||
@fa-magnet: "\f076"; | |||||
@fa-chevron-up: "\f077"; | |||||
@fa-chevron-down: "\f078"; | |||||
@fa-retweet: "\f079"; | |||||
@fa-shopping-cart: "\f07a"; | |||||
@fa-folder: "\f07b"; | |||||
@fa-folder-open: "\f07c"; | |||||
@fa-arrows-v: "\f07d"; | |||||
@fa-arrows-h: "\f07e"; | |||||
@fa-bar-chart: "\f080"; | |||||
@fa-twitter-square: "\f081"; | |||||
@fa-facebook-square: "\f082"; | |||||
@fa-camera-retro: "\f083"; | |||||
@fa-key: "\f084"; | |||||
@fa-cogs: "\f085"; | |||||
@fa-comments: "\f086"; | |||||
@fa-thumbs-o-up: "\f087"; | |||||
@fa-thumbs-o-down: "\f088"; | |||||
@fa-star-half: "\f089"; | |||||
@fa-heart-o: "\f08a"; | |||||
@fa-sign-out: "\f08b"; | |||||
@fa-linkedin-square: "\f08c"; | |||||
@fa-thumb-tack: "\f08d"; | |||||
@fa-external-link: "\f08e"; | |||||
@fa-sign-in: "\f090"; | |||||
@fa-trophy: "\f091"; | |||||
@fa-github-square: "\f092"; | |||||
@fa-upload: "\f093"; | |||||
@fa-lemon-o: "\f094"; | |||||
@fa-phone: "\f095"; | |||||
@fa-square-o: "\f096"; | |||||
@fa-bookmark-o: "\f097"; | |||||
@fa-phone-square: "\f098"; | |||||
@fa-twitter: "\f099"; | |||||
@fa-facebook: "\f09a"; | |||||
@fa-github: "\f09b"; | |||||
@fa-unlock: "\f09c"; | |||||
@fa-credit-card: "\f09d"; | |||||
@fa-rss: "\f09e"; | |||||
@fa-hdd-o: "\f0a0"; | |||||
@fa-bullhorn: "\f0a1"; | |||||
@fa-bell: "\f0f3"; | |||||
@fa-certificate: "\f0a3"; | |||||
@fa-hand-o-right: "\f0a4"; | |||||
@fa-hand-o-left: "\f0a5"; | |||||
@fa-hand-o-up: "\f0a6"; | |||||
@fa-hand-o-down: "\f0a7"; | |||||
@fa-arrow-circle-left: "\f0a8"; | |||||
@fa-arrow-circle-right: "\f0a9"; | |||||
@fa-arrow-circle-up: "\f0aa"; | |||||
@fa-arrow-circle-down: "\f0ab"; | |||||
@fa-globe: "\f0ac"; | |||||
@fa-wrench: "\f0ad"; | |||||
@fa-tasks: "\f0ae"; | |||||
@fa-filter: "\f0b0"; | |||||
@fa-briefcase: "\f0b1"; | |||||
@fa-arrows-alt: "\f0b2"; | |||||
@fa-users: "\f0c0"; | |||||
@fa-link: "\f0c1"; | |||||
@fa-cloud: "\f0c2"; | |||||
@fa-flask: "\f0c3"; | |||||
@fa-scissors: "\f0c4"; | |||||
@fa-files-o: "\f0c5"; | |||||
@fa-paperclip: "\f0c6"; | |||||
@fa-floppy-o: "\f0c7"; | |||||
@fa-square: "\f0c8"; | |||||
@fa-bars: "\f0c9"; | |||||
@fa-list-ul: "\f0ca"; | |||||
@fa-list-ol: "\f0cb"; | |||||
@fa-strikethrough: "\f0cc"; | |||||
@fa-underline: "\f0cd"; | |||||
@fa-table: "\f0ce"; | |||||
@fa-magic: "\f0d0"; | |||||
@fa-truck: "\f0d1"; | |||||
@fa-pinterest: "\f0d2"; | |||||
@fa-pinterest-square: "\f0d3"; | |||||
@fa-google-plus-square: "\f0d4"; | |||||
@fa-google-plus: "\f0d5"; | |||||
@fa-money: "\f0d6"; | |||||
@fa-caret-down: "\f0d7"; | |||||
@fa-caret-up: "\f0d8"; | |||||
@fa-caret-left: "\f0d9"; | |||||
@fa-caret-right: "\f0da"; | |||||
@fa-columns: "\f0db"; | |||||
@fa-sort: "\f0dc"; | |||||
@fa-sort-desc: "\f0dd"; | |||||
@fa-sort-asc: "\f0de"; | |||||
@fa-envelope: "\f0e0"; | |||||
@fa-linkedin: "\f0e1"; | |||||
@fa-undo: "\f0e2"; | |||||
@fa-gavel: "\f0e3"; | |||||
@fa-tachometer: "\f0e4"; | |||||
@fa-comment-o: "\f0e5"; | |||||
@fa-comments-o: "\f0e6"; | |||||
@fa-bolt: "\f0e7"; | |||||
@fa-sitemap: "\f0e8"; | |||||
@fa-umbrella: "\f0e9"; | |||||
@fa-clipboard: "\f0ea"; | |||||
@fa-lightbulb-o: "\f0eb"; | |||||
@fa-exchange: "\f0ec"; | |||||
@fa-cloud-download: "\f0ed"; | |||||
@fa-cloud-upload: "\f0ee"; | |||||
@fa-user-md: "\f0f0"; | |||||
@fa-stethoscope: "\f0f1"; | |||||
@fa-suitcase: "\f0f2"; | |||||
@fa-bell-o: "\f0a2"; | |||||
@fa-coffee: "\f0f4"; | |||||
@fa-cutlery: "\f0f5"; | |||||
@fa-file-text-o: "\f0f6"; | |||||
@fa-building-o: "\f0f7"; | |||||
@fa-hospital-o: "\f0f8"; | |||||
@fa-ambulance: "\f0f9"; | |||||
@fa-medkit: "\f0fa"; | |||||
@fa-fighter-jet: "\f0fb"; | |||||
@fa-beer: "\f0fc"; | |||||
@fa-h-square: "\f0fd"; | |||||
@fa-plus-square: "\f0fe"; | |||||
@fa-angle-double-left: "\f100"; | |||||
@fa-angle-double-right: "\f101"; | |||||
@fa-angle-double-up: "\f102"; | |||||
@fa-angle-double-down: "\f103"; | |||||
@fa-angle-left: "\f104"; | |||||
@fa-angle-right: "\f105"; | |||||
@fa-angle-up: "\f106"; | |||||
@fa-angle-down: "\f107"; | |||||
@fa-desktop: "\f108"; | |||||
@fa-laptop: "\f109"; | |||||
@fa-tablet: "\f10a"; | |||||
@fa-mobile: "\f10b"; | |||||
@fa-circle-o: "\f10c"; | |||||
@fa-quote-left: "\f10d"; | |||||
@fa-quote-right: "\f10e"; | |||||
@fa-spinner: "\f110"; | |||||
@fa-circle: "\f111"; | |||||
@fa-reply: "\f112"; | |||||
@fa-github-alt: "\f113"; | |||||
@fa-folder-o: "\f114"; | |||||
@fa-folder-open-o: "\f115"; | |||||
@fa-smile-o: "\f118"; | |||||
@fa-frown-o: "\f119"; | |||||
@fa-meh-o: "\f11a"; | |||||
@fa-gamepad: "\f11b"; | |||||
@fa-keyboard-o: "\f11c"; | |||||
@fa-flag-o: "\f11d"; | |||||
@fa-flag-checkered: "\f11e"; | |||||
@fa-terminal: "\f120"; | |||||
@fa-code: "\f121"; | |||||
@fa-reply-all: "\f122"; | |||||
@fa-star-half-o: "\f123"; | |||||
@fa-location-arrow: "\f124"; | |||||
@fa-crop: "\f125"; | |||||
@fa-code-fork: "\f126"; | |||||
@fa-chain-broken: "\f127"; | |||||
@fa-question: "\f128"; | |||||
@fa-info: "\f129"; | |||||
@fa-exclamation: "\f12a"; | |||||
@fa-superscript: "\f12b"; | |||||
@fa-subscript: "\f12c"; | |||||
@fa-eraser: "\f12d"; | |||||
@fa-puzzle-piece: "\f12e"; | |||||
@fa-microphone: "\f130"; | |||||
@fa-microphone-slash: "\f131"; | |||||
@fa-shield: "\f132"; | |||||
@fa-calendar-o: "\f133"; | |||||
@fa-fire-extinguisher: "\f134"; | |||||
@fa-rocket: "\f135"; | |||||
@fa-maxcdn: "\f136"; | |||||
@fa-chevron-circle-left: "\f137"; | |||||
@fa-chevron-circle-right: "\f138"; | |||||
@fa-chevron-circle-up: "\f139"; | |||||
@fa-chevron-circle-down: "\f13a"; | |||||
@fa-html5: "\f13b"; | |||||
@fa-css3: "\f13c"; | |||||
@fa-anchor: "\f13d"; | |||||
@fa-unlock-alt: "\f13e"; | |||||
@fa-bullseye: "\f140"; | |||||
@fa-ellipsis-h: "\f141"; | |||||
@fa-ellipsis-v: "\f142"; | |||||
@fa-rss-square: "\f143"; | |||||
@fa-play-circle: "\f144"; | |||||
@fa-ticket: "\f145"; | |||||
@fa-minus-square: "\f146"; | |||||
@fa-minus-square-o: "\f147"; | |||||
@fa-level-up: "\f148"; | |||||
@fa-level-down: "\f149"; | |||||
@fa-check-square: "\f14a"; | |||||
@fa-pencil-square: "\f14b"; | |||||
@fa-external-link-square: "\f14c"; | |||||
@fa-share-square: "\f14d"; | |||||
@fa-compass: "\f14e"; | |||||
@fa-caret-square-o-down: "\f150"; | |||||
@fa-caret-square-o-up: "\f151"; | |||||
@fa-caret-square-o-right: "\f152"; | |||||
@fa-eur: "\f153"; | |||||
@fa-gbp: "\f154"; | |||||
@fa-usd: "\f155"; | |||||
@fa-inr: "\f156"; | |||||
@fa-jpy: "\f157"; | |||||
@fa-rub: "\f158"; | |||||
@fa-krw: "\f159"; | |||||
@fa-btc: "\f15a"; | |||||
@fa-file: "\f15b"; | |||||
@fa-file-text: "\f15c"; | |||||
@fa-sort-alpha-asc: "\f15d"; | |||||
@fa-sort-alpha-desc: "\f15e"; | |||||
@fa-sort-amount-asc: "\f160"; | |||||
@fa-sort-amount-desc: "\f161"; | |||||
@fa-sort-numeric-asc: "\f162"; | |||||
@fa-sort-numeric-desc: "\f163"; | |||||
@fa-thumbs-up: "\f164"; | |||||
@fa-thumbs-down: "\f165"; | |||||
@fa-youtube-square: "\f166"; | |||||
@fa-youtube: "\f167"; | |||||
@fa-xing: "\f168"; | |||||
@fa-xing-square: "\f169"; | |||||
@fa-youtube-play: "\f16a"; | |||||
@fa-dropbox: "\f16b"; | |||||
@fa-stack-overflow: "\f16c"; | |||||
@fa-instagram: "\f16d"; | |||||
@fa-flickr: "\f16e"; | |||||
@fa-adn: "\f170"; | |||||
@fa-bitbucket: "\f171"; | |||||
@fa-bitbucket-square: "\f172"; | |||||
@fa-tumblr: "\f173"; | |||||
@fa-tumblr-square: "\f174"; | |||||
@fa-long-arrow-down: "\f175"; | |||||
@fa-long-arrow-up: "\f176"; | |||||
@fa-long-arrow-left: "\f177"; | |||||
@fa-long-arrow-right: "\f178"; | |||||
@fa-apple: "\f179"; | |||||
@fa-windows: "\f17a"; | |||||
@fa-android: "\f17b"; | |||||
@fa-linux: "\f17c"; | |||||
@fa-dribbble: "\f17d"; | |||||
@fa-skype: "\f17e"; | |||||
@fa-foursquare: "\f180"; | |||||
@fa-trello: "\f181"; | |||||
@fa-female: "\f182"; | |||||
@fa-male: "\f183"; | |||||
@fa-gittip: "\f184"; | |||||
@fa-sun-o: "\f185"; | |||||
@fa-moon-o: "\f186"; | |||||
@fa-archive: "\f187"; | |||||
@fa-bug: "\f188"; | |||||
@fa-vk: "\f189"; | |||||
@fa-weibo: "\f18a"; | |||||
@fa-renren: "\f18b"; | |||||
@fa-pagelines: "\f18c"; | |||||
@fa-stack-exchange: "\f18d"; | |||||
@fa-arrow-circle-o-right: "\f18e"; | |||||
@fa-arrow-circle-o-left: "\f190"; | |||||
@fa-caret-square-o-left: "\f191"; | |||||
@fa-dot-circle-o: "\f192"; | |||||
@fa-wheelchair: "\f193"; | |||||
@fa-vimeo-square: "\f194"; | |||||
@fa-try: "\f195"; | |||||
@fa-plus-square-o: "\f196"; | |||||
@fa-space-shuttle: "\f197"; | |||||
@fa-slack: "\f198"; | |||||
@fa-envelope-square: "\f199"; | |||||
@fa-wordpress: "\f19a"; | |||||
@fa-openid: "\f19b"; | |||||
@fa-university: "\f19c"; | |||||
@fa-graduation-cap: "\f19d"; | |||||
@fa-yahoo: "\f19e"; | |||||
@fa-google: "\f1a0"; | |||||
@fa-reddit: "\f1a1"; | |||||
@fa-reddit-square: "\f1a2"; | |||||
@fa-stumbleupon-circle: "\f1a3"; | |||||
@fa-stumbleupon: "\f1a4"; | |||||
@fa-delicious: "\f1a5"; | |||||
@fa-digg: "\f1a6"; | |||||
@fa-pied-piper: "\f1a7"; | |||||
@fa-pied-piper-alt: "\f1a8"; | |||||
@fa-drupal: "\f1a9"; | |||||
@fa-joomla: "\f1aa"; | |||||
@fa-language: "\f1ab"; | |||||
@fa-fax: "\f1ac"; | |||||
@fa-building: "\f1ad"; | |||||
@fa-child: "\f1ae"; | |||||
@fa-paw: "\f1b0"; | |||||
@fa-spoon: "\f1b1"; | |||||
@fa-cube: "\f1b2"; | |||||
@fa-cubes: "\f1b3"; | |||||
@fa-behance: "\f1b4"; | |||||
@fa-behance-square: "\f1b5"; | |||||
@fa-steam: "\f1b6"; | |||||
@fa-steam-square: "\f1b7"; | |||||
@fa-recycle: "\f1b8"; | |||||
@fa-car: "\f1b9"; | |||||
@fa-taxi: "\f1ba"; | |||||
@fa-tree: "\f1bb"; | |||||
@fa-spotify: "\f1bc"; | |||||
@fa-deviantart: "\f1bd"; | |||||
@fa-soundcloud: "\f1be"; | |||||
@fa-database: "\f1c0"; | |||||
@fa-file-pdf-o: "\f1c1"; | |||||
@fa-file-word-o: "\f1c2"; | |||||
@fa-file-excel-o: "\f1c3"; | |||||
@fa-file-powerpoint-o: "\f1c4"; | |||||
@fa-file-image-o: "\f1c5"; | |||||
@fa-file-archive-o: "\f1c6"; | |||||
@fa-file-audio-o: "\f1c7"; | |||||
@fa-file-video-o: "\f1c8"; | |||||
@fa-file-code-o: "\f1c9"; | |||||
@fa-vine: "\f1ca"; | |||||
@fa-codepen: "\f1cb"; | |||||
@fa-jsfiddle: "\f1cc"; | |||||
@fa-life-ring: "\f1cd"; | |||||
@fa-circle-o-notch: "\f1ce"; | |||||
@fa-rebel: "\f1d0"; | |||||
@fa-empire: "\f1d1"; | |||||
@fa-git-square: "\f1d2"; | |||||
@fa-git: "\f1d3"; | |||||
@fa-hacker-news: "\f1d4"; | |||||
@fa-tencent-weibo: "\f1d5"; | |||||
@fa-qq: "\f1d6"; | |||||
@fa-weixin: "\f1d7"; | |||||
@fa-paper-plane: "\f1d8"; | |||||
@fa-paper-plane-o: "\f1d9"; | |||||
@fa-history: "\f1da"; | |||||
@fa-circle-thin: "\f1db"; | |||||
@fa-header: "\f1dc"; | |||||
@fa-paragraph: "\f1dd"; | |||||
@fa-sliders: "\f1de"; | |||||
@fa-share-alt: "\f1e0"; | |||||
@fa-share-alt-square: "\f1e1"; | |||||
@fa-bomb: "\f1e2"; | |||||
@fa-futbol-o: "\f1e3"; | |||||
@fa-tty: "\f1e4"; | |||||
@fa-binoculars: "\f1e5"; | |||||
@fa-plug: "\f1e6"; | |||||
@fa-slideshare: "\f1e7"; | |||||
@fa-twitch: "\f1e8"; | |||||
@fa-yelp: "\f1e9"; | |||||
@fa-newspaper-o: "\f1ea"; | |||||
@fa-wifi: "\f1eb"; | |||||
@fa-calculator: "\f1ec"; | |||||
@fa-paypal: "\f1ed"; | |||||
@fa-google-wallet: "\f1ee"; | |||||
@fa-cc-visa: "\f1f0"; | |||||
@fa-cc-mastercard: "\f1f1"; | |||||
@fa-cc-discover: "\f1f2"; | |||||
@fa-cc-amex: "\f1f3"; | |||||
@fa-cc-paypal: "\f1f4"; | |||||
@fa-cc-stripe: "\f1f5"; | |||||
@fa-bell-slash: "\f1f6"; | |||||
@fa-bell-slash-o: "\f1f7"; | |||||
@fa-trash: "\f1f8"; | |||||
@fa-copyright: "\f1f9"; | |||||
@fa-at: "\f1fa"; | |||||
@fa-eyedropper: "\f1fb"; | |||||
@fa-paint-brush: "\f1fc"; | |||||
@fa-birthday-cake: "\f1fd"; | |||||
@fa-area-chart: "\f1fe"; | |||||
@fa-pie-chart: "\f200"; | |||||
@fa-line-chart: "\f201"; | |||||
@fa-lastfm: "\f202"; | |||||
@fa-lastfm-square: "\f203"; | |||||
@fa-toggle-off: "\f204"; | |||||
@fa-toggle-on: "\f205"; | |||||
@fa-bicycle: "\f206"; | |||||
@fa-bus: "\f207"; | |||||
@fa-ioxhost: "\f208"; | |||||
@fa-angellist: "\f209"; | |||||
@fa-cc: "\f20a"; | |||||
@fa-ils: "\f20b"; | |||||
@fa-meanpath: "\f20c"; | |||||
@@ -0,0 +1,33 @@ | |||||
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { | |||||
margin: 0;padding: 0;border: 0;outline: 0;font-weight: inherit;font-style: inherit;font-size: 100%;font-family: inherit;vertical-align: baseline;} | |||||
body {color: #2f332a;font: 15px/21px Arial, Helvetica, simsun, sans-serif;background: #f0f6e4 \9;} | |||||
h1, h2, h3, h4, h5, h6 {color: #2f332a;font-weight: bold;font-family: Helvetica, Arial, sans-serif;padding-bottom: 5px;} | |||||
h1 {font-size: 24px;line-height: 34px;text-align: center;} | |||||
h2 {font-size: 14px;line-height: 24px;padding-top: 5px;} | |||||
h6 {font-weight: normal;font-size: 12px;letter-spacing: 1px;line-height: 24px;text-align: center;} | |||||
a {color:#3C6E31;text-decoration: underline;} | |||||
a:hover {background-color:#3C6E31;color:white;} | |||||
input.radio {margin: 0 2px 0 8px;} | |||||
input.radio.first {margin-left:0;} | |||||
input.empty {color: lightgray;} | |||||
code {color: #2f332a;} | |||||
.highlight_red {color:#A60000;} | |||||
.highlight_green {color:#A7F43D;} | |||||
li {list-style: circle;font-size: 12px;} | |||||
li.title {list-style: none;} | |||||
ul.list {margin-left: 17px;} | |||||
div.content_wrap {width: 600px;height:380px;} | |||||
div.content_wrap div.left{float: left;width: 250px;} | |||||
div.content_wrap div.right{float: right;width: 340px;} | |||||
div.zTreeDemoBackground {width:250px;height:362px;text-align:left;} | |||||
ul.ztree {margin-top: 10px;border: 1px solid #617775;background: #f0f6e4;width:220px;height:360px;overflow-y:scroll;overflow-x:auto;} | |||||
ul.log {border: 1px solid #617775;background: #f0f6e4;width:300px;height:170px;overflow: hidden;} | |||||
ul.log.small {height:45px;} | |||||
ul.log li {color: #666666;list-style: none;padding-left: 10px;} | |||||
ul.log li.dark {background-color: #E3E3E3;} | |||||
/* ruler */ | |||||
div.ruler {height:20px; width:220px; background-color:#f0f6e4;border: 1px solid #333; margin-bottom: 5px; cursor: pointer} | |||||
div.ruler div.cursor {height:20px; width:30px; background-color:#3C6E31; color:white; text-align: right; padding-right: 5px; cursor: pointer} |
@@ -0,0 +1,96 @@ | |||||
/*------------------------------------- | |||||
zTree Style | |||||
version: 3.4 | |||||
author: Hunter.z | |||||
email: hunter.z@263.net | |||||
website: http://code.google.com/p/jquerytree/ | |||||
-------------------------------------*/ | |||||
.ztree * {padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif} | |||||
.ztree {margin:0; padding:5px; color:#333} | |||||
.ztree li{padding:0; margin:0; list-style:none; line-height:17px; text-align:left; white-space:nowrap; outline:0} | |||||
.ztree li ul{ margin:0; padding:0 0 0 18px} | |||||
.ztree li ul.line{ background:url(./img/line_conn.png) 0 0 repeat-y;} | |||||
.ztree li a {padding-right:3px; margin:0; cursor:pointer; height:21px; color:#333; background-color: transparent; text-decoration:none; vertical-align:top; display: inline-block} | |||||
.ztree li a:hover {text-decoration:underline} | |||||
.ztree li a.curSelectedNode {padding-top:0px; background-color:#e5e5e5; color:black; height:21px; opacity:0.8;} | |||||
.ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#e5e5e5; color:black; height:21px; border:1px #666 solid; opacity:0.8;} | |||||
.ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#aaa; color:white; height:21px; border:1px #666 solid; | |||||
opacity:0.8; filter:alpha(opacity=80)} | |||||
.ztree li a.tmpTargetNode_prev {} | |||||
.ztree li a.tmpTargetNode_next {} | |||||
.ztree li a input.rename {height:14px; width:80px; padding:0; margin:0; | |||||
font-size:12px; border:1px #585956 solid; *border:0px} | |||||
.ztree li span {line-height:21px; margin-right:2px} | |||||
.ztree li span.button {line-height:0; margin:0; padding: 0; width:21px; height:21px; display: inline-block; vertical-align:middle; | |||||
border:0 none; cursor: pointer;outline:none; | |||||
background-color:transparent; background-repeat:no-repeat; background-attachment: scroll; | |||||
background-image:url("./img/metro.png"); *background-image:url("./img/metro.gif")} | |||||
.ztree li span.button.chk {width:13px; height:13px; margin:0 2px; cursor: auto} | |||||
.ztree li span.button.chk.checkbox_false_full {background-position: -5px -5px;} | |||||
.ztree li span.button.chk.checkbox_false_full_focus {background-position: -5px -26px;} | |||||
.ztree li span.button.chk.checkbox_false_part {background-position: -5px -48px;} | |||||
.ztree li span.button.chk.checkbox_false_part_focus {background-position: -5px -68px;} | |||||
.ztree li span.button.chk.checkbox_false_disable {background-position: -5px -89px;} | |||||
.ztree li span.button.chk.checkbox_true_full {background-position: -26px -5px;} | |||||
.ztree li span.button.chk.checkbox_true_full_focus {background-position: -26px -26px;} | |||||
.ztree li span.button.chk.checkbox_true_part {background-position: -26px -48px;} | |||||
.ztree li span.button.chk.checkbox_true_part_focus {background-position: -26px -68px;} | |||||
.ztree li span.button.chk.checkbox_true_disable {background-position: -26px -89px;} | |||||
.ztree li span.button.chk.radio_false_full {background-position: -47px -5px;} | |||||
.ztree li span.button.chk.radio_false_full_focus {background-position: -47px -26px;} | |||||
.ztree li span.button.chk.radio_false_part {background-position: -47px -47px;} | |||||
.ztree li span.button.chk.radio_false_part_focus {background-position: -47px -68px;} | |||||
.ztree li span.button.chk.radio_false_disable {background-position: -47px -89px;} | |||||
.ztree li span.button.chk.radio_true_full {background-position: -68px -5px;} | |||||
.ztree li span.button.chk.radio_true_full_focus {background-position: -68px -26px;} | |||||
.ztree li span.button.chk.radio_true_part {background-position: -68px -47px;} | |||||
.ztree li span.button.chk.radio_true_part_focus {background-position: -68px -68px;} | |||||
.ztree li span.button.chk.radio_true_disable {background-position: -68px -89px;} | |||||
.ztree li span.button.switch {width:21px; height:21px} | |||||
.ztree li span.button.root_open{background-position:-105px -63px} | |||||
.ztree li span.button.root_close{background-position:-126px -63px} | |||||
.ztree li span.button.roots_open{background-position: -105px 0;} | |||||
.ztree li span.button.roots_close{background-position: -126px 0;} | |||||
.ztree li span.button.center_open{background-position: -105px -21px;} | |||||
.ztree li span.button.center_close{background-position: -126px -21px;} | |||||
.ztree li span.button.bottom_open{background-position: -105px -42px;} | |||||
.ztree li span.button.bottom_close{background-position: -126px -42px;} | |||||
.ztree li span.button.noline_open{background-position: -105px -84px;} | |||||
.ztree li span.button.noline_close{background-position: -126px -84px;} | |||||
.ztree li span.button.root_docu{ background:none;} | |||||
.ztree li span.button.roots_docu{background-position: -84px 0;} | |||||
.ztree li span.button.center_docu{background-position: -84px -21px;} | |||||
.ztree li span.button.bottom_docu{background-position: -84px -42px;} | |||||
.ztree li span.button.noline_docu{ background:none;} | |||||
.ztree li span.button.ico_open{margin-right:2px; background-position: -147px -21px; vertical-align:top; *vertical-align:middle} | |||||
.ztree li span.button.ico_close{margin-right:2px; margin-right:2px; background-position: -147px 0; vertical-align:top; *vertical-align:middle} | |||||
.ztree li span.button.ico_docu{margin-right:2px; background-position: -147px -42px; vertical-align:top; *vertical-align:middle} | |||||
.ztree li span.button.edit {margin-left:2px; margin-right: -1px; background-position: -189px -21px; vertical-align:top; *vertical-align:middle} | |||||
.ztree li span.button.edit:hover { | |||||
background-position: -168px -21px; | |||||
} | |||||
.ztree li span.button.remove {margin-left:2px; margin-right: -1px; background-position: -189px -42px; vertical-align:top; *vertical-align:middle} | |||||
.ztree li span.button.remove:hover { | |||||
background-position: -168px -42px; | |||||
} | |||||
.ztree li span.button.add {margin-left:2px; margin-right: -1px; background-position: -189px 0; vertical-align:top; *vertical-align:middle} | |||||
.ztree li span.button.add:hover { | |||||
background-position: -168px 0; | |||||
} | |||||
.ztree li span.button.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle} | |||||
ul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)} | |||||
span.tmpzTreeMove_arrow {width:16px; height:21px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute; | |||||
background-color:transparent; background-repeat:no-repeat; background-attachment: scroll; | |||||
background-position:-168px -84px; background-image:url("./img/metro.png"); *background-image:url("./img/metro.gif")} | |||||
ul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)} | |||||
.ztreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute} |
@@ -0,0 +1,99 @@ | |||||
/*------------------------------------- | |||||
zTree Style | |||||
version: 3.5.19 | |||||
author: Hunter.z | |||||
email: hunter.z@263.net | |||||
website: http://code.google.com/p/jquerytree/ | |||||
-------------------------------------*/ | |||||
.ztree * {padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif} | |||||
.ztree {margin:0; padding:5px; color:#333;margin-top: 0; height: 100%; max-height: 400px; overflow-y: scroll;} | |||||
.ztree::-webkit-scrollbar-track{background-color: #FFF;} | |||||
.ztree li{padding:5px 0; margin:0; list-style:none; line-height:14px; text-align:left; white-space:nowrap; outline:0; position: relative;} | |||||
.ztree li ul{ margin:0; padding:0 0 0 18px} | |||||
/*.ztree li ul.line{ background:url(./img/line_conn.gif) 0 0 repeat-y;}*/ | |||||
.ztree li a {padding:1px 3px 0 0; margin:0; cursor:pointer; height:17px; color:#333; background-color: transparent; | |||||
text-decoration:none; vertical-align:top; display: inline-block} | |||||
.ztree li a:hover {text-decoration:none;} | |||||
.ztree li a:hover .node_name::after{content: '';position: absolute;left: 0;right: 0;top: 0;background-color: #f7f7f7;height: 100%;z-index: -1;} | |||||
.ztree li a.curSelectedNode {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;} | |||||
.ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;} | |||||
.ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#316AC5; color:white; height:16px; border:1px #316AC5 solid; | |||||
opacity:0.8; filter:alpha(opacity=80)} | |||||
.ztree li a.tmpTargetNode_prev {} | |||||
.ztree li a.tmpTargetNode_next {} | |||||
.ztree li a input.rename {height:14px; width:80px; padding:0; margin:0; | |||||
font-size:12px; border:1px #7EC4CC solid; *border:0px} | |||||
.ztree li span {line-height:16px; margin-right:2px} | |||||
.ztree li span.button {line-height:0; margin:0; width:16px; height:16px; display: inline-block; vertical-align:middle; | |||||
border:0 none; cursor: pointer;outline:none; | |||||
background-color:transparent; background-repeat:no-repeat; background-attachment: scroll; | |||||
background-image:url("./img/zTreeStandard.png"); *background-image:url("./img/zTreeStandard.gif")} | |||||
.ztree li span.button.chk {width:13px; height:13px; margin:0 3px 0 0; cursor: auto} | |||||
.ztree li span.button.chk.checkbox_false_full {background-position:0 0} | |||||
.ztree li span.button.chk.checkbox_false_full_focus {background-position:0 -14px} | |||||
.ztree li span.button.chk.checkbox_false_part {background-position:0 -28px} | |||||
.ztree li span.button.chk.checkbox_false_part_focus {background-position:0 -42px} | |||||
.ztree li span.button.chk.checkbox_false_disable {background-position:0 -56px} | |||||
.ztree li span.button.chk.checkbox_true_full {background-position:-14px 0} | |||||
.ztree li span.button.chk.checkbox_true_full_focus {background-position:-14px -14px} | |||||
.ztree li span.button.chk.checkbox_true_part {background-position:-14px -28px} | |||||
.ztree li span.button.chk.checkbox_true_part_focus {background-position:-14px -42px} | |||||
.ztree li span.button.chk.checkbox_true_disable {background-position:-14px -56px} | |||||
.ztree li span.button.chk.radio_false_full {background-position:-28px 0} | |||||
.ztree li span.button.chk.radio_false_full_focus {background-position:-28px -14px} | |||||
.ztree li span.button.chk.radio_false_part {background-position:-28px -28px} | |||||
.ztree li span.button.chk.radio_false_part_focus {background-position:-28px -42px} | |||||
.ztree li span.button.chk.radio_false_disable {background-position:-28px -56px} | |||||
.ztree li span.button.chk.radio_true_full {background-position:-42px 0} | |||||
.ztree li span.button.chk.radio_true_full_focus {background-position:-42px -14px} | |||||
.ztree li span.button.chk.radio_true_part {background-position:-42px -28px} | |||||
.ztree li span.button.chk.radio_true_part_focus {background-position:-42px -42px} | |||||
.ztree li span.button.chk.radio_true_disable {background-position:-42px -56px} | |||||
.ztree li span.button.switch {width:18px; height:18px} | |||||
.ztree li span.button.root_open{background-position:-92px -54px} | |||||
.ztree li span.button.root_close{background-position:-74px -54px} | |||||
.ztree li span.button.roots_open{background-position:-92px 0} | |||||
.ztree li span.button.roots_close{background-position:-74px 0} | |||||
.ztree li span.button.center_open{background-position:-92px -18px} | |||||
.ztree li span.button.center_close{background-position:-74px -18px} | |||||
.ztree li span.button.bottom_open{background-position:-92px -36px} | |||||
.ztree li span.button.bottom_close{background-position:-74px -36px} | |||||
.ztree li span.button.noline_open{background-position:-92px -72px} | |||||
.ztree li span.button.noline_close{background-position:-74px -72px} | |||||
.ztree li span.button.root_docu{ background:none;} | |||||
.ztree li span.button.roots_docu{background-position:-56px 0} | |||||
.ztree li span.button.center_docu{background-position:-56px -18px} | |||||
.ztree li span.button.bottom_docu{background-position:-56px -36px} | |||||
.ztree li span.button.noline_docu{ background:none;} | |||||
.ztree li span.button.ico_open{margin-right:2px; background-position:-110px -16px; vertical-align:top; *vertical-align:middle} | |||||
.ztree li span.button.ico_close{margin-right:2px; background-position:-110px 0; vertical-align:top; *vertical-align:middle} | |||||
.ztree li span.button.ico_docu{margin-right:2px; background-position:-110px -32px; vertical-align:top; *vertical-align:middle} | |||||
.ztree li span.button.edit {margin-right:2px; background-position:-110px -48px; vertical-align:top; *vertical-align:middle} | |||||
.ztree li span.button.remove {margin-right:2px; background-position:-110px -64px; vertical-align:top; *vertical-align:middle} | |||||
.ztree li span.button.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle} | |||||
ul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)} | |||||
span.tmpzTreeMove_arrow {width:16px; height:16px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute; | |||||
background-color:transparent; background-repeat:no-repeat; background-attachment: scroll; | |||||
background-position:-110px -80px; background-image:url("./img/zTreeStandard.png"); *background-image:url("./img/zTreeStandard.gif")} | |||||
ul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)} | |||||
.zTreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute} | |||||
/* level style*/ | |||||
/*.ztree li span.button.level0 { | |||||
display:none; | |||||
} | |||||
.ztree li ul.level0 { | |||||
padding:0; | |||||
background:none; | |||||
}*/ |
@@ -0,0 +1,167 @@ | |||||
/*! | |||||
* jQuery JavaScript Library v1.4.4 | |||||
* http://jquery.com/ | |||||
* | |||||
* Copyright 2010, John Resig | |||||
* Dual licensed under the MIT or GPL Version 2 licenses. | |||||
* http://jquery.org/license | |||||
* | |||||
* Includes Sizzle.js | |||||
* http://sizzlejs.com/ | |||||
* Copyright 2010, The Dojo Foundation | |||||
* Released under the MIT, BSD, and GPL Licenses. | |||||
* | |||||
* Date: Thu Nov 11 19:04:53 2010 -0500 | |||||
*/ | |||||
(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute("data-"+b);if(typeof d==="string"){try{d=d==="true"?true:d==="false"?false:d==="null"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?"events":"__events__");if(typeof h==="function")h= | |||||
h.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type==="click")){if(a.namespace)A=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var J=h.live.slice(0);for(k=0;k<J.length;k++){h=J[k];h.origType.replace(X,"")===a.type?f.push(h.selector):J.splice(k--,1)}f=c(a.target).closest(f,a.currentTarget);o=0;for(x=f.length;o<x;o++){r=f[o];for(k=0;k<J.length;k++){h=J[k];if(r.selector===h.selector&&(!A||A.test(h.namespace))){l=r.elem;e=null;if(h.preType==="mouseenter"|| | |||||
h.preType==="mouseleave"){a.type=h.preType;e=c(a.relatedTarget).closest(h.selector)[0]}if(!e||e!==l)C.push({elem:l,handleObj:h,level:r.level})}}}o=0;for(x=C.length;o<x;o++){f=C[o];if(d&&f.level>d)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La, | |||||
"`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this, | |||||
e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a, | |||||
"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+ | |||||
a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/, | |||||
C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j, | |||||
s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this, | |||||
j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length}, | |||||
toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j=== | |||||
-1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false; | |||||
if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K<Q;K++)if((j=arguments[K])!=null)for(s in j){v=G[s];z=j[s];if(G!==z)if(ga&&z&&(b.isPlainObject(z)||(H=b.isArray(z)))){if(H){H=false;v=v&&b.isArray(v)?v:[]}else v=v&&b.isPlainObject(v)?v:{};G[s]=b.extend(ga,v,z)}else if(z!==B)G[s]=z}return G};b.extend({noConflict:function(j){E.$=e;if(j)E.jQuery=d;return b},isReady:false,readyWait:1,ready:function(j){j===true&&b.readyWait--; | |||||
if(!b.readyWait||j!==true&&!b.isReady){if(!t.body)return setTimeout(b.ready,1);b.isReady=true;if(!(j!==true&&--b.readyWait>0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload", | |||||
b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&& | |||||
!F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&& | |||||
l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H<G;){if(s.apply(j[H++],v)===false)break}else if(K)for(z in j){if(s.call(j[z], | |||||
z,j[z])===false)break}else for(v=j[0];H<G&&s.call(v,H,v)!==false;v=j[++H]);return j},trim:O?function(j){return j==null?"":O.call(j)}:function(j){return j==null?"":j.toString().replace(k,"").replace(o,"")},makeArray:function(j,s){var v=s||[];if(j!=null){var z=b.type(j);j.length==null||z==="string"||z==="function"||z==="regexp"||b.isWindow(j)?M.call(v,j):b.merge(v,j)}return v},inArray:function(j,s){if(s.indexOf)return s.indexOf(j);for(var v=0,z=s.length;v<z;v++)if(s[v]===j)return v;return-1},merge:function(j, | |||||
s){var v=j.length,z=0;if(typeof s.length==="number")for(var H=s.length;z<H;z++)j[v++]=s[z];else for(;s[z]!==B;)j[v++]=s[z++];j.length=v;return j},grep:function(j,s,v){var z=[],H;v=!!v;for(var G=0,K=j.length;G<K;G++){H=!!s(j[G],G);v!==H&&z.push(j[G])}return z},map:function(j,s,v){for(var z=[],H,G=0,K=j.length;G<K;G++){H=s(j[G],G,v);if(H!=null)z[z.length]=H}return z.concat.apply([],z)},guid:1,proxy:function(j,s,v){if(arguments.length===2)if(typeof s==="string"){v=j;j=v[s];s=B}else if(s&&!b.isFunction(s)){v= | |||||
s;s=B}if(!s&&j)s=function(){return j.apply(v||this,arguments)};if(j)s.guid=j.guid=j.guid||s.guid||b.guid++;return s},access:function(j,s,v,z,H,G){var K=j.length;if(typeof s==="object"){for(var Q in s)b.access(j,Q,s[Q],z,H,v);return j}if(v!==B){z=!G&&z&&b.isFunction(v);for(Q=0;Q<K;Q++)H(j[Q],s,z?v.call(j[Q],Q,H(j[Q],s)):v,G);return j}return K?H(j[0],s):B},now:function(){return(new Date).getTime()},uaMatch:function(j){j=j.toLowerCase();j=L.exec(j)||g.exec(j)||i.exec(j)||j.indexOf("compatible")<0&&n.exec(j)|| | |||||
[];return{browser:j[1]||"",version:j[2]||"0"}},browser:{}});b.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(j,s){R["[object "+s+"]"]=s.toLowerCase()});m=b.uaMatch(m);if(m.browser){b.browser[m.browser]=true;b.browser.version=m.version}if(b.browser.webkit)b.browser.safari=true;if(D)b.inArray=function(j,s){return D.call(s,j)};if(!/\s/.test("\u00a0")){k=/^[\s\xA0]+/;o=/[\s\xA0]+$/}f=b(t);if(t.addEventListener)u=function(){t.removeEventListener("DOMContentLoaded",u, | |||||
false);b.ready()};else if(t.attachEvent)u=function(){if(t.readyState==="complete"){t.detachEvent("onreadystatechange",u);b.ready()}};return E.jQuery=E.$=b}();(function(){c.support={};var a=t.documentElement,b=t.createElement("script"),d=t.createElement("div"),e="script"+c.now();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"), | |||||
k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false, | |||||
scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent= | |||||
false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom= | |||||
1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="<div style='width:4px;'></div>";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display= | |||||
"none"});a=function(r){var A=t.createElement("div");r="on"+r;var C=r in A;if(!C){A.setAttribute(r,"return;");C=typeof A[r]==="function"}return C};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h= | |||||
c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando); | |||||
else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h<l;h++){f=e[h].name;if(f.indexOf("data-")===0){f=f.substr(5);ka(this[0],f,d[f])}}}return d}else if(typeof a==="object")return this.each(function(){c.data(this, | |||||
a)});var k=a.split(".");k[1]=k[1]?"."+k[1]:"";if(b===B){d=this.triggerHandler("getData"+k[1]+"!",[k[0]]);if(d===B&&this.length){d=c.data(this[0],a);d=ka(this[0],a,d)}return d===B&&k[1]?this.data(k[0]):d}else return this.each(function(){var o=c(this),x=[k[0],b];o.triggerHandler("setData"+k[1]+"!",x);c.data(this,a,b);o.triggerHandler("changeData"+k[1]+"!",x)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var e= | |||||
c.data(a,b);if(!d)return e||[];if(!e||c.isArray(d))e=c.data(a,b,c.makeArray(d));else e.push(d);return e}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),e=d.shift();if(e==="inprogress")e=d.shift();if(e){b==="fx"&&d.unshift("inprogress");e.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===B)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this, | |||||
a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var sa=/[\n\t]/g,ha=/\s+/,Sa=/\r/g,Ta=/^(?:href|src|style)$/,Ua=/^(?:button|input)$/i,Va=/^(?:button|input|object|select|textarea)$/i,Wa=/^a(?:rea)?$/i,ta=/^(?:radio|checkbox)$/i;c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan", | |||||
colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};c.fn.extend({attr:function(a,b){return c.access(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(x){var r=c(this);r.addClass(a.call(this,x,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType=== | |||||
1)if(f.className){for(var h=" "+f.className+" ",l=f.className,k=0,o=b.length;k<o;k++)if(h.indexOf(" "+b[k]+" ")<0)l+=" "+b[k];f.className=c.trim(l)}else f.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var x=c(this);x.removeClass(a.call(this,o,x.attr("class")))});if(a&&typeof a==="string"||a===B)for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1&&f.className)if(a){for(var h=(" "+f.className+" ").replace(sa," "), | |||||
l=0,k=b.length;l<k;l++)h=h.replace(" "+b[l]+" "," ");f.className=c.trim(h)}else f.className=""}return this},toggleClass:function(a,b){var d=typeof a,e=typeof b==="boolean";if(c.isFunction(a))return this.each(function(f){var h=c(this);h.toggleClass(a.call(this,f,h.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var f,h=0,l=c(this),k=b,o=a.split(ha);f=o[h++];){k=e?k:!l.hasClass(f);l[k?"addClass":"removeClass"](f)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this, | |||||
"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(sa," ").indexOf(a)>-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one"; | |||||
if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h<e;h++){var l=f[h];if(l.selected&&(c.support.optDisabled?!l.disabled:l.getAttribute("disabled")===null)&&(!l.parentNode.disabled||!c.nodeName(l.parentNode,"optgroup"))){a=c(l).val();if(b)return a;d.push(a)}}return d}if(ta.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Sa,"")}return B}var k=c.isFunction(a);return this.each(function(o){var x=c(this),r=a;if(this.nodeType===1){if(k)r= | |||||
a.call(this,o,x.val());if(r==null)r="";else if(typeof r==="number")r+="";else if(c.isArray(r))r=c.map(r,function(C){return C==null?"":C+""});if(c.isArray(r)&&ta.test(this.type))this.checked=c.inArray(x.val(),r)>=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true}, | |||||
attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&& | |||||
b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0}; | |||||
c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem, | |||||
arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid= | |||||
d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=f.split(".");f=o.shift();x=RegExp("(^|\\.)"+ | |||||
c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h<A.length;h++){C=A[h];if(d.guid===C.guid){if(k||x.test(C.namespace)){e==null&&A.splice(h--,1);r.remove&&r.remove.call(a,C)}if(e!=null)break}}if(A.length===0||e!=null&&A.length===1){if(!r.teardown||r.teardown.call(a,o)===false)c.removeEvent(a,f,w.handle);delete I[f]}}else for(h=0;h<A.length;h++){C=A[h];if(k||x.test(C.namespace)){c.event.remove(a,r,C.handler,h);A.splice(h--,1)}}}if(c.isEmptyObject(I)){if(b= | |||||
w.handle)b.elem=null;delete w.events;delete w.handle;if(typeof w==="function")c.removeData(a,J);else c.isEmptyObject(w)&&c.removeData(a)}}}}},trigger:function(a,b,d,e){var f=a.type||a;if(!e){a=typeof a==="object"?a[c.expando]?a:c.extend(c.Event(f),a):c.Event(f);if(f.indexOf("!")>=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType=== | |||||
8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k=== | |||||
"click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+ | |||||
d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f<l;f++){var k=d[f];if(b||e.test(k.namespace)){a.handler=k.handler;a.data=k.data;a.handleObj=k;k=k.handler.apply(this,h);if(k!==B){a.result=k;if(k===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), | |||||
fix:function(a){if(a[c.expando])return a;var b=a;a=c.Event(b);for(var d=this.props.length,e;d;){e=this.props[--d];a[e]=b[e]}if(!a.target)a.target=a.srcElement||t;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=t.documentElement;d=t.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop|| | |||||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(a.which==null&&(a.charCode!=null||a.keyCode!=null))a.which=a.charCode!=null?a.charCode:a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==B)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,Y(a.origType,a.selector),c.extend({},a,{handler:Ka,guid:a.handler.guid}))},remove:function(a){c.event.remove(this, | |||||
Y(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,d){if(c.isWindow(this))this.onbeforeunload=d},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.removeEvent=t.removeEventListener?function(a,b,d){a.removeEventListener&&a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent&&a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp= | |||||
c.now();this[c.expando]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ca;var a=this.originalEvent;if(a)if(a.preventDefault)a.preventDefault();else a.returnValue=false},stopPropagation:function(){this.isPropagationStopped=ca;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ca;this.stopPropagation()},isDefaultPrevented:U,isPropagationStopped:U,isImmediatePropagationStopped:U}; | |||||
var va=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},wa=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?wa:va,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?wa:va)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(){if(this.nodeName.toLowerCase()!== | |||||
"form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length){a.liveFired=B;return la("submit",this,arguments)}});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13){a.liveFired=B;return la("submit",this,arguments)}})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};if(!c.support.changeBubbles){var V, | |||||
xa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired= | |||||
B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type=== | |||||
"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]=== | |||||
0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h<k;h++)c.event.add(this[h],d,l,e)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&!a.preventDefault)for(var d in a)this.unbind(d, | |||||
a[d]);else{d=0;for(var e=this.length;d<e;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,e){return this.live(b,d,e,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var d=c.Event(a);d.preventDefault();d.stopPropagation();c.event.trigger(d,b,this[0]);return d.result}},toggle:function(a){for(var b=arguments,d= | |||||
1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(e){var f=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,f+1);e.preventDefault();return b[f].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var ya={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,e,f,h){var l,k=0,o,x,r=h||this.selector;h=h?this:c(this.context);if(typeof d=== | |||||
"object"&&!d.preventDefault){for(l in d)h[b](l,e,d[l],r);return this}if(c.isFunction(e)){f=e;e=B}for(d=(d||"").split(" ");(l=d[k++])!=null;){o=X.exec(l);x="";if(o){x=o[0];l=l.replace(X,"")}if(l==="hover")d.push("mouseenter"+x,"mouseleave"+x);else{o=l;if(l==="focus"||l==="blur"){d.push(ya[l]+x);l+=x}else l=(ya[l]||l)+x;if(b==="live"){x=0;for(var A=h.length;x<A;x++)c.event.add(h[x],"live."+Y(l,r),{data:e,selector:r,handler:f,origType:l,origHandler:f,preType:o})}else h.unbind("live."+Y(l,r),f)}}return this}}); | |||||
c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d,e){if(e==null){e=d;d=null}return arguments.length>0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}}); | |||||
(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1&&!q){y.sizcache=n;y.sizset=p}if(y.nodeName.toLowerCase()===i){F=y;break}y=y[g]}m[p]=F}}}function b(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1){if(!q){y.sizcache=n;y.sizset=p}if(typeof i!=="string"){if(y===i){F=true;break}}else if(k.filter(i, | |||||
[y]).length>0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3]; | |||||
break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr, | |||||
q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h= | |||||
l;g.sort(w);if(h)for(var i=1;i<g.length;i++)g[i]===g[i-1]&&g.splice(i--,1)}return g};k.matches=function(g,i){return k(g,null,null,i)};k.matchesSelector=function(g,i){return k(i,null,null,[g]).length>0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p<q;p++){var u,y=o.order[p];if(u=o.leftMatch[y].exec(g)){var F=u[1];u.splice(1,1);if(F.substr(F.length-1)!=="\\"){u[1]=(u[1]||"").replace(/\\/g,"");m=o.find[y](u,i,n);if(m!=null){g=g.replace(o.match[y],"");break}}}}m||(m=i.getElementsByTagName("*")); | |||||
return{set:m,expr:g}};k.filter=function(g,i,n,m){for(var p,q,u=g,y=[],F=i,M=i&&i[0]&&k.isXML(i[0]);g&&i.length;){for(var N in o.filter)if((p=o.leftMatch[N].exec(g))!=null&&p[2]){var O,D,R=o.filter[N];D=p[1];q=false;p.splice(1,1);if(D.substr(D.length-1)!=="\\"){if(F===y)y=[];if(o.preFilter[N])if(p=o.preFilter[N](p,F,n,y,m,M)){if(p===true)continue}else q=O=true;if(p)for(var j=0;(D=F[j])!=null;j++)if(D){O=R(D,p,j,F);var s=m^!!O;if(n&&O!=null)if(s)q=true;else F[j]=false;else if(s){y.push(D);q=true}}if(O!== | |||||
B){n||(F=y);g=g.replace(o.match[N],"");if(!q)return[];break}}}if(g===u)if(q==null)k.error(g);else break;u=g}return F};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var o=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/, | |||||
POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,i){var n=typeof i==="string",m=n&&!/\W/.test(i);n=n&&!m;if(m)i=i.toLowerCase();m=0;for(var p=g.length,q;m<p;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=n||q&&q.nodeName.toLowerCase()=== | |||||
i?q||false:q===i}n&&k.filter(i,g,true)},">":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p<q;p++){if(n=g[p]){n=n.parentNode;g[p]=n.nodeName.toLowerCase()===i?n:false}}else{for(;p<q;p++)if(n=g[p])g[p]=m?n.parentNode:n.parentNode===i;m&&k.filter(i,g,true)}},"":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=i=i.toLowerCase();q=a}q("parentNode",i,p,g,m,n)},"~":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m= | |||||
i=i.toLowerCase();q=a}q("previousSibling",i,p,g,m,n)}},find:{ID:function(g,i,n){if(typeof i.getElementById!=="undefined"&&!n)return(g=i.getElementById(g[1]))&&g.parentNode?[g]:[]},NAME:function(g,i){if(typeof i.getElementsByName!=="undefined"){for(var n=[],m=i.getElementsByName(g[1]),p=0,q=m.length;p<q;p++)m[p].getAttribute("name")===g[1]&&n.push(m[p]);return n.length===0?null:n}},TAG:function(g,i){return i.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,i,n,m,p,q){g=" "+g[1].replace(/\\/g, | |||||
"")+" ";if(q)return g;q=0;for(var u;(u=i[q])!=null;q++)if(u)if(p^(u.className&&(" "+u.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n, | |||||
m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled=== | |||||
true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"=== | |||||
g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return i<n[3]-0},gt:function(g,i,n){return i>n[3]-0},nth:function(g,i,n){return n[3]- | |||||
0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n<m;n++)if(i[n]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+p)},CHILD:function(g,i){var n=i[1],m=g;switch(n){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(n=== | |||||
"first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":n=i[2];var p=i[3];if(n===1&&p===0)return true;var q=i[0],u=g.parentNode;if(u&&(u.sizcache!==q||!g.nodeIndex)){var y=0;for(m=u.firstChild;m;m=m.nextSibling)if(m.nodeType===1)m.nodeIndex=++y;u.sizcache=q}m=g.nodeIndex-p;return n===0?m===0:m%n===0&&m/n>=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()=== | |||||
i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]]; | |||||
if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m, | |||||
g);else if(typeof g.length==="number")for(var p=g.length;n<p;n++)m.push(g[n]);else for(;g[n];n++)m.push(g[n]);return m}}var w,I;if(t.documentElement.compareDocumentPosition)w=function(g,i){if(g===i){h=true;return 0}if(!g.compareDocumentPosition||!i.compareDocumentPosition)return g.compareDocumentPosition?-1:1;return g.compareDocumentPosition(i)&4?-1:1};else{w=function(g,i){var n,m,p=[],q=[];n=g.parentNode;m=i.parentNode;var u=n;if(g===i){h=true;return 0}else if(n===m)return I(g,i);else if(n){if(!m)return 1}else return-1; | |||||
for(;u;){p.unshift(u);u=u.parentNode}for(u=m;u;){q.unshift(u);u=u.parentNode}n=p.length;m=q.length;for(u=0;u<n&&u<m;u++)if(p[u]!==q[u])return I(p[u],q[u]);return u===n?I(g,q[u],-1):I(p[u],i,1)};I=function(g,i,n){if(g===i)return n;for(g=g.nextSibling;g;){if(g===i)return-1;g=g.nextSibling}return 1}}k.getText=function(g){for(var i="",n,m=0;g[m];m++){n=g[m];if(n.nodeType===3||n.nodeType===4)i+=n.nodeValue;else if(n.nodeType!==8)i+=k.getText(n.childNodes)}return i};(function(){var g=t.createElement("div"), | |||||
i="script"+(new Date).getTime(),n=t.documentElement;g.innerHTML="<a name='"+i+"'/>";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g); | |||||
n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&& | |||||
function(){var g=k,i=t.createElement("div");i.innerHTML="<p class='TEST'></p>";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F|| | |||||
p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g= | |||||
t.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition? | |||||
function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n<u;n++)k(g,q[n],m);return k.filter(p,m)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=k.getText;c.isXMLDoc=k.isXML; | |||||
c.contains=k.contains})();var Za=/Until$/,$a=/^(?:parents|prevUntil|prevAll)/,ab=/,/,Na=/^.[^:#\[\.,]*$/,bb=Array.prototype.slice,cb=c.expr.match.POS;c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,e=0,f=this.length;e<f;e++){d=b.length;c.find(a,this[e],b);if(e>0)for(var h=d;h<b.length;h++)for(var l=0;l<d;l++)if(b[l]===b[h]){b.splice(h--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,e=b.length;d<e;d++)if(c.contains(this,b[d]))return true})}, | |||||
not:function(a){return this.pushStack(ma(this,a,false),"not",a)},filter:function(a){return this.pushStack(ma(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e<f;e++){l=a[e];k[l]||(k[l]=c.expr.match.POS.test(l)?c(l,b||this.context):l)}for(;h&&h.ownerDocument&&h!==b;){for(l in k){e=k[l];if(e.jquery?e.index(h)>-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h= | |||||
h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e<f;e++)for(h=this[e];h;)if(l?l.index(h)>-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context): | |||||
c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a, | |||||
2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a, | |||||
b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&& | |||||
e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/<tbody/i,eb=/<|&#?\w+;/,Ca=/<(?:script|object|embed|option|style)/i,Da=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/\=([^="'>\s]+\/)>/g,P={option:[1, | |||||
"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= | |||||
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, | |||||
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, | |||||
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, | |||||
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); | |||||
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null; | |||||
else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Aa,"<$1></$2>");try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(e){this.empty().append(a)}}else c.isFunction(a)?this.each(function(f){var h=c(this);h.html(a.call(this,f,h.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d= | |||||
c(this),e=d.html();d.replaceWith(a.call(this,b,e))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){var e,f,h,l=a[0],k=[];if(!c.support.checkClone&&arguments.length===3&&typeof l==="string"&&Da.test(l))return this.each(function(){c(this).domManip(a, | |||||
b,d,true)});if(c.isFunction(l))return this.each(function(x){var r=c(this);a[0]=l.call(this,x,b?r.html():B);r.domManip(a,b,d)});if(this[0]){e=l&&l.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:c.buildFragment(a,this,k);h=e.fragment;if(f=h.childNodes.length===1?h=h.firstChild:h.firstChild){b=b&&c.nodeName(f,"tr");f=0;for(var o=this.length;f<o;f++)d.call(b?c.nodeName(this[f],"table")?this[f].getElementsByTagName("tbody")[0]||this[f].appendChild(this[f].ownerDocument.createElement("tbody")): | |||||
this[f]:this[f],f>0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append", | |||||
prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f<h;f++){var l=(f>0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument|| | |||||
b[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1></$2>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]==="<table>"&&!x?r.childNodes:[];for(o=k.length- | |||||
1;o>=0;--o)c.nodeName(k[o],"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script")))); | |||||
d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i, | |||||
jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true, | |||||
zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b), | |||||
h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b); | |||||
if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f= | |||||
d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left; | |||||
e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, | |||||
ob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\[\]$/,T=/\=\?(&|$)/,ja=/\?/,rb=/([?&])_=[^&]*/,sb=/^(\w+:)?\/\/([^\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b=== | |||||
"object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(l,k){if(k==="success"||k==="notmodified")h.html(f?c("<div>").append(l.responseText.replace(nb,"")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&& | |||||
!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})}, | |||||
getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html", | |||||
script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ja.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data|| | |||||
!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+mb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType==="script"&&b.cache===null)b.cache= | |||||
false;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,"$1_="+o);b.url=x+(x===b.url?(ja.test(b.url)?"&":"?")+"_="+o:"")}if(b.data&&l)b.url+=(ja.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType==="script"&&h==="GET"&&o){var r=t.getElementsByTagName("head")[0]||t.documentElement,A=t.createElement("script");if(b.scriptCharset)A.charset=b.scriptCharset; | |||||
A.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader("Content-Type", | |||||
b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}o||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&& | |||||
c.triggerGlobal(b,"ajaxSend",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m==="timeout")){J=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d|| | |||||
c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L("abort")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L("timeout")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]= | |||||
encodeURIComponent(h)+"="+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join("&").replace(tb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess", | |||||
[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"), | |||||
e=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}}); | |||||
if(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\-]=)?([\d+.\-]+)(.*)$/,ba,pa=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show", | |||||
3),a,b,d);else{d=0;for(var e=this.length;d<e;d++){a=this[d];b=a.style.display;if(!c.data(a,"olddisplay")&&b==="none")b=a.style.display="";b===""&&c.css(a,"display")==="none"&&c.data(a,"olddisplay",qa(a.nodeName))}for(d=0;d<e;d++){a=this[d];b=a.style.display;if(b===""||b==="none")a.style.display=c.data(a,"olddisplay")||""}return this}},hide:function(a,b,d){if(a||a===0)return this.animate(S("hide",3),a,b,d);else{a=0;for(b=this.length;a<b;a++){d=c.css(this[a],"display");d!=="none"&&c.data(this[a],"olddisplay", | |||||
d)}for(a=0;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b,d){var e=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||e?this.each(function(){var f=e?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(S("toggle",3),a,b,d);return this},fadeTo:function(a,b,d,e){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d,e)},animate:function(a,b,d,e){var f=c.speed(b, | |||||
d,e);if(c.isEmptyObject(a))return this.each(f.complete);return this[f.queue===false?"each":"queue"](function(){var h=c.extend({},f),l,k=this.nodeType===1,o=k&&c(this).is(":hidden"),x=this;for(l in a){var r=c.camelCase(l);if(l!==r){a[r]=a[l];delete a[l];l=r}if(a[l]==="hide"&&o||a[l]==="show"&&!o)return h.complete.call(this);if(k&&(l==="height"||l==="width")){h.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(c.css(this,"display")==="inline"&&c.css(this,"float")==="none")if(c.support.inlineBlockNeedsLayout)if(qa(this.nodeName)=== | |||||
"inline")this.style.display="inline-block";else{this.style.display="inline";this.style.zoom=1}else this.style.display="inline-block"}if(c.isArray(a[l])){(h.specialEasing=h.specialEasing||{})[l]=a[l][1];a[l]=a[l][0]}}if(h.overflow!=null)this.style.overflow="hidden";h.curAnim=c.extend({},a);c.each(a,function(A,C){var J=new c.fx(x,h,A);if(vb.test(C))J[C==="toggle"?o?"show":"hide":C](a);else{var w=wb.exec(C),I=J.cur()||0;if(w){var L=parseFloat(w[2]),g=w[3]||"px";if(g!=="px"){c.style(x,A,(L||1)+g);I=(L|| | |||||
1)/J.cur()*I;c.style(x,A,I+g)}if(w[1])L=(w[1]==="-="?-1:1)*L+I;J.custom(I,L,g)}else J.custom(I,C,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var e=d.length-1;e>=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b, | |||||
d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a* | |||||
Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)} | |||||
var f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true; | |||||
this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(k,o){f.style["overflow"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide|| | |||||
this.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a= | |||||
c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},interval:13,stop:function(){clearInterval(ba);ba=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a=== | |||||
b.elem}).length};var xb=/^t(?:able|d|h)$/i,Ia=/^(?:body|html)$/i;c.fn.offset="getBoundingClientRect"in t.documentElement?function(a){var b=this[0],d;if(a)return this.each(function(l){c.offset.setOffset(this,a,l)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);try{d=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,h=f.documentElement;if(!d||!c.contains(h,b))return d||{top:0,left:0};b=f.body;f=fa(f);return{top:d.top+(f.pageYOffset||c.support.boxModel&& | |||||
h.scrollTop||b.scrollTop)-(h.clientTop||b.clientTop||0),left:d.left+(f.pageXOffset||c.support.boxModel&&h.scrollLeft||b.scrollLeft)-(h.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(x){c.offset.setOffset(this,a,x)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d,e=b.offsetParent,f=b.ownerDocument,h=f.documentElement,l=f.body;d=(f=f.defaultView)?f.getComputedStyle(b,null):b.currentStyle; | |||||
for(var k=b.offsetTop,o=b.offsetLeft;(b=b.parentNode)&&b!==l&&b!==h;){if(c.offset.supportsFixedPosition&&d.position==="fixed")break;d=f?f.getComputedStyle(b,null):b.currentStyle;k-=b.scrollTop;o-=b.scrollLeft;if(b===e){k+=b.offsetTop;o+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&xb.test(b.nodeName))){k+=parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}e=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"){k+= | |||||
parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}d=d}if(d.position==="relative"||d.position==="static"){k+=l.offsetTop;o+=l.offsetLeft}if(c.offset.supportsFixedPosition&&d.position==="fixed"){k+=Math.max(h.scrollTop,l.scrollTop);o+=Math.max(h.scrollLeft,l.scrollLeft)}return{top:k,left:o}};c.offset={initialize:function(){var a=t.body,b=t.createElement("div"),d,e,f,h=parseFloat(c.css(a,"marginTop"))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px", | |||||
height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);d=b.firstChild;e=d.firstChild;f=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=e.offsetTop!==5;this.doesAddBorderForTableAndCells= | |||||
f.offsetTop===5;e.style.position="fixed";e.style.top="20px";this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15;e.style.position=e.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==h;a.removeChild(b);c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.css(a, | |||||
"marginTop"))||0;d+=parseFloat(c.css(a,"marginLeft"))||0}return{top:b,left:d}},setOffset:function(a,b,d){var e=c.css(a,"position");if(e==="static")a.style.position="relative";var f=c(a),h=f.offset(),l=c.css(a,"top"),k=c.css(a,"left"),o=e==="absolute"&&c.inArray("auto",[l,k])>-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;"using"in b?b.using.call(a, | |||||
e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&& | |||||
c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase(); | |||||
c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b];else if(f.nodeType===9)return Math.max(f.documentElement["client"+ | |||||
b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e==="string"?e:e+"px")}})})(window); |
@@ -0,0 +1,652 @@ | |||||
/* | |||||
* JQuery zTree excheck | |||||
* v3.5.48 | |||||
* http://treejs.cn/ | |||||
* | |||||
* Copyright (c) 2010 Hunter.z | |||||
* | |||||
* Licensed same as jquery - MIT License | |||||
* http://www.opensource.org/licenses/mit-license.php | |||||
* | |||||
* Date: 2020-11-21 | |||||
*/ | |||||
(function ($) { | |||||
//default consts of excheck | |||||
var _consts = { | |||||
event: { | |||||
CHECK: "ztree_check" | |||||
}, | |||||
id: { | |||||
CHECK: "_check" | |||||
}, | |||||
checkbox: { | |||||
STYLE: "checkbox", | |||||
DEFAULT: "chk", | |||||
DISABLED: "disable", | |||||
FALSE: "false", | |||||
TRUE: "true", | |||||
FULL: "full", | |||||
PART: "part", | |||||
FOCUS: "focus" | |||||
}, | |||||
radio: { | |||||
STYLE: "radio", | |||||
TYPE_ALL: "all", | |||||
TYPE_LEVEL: "level" | |||||
} | |||||
}, | |||||
//default setting of excheck | |||||
_setting = { | |||||
check: { | |||||
enable: false, | |||||
autoCheckTrigger: false, | |||||
chkStyle: _consts.checkbox.STYLE, | |||||
nocheckInherit: false, | |||||
chkDisabledInherit: false, | |||||
radioType: _consts.radio.TYPE_LEVEL, | |||||
chkboxType: { | |||||
"Y": "ps", | |||||
"N": "ps" | |||||
} | |||||
}, | |||||
data: { | |||||
key: { | |||||
checked: "checked" | |||||
} | |||||
}, | |||||
callback: { | |||||
beforeCheck: null, | |||||
onCheck: null | |||||
} | |||||
}, | |||||
//default root of excheck | |||||
_initRoot = function (setting) { | |||||
var r = data.getRoot(setting); | |||||
r.radioCheckedList = []; | |||||
}, | |||||
//default cache of excheck | |||||
_initCache = function (treeId) { | |||||
}, | |||||
//default bind event of excheck | |||||
_bindEvent = function (setting) { | |||||
var o = setting.treeObj, | |||||
c = consts.event; | |||||
o.bind(c.CHECK, function (event, srcEvent, treeId, node) { | |||||
event.srcEvent = srcEvent; | |||||
tools.apply(setting.callback.onCheck, [event, treeId, node]); | |||||
}); | |||||
}, | |||||
_unbindEvent = function (setting) { | |||||
var o = setting.treeObj, | |||||
c = consts.event; | |||||
o.unbind(c.CHECK); | |||||
}, | |||||
//default event proxy of excheck | |||||
_eventProxy = function (e) { | |||||
var target = e.target, | |||||
setting = data.getSetting(e.data.treeId), | |||||
tId = "", node = null, | |||||
nodeEventType = "", treeEventType = "", | |||||
nodeEventCallback = null, treeEventCallback = null; | |||||
if (tools.eqs(e.type, "mouseover")) { | |||||
if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode" + consts.id.CHECK) !== null) { | |||||
tId = tools.getNodeMainDom(target).id; | |||||
nodeEventType = "mouseoverCheck"; | |||||
} | |||||
} else if (tools.eqs(e.type, "mouseout")) { | |||||
if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode" + consts.id.CHECK) !== null) { | |||||
tId = tools.getNodeMainDom(target).id; | |||||
nodeEventType = "mouseoutCheck"; | |||||
} | |||||
} else if (tools.eqs(e.type, "click")) { | |||||
if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode" + consts.id.CHECK) !== null) { | |||||
tId = tools.getNodeMainDom(target).id; | |||||
nodeEventType = "checkNode"; | |||||
} | |||||
} | |||||
if (tId.length > 0) { | |||||
node = data.getNodeCache(setting, tId); | |||||
switch (nodeEventType) { | |||||
case "checkNode" : | |||||
nodeEventCallback = _handler.onCheckNode; | |||||
break; | |||||
case "mouseoverCheck" : | |||||
nodeEventCallback = _handler.onMouseoverCheck; | |||||
break; | |||||
case "mouseoutCheck" : | |||||
nodeEventCallback = _handler.onMouseoutCheck; | |||||
break; | |||||
} | |||||
} | |||||
var proxyResult = { | |||||
stop: nodeEventType === "checkNode", | |||||
node: node, | |||||
nodeEventType: nodeEventType, | |||||
nodeEventCallback: nodeEventCallback, | |||||
treeEventType: treeEventType, | |||||
treeEventCallback: treeEventCallback | |||||
}; | |||||
return proxyResult | |||||
}, | |||||
//default init node of excheck | |||||
_initNode = function (setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) { | |||||
if (!n) return; | |||||
var checked = data.nodeChecked(setting, n); | |||||
n.checkedOld = checked; | |||||
if (typeof n.nocheck == "string") n.nocheck = tools.eqs(n.nocheck, "true"); | |||||
n.nocheck = !!n.nocheck || (setting.check.nocheckInherit && parentNode && !!parentNode.nocheck); | |||||
if (typeof n.chkDisabled == "string") n.chkDisabled = tools.eqs(n.chkDisabled, "true"); | |||||
n.chkDisabled = !!n.chkDisabled || (setting.check.chkDisabledInherit && parentNode && !!parentNode.chkDisabled); | |||||
if (typeof n.halfCheck == "string") n.halfCheck = tools.eqs(n.halfCheck, "true"); | |||||
n.halfCheck = !!n.halfCheck; | |||||
n.check_Child_State = -1; | |||||
n.check_Focus = false; | |||||
n.getCheckStatus = function () { | |||||
return data.getCheckStatus(setting, n); | |||||
}; | |||||
if (setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL && checked) { | |||||
var r = data.getRoot(setting); | |||||
r.radioCheckedList.push(n); | |||||
} | |||||
}, | |||||
//add dom for check | |||||
_beforeA = function (setting, node, html) { | |||||
if (setting.check.enable) { | |||||
data.makeChkFlag(setting, node); | |||||
html.push("<span ID='", node.tId, consts.id.CHECK, "' class='", view.makeChkClass(setting, node), "' treeNode", consts.id.CHECK, (node.nocheck === true ? " style='display:none;'" : ""), "></span>"); | |||||
} | |||||
}, | |||||
//update zTreeObj, add method of check | |||||
_zTreeTools = function (setting, zTreeTools) { | |||||
zTreeTools.checkNode = function (node, checked, checkTypeFlag, callbackFlag) { | |||||
var nodeChecked = data.nodeChecked(setting, node); | |||||
if (node.chkDisabled === true) return; | |||||
if (checked !== true && checked !== false) { | |||||
checked = !nodeChecked; | |||||
} | |||||
callbackFlag = !!callbackFlag; | |||||
if (nodeChecked === checked && !checkTypeFlag) { | |||||
return; | |||||
} else if (callbackFlag && tools.apply(this.setting.callback.beforeCheck, [this.setting.treeId, node], true) == false) { | |||||
return; | |||||
} | |||||
if (tools.uCanDo(this.setting) && this.setting.check.enable && node.nocheck !== true) { | |||||
data.nodeChecked(setting, node, checked); | |||||
var checkObj = $$(node, consts.id.CHECK, this.setting); | |||||
if (checkTypeFlag || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node); | |||||
view.setChkClass(this.setting, checkObj, node); | |||||
view.repairParentChkClassWithSelf(this.setting, node); | |||||
if (callbackFlag) { | |||||
this.setting.treeObj.trigger(consts.event.CHECK, [null, this.setting.treeId, node]); | |||||
} | |||||
} | |||||
} | |||||
zTreeTools.checkAllNodes = function (checked) { | |||||
view.repairAllChk(this.setting, !!checked); | |||||
} | |||||
zTreeTools.getCheckedNodes = function (checked) { | |||||
checked = (checked !== false); | |||||
var children = data.nodeChildren(setting, data.getRoot(this.setting)); | |||||
return data.getTreeCheckedNodes(this.setting, children, checked); | |||||
} | |||||
zTreeTools.getChangeCheckedNodes = function () { | |||||
var children = data.nodeChildren(setting, data.getRoot(this.setting)); | |||||
return data.getTreeChangeCheckedNodes(this.setting, children); | |||||
} | |||||
zTreeTools.setChkDisabled = function (node, disabled, inheritParent, inheritChildren) { | |||||
disabled = !!disabled; | |||||
inheritParent = !!inheritParent; | |||||
inheritChildren = !!inheritChildren; | |||||
view.repairSonChkDisabled(this.setting, node, disabled, inheritChildren); | |||||
view.repairParentChkDisabled(this.setting, node.getParentNode(), disabled, inheritParent); | |||||
} | |||||
var _updateNode = zTreeTools.updateNode; | |||||
zTreeTools.updateNode = function (node, checkTypeFlag) { | |||||
if (_updateNode) _updateNode.apply(zTreeTools, arguments); | |||||
if (!node || !this.setting.check.enable) return; | |||||
var nObj = $$(node, this.setting); | |||||
if (nObj.get(0) && tools.uCanDo(this.setting)) { | |||||
var checkObj = $$(node, consts.id.CHECK, this.setting); | |||||
if (checkTypeFlag == true || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node); | |||||
view.setChkClass(this.setting, checkObj, node); | |||||
view.repairParentChkClassWithSelf(this.setting, node); | |||||
} | |||||
} | |||||
}, | |||||
//method of operate data | |||||
_data = { | |||||
getRadioCheckedList: function (setting) { | |||||
var checkedList = data.getRoot(setting).radioCheckedList; | |||||
for (var i = 0, j = checkedList.length; i < j; i++) { | |||||
if (!data.getNodeCache(setting, checkedList[i].tId)) { | |||||
checkedList.splice(i, 1); | |||||
i--; | |||||
j--; | |||||
} | |||||
} | |||||
return checkedList; | |||||
}, | |||||
getCheckStatus: function (setting, node) { | |||||
if (!setting.check.enable || node.nocheck || node.chkDisabled) return null; | |||||
var checked = data.nodeChecked(setting, node), | |||||
r = { | |||||
checked: checked, | |||||
half: node.halfCheck ? node.halfCheck : (setting.check.chkStyle == consts.radio.STYLE ? (node.check_Child_State === 2) : (checked ? (node.check_Child_State > -1 && node.check_Child_State < 2) : (node.check_Child_State > 0))) | |||||
}; | |||||
return r; | |||||
}, | |||||
getTreeCheckedNodes: function (setting, nodes, checked, results) { | |||||
if (!nodes) return []; | |||||
var onlyOne = (checked && setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL); | |||||
results = !results ? [] : results; | |||||
for (var i = 0, l = nodes.length; i < l; i++) { | |||||
var node = nodes[i]; | |||||
var children = data.nodeChildren(setting, node); | |||||
var nodeChecked = data.nodeChecked(setting, node); | |||||
if (node.nocheck !== true && node.chkDisabled !== true && nodeChecked == checked) { | |||||
results.push(node); | |||||
if (onlyOne) { | |||||
break; | |||||
} | |||||
} | |||||
data.getTreeCheckedNodes(setting, children, checked, results); | |||||
if (onlyOne && results.length > 0) { | |||||
break; | |||||
} | |||||
} | |||||
return results; | |||||
}, | |||||
getTreeChangeCheckedNodes: function (setting, nodes, results) { | |||||
if (!nodes) return []; | |||||
results = !results ? [] : results; | |||||
for (var i = 0, l = nodes.length; i < l; i++) { | |||||
var node = nodes[i]; | |||||
var children = data.nodeChildren(setting, node); | |||||
var nodeChecked = data.nodeChecked(setting, node); | |||||
if (node.nocheck !== true && node.chkDisabled !== true && nodeChecked != node.checkedOld) { | |||||
results.push(node); | |||||
} | |||||
data.getTreeChangeCheckedNodes(setting, children, results); | |||||
} | |||||
return results; | |||||
}, | |||||
makeChkFlag: function (setting, node) { | |||||
if (!node) return; | |||||
var chkFlag = -1; | |||||
var children = data.nodeChildren(setting, node); | |||||
if (children) { | |||||
for (var i = 0, l = children.length; i < l; i++) { | |||||
var cNode = children[i]; | |||||
var nodeChecked = data.nodeChecked(setting, cNode); | |||||
var tmp = -1; | |||||
if (setting.check.chkStyle == consts.radio.STYLE) { | |||||
if (cNode.nocheck === true || cNode.chkDisabled === true) { | |||||
tmp = cNode.check_Child_State; | |||||
} else if (cNode.halfCheck === true) { | |||||
tmp = 2; | |||||
} else if (nodeChecked) { | |||||
tmp = 2; | |||||
} else { | |||||
tmp = cNode.check_Child_State > 0 ? 2 : 0; | |||||
} | |||||
if (tmp == 2) { | |||||
chkFlag = 2; | |||||
break; | |||||
} else if (tmp == 0) { | |||||
chkFlag = 0; | |||||
} | |||||
} else if (setting.check.chkStyle == consts.checkbox.STYLE) { | |||||
if (cNode.nocheck === true || cNode.chkDisabled === true) { | |||||
tmp = cNode.check_Child_State; | |||||
} else if (cNode.halfCheck === true) { | |||||
tmp = 1; | |||||
} else if (nodeChecked) { | |||||
tmp = (cNode.check_Child_State === -1 || cNode.check_Child_State === 2) ? 2 : 1; | |||||
} else { | |||||
tmp = (cNode.check_Child_State > 0) ? 1 : 0; | |||||
} | |||||
if (tmp === 1) { | |||||
chkFlag = 1; | |||||
break; | |||||
} else if (tmp === 2 && chkFlag > -1 && i > 0 && tmp !== chkFlag) { | |||||
chkFlag = 1; | |||||
break; | |||||
} else if (chkFlag === 2 && tmp > -1 && tmp < 2) { | |||||
chkFlag = 1; | |||||
break; | |||||
} else if (tmp > -1) { | |||||
chkFlag = tmp; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
node.check_Child_State = chkFlag; | |||||
} | |||||
}, | |||||
//method of event proxy | |||||
_event = {}, | |||||
//method of event handler | |||||
_handler = { | |||||
onCheckNode: function (event, node) { | |||||
if (node.chkDisabled === true) return false; | |||||
var setting = data.getSetting(event.data.treeId); | |||||
if (tools.apply(setting.callback.beforeCheck, [setting.treeId, node], true) == false) return true; | |||||
var nodeChecked = data.nodeChecked(setting, node); | |||||
data.nodeChecked(setting, node, !nodeChecked); | |||||
view.checkNodeRelation(setting, node); | |||||
var checkObj = $$(node, consts.id.CHECK, setting); | |||||
view.setChkClass(setting, checkObj, node); | |||||
view.repairParentChkClassWithSelf(setting, node); | |||||
setting.treeObj.trigger(consts.event.CHECK, [event, setting.treeId, node]); | |||||
return true; | |||||
}, | |||||
onMouseoverCheck: function (event, node) { | |||||
if (node.chkDisabled === true) return false; | |||||
var setting = data.getSetting(event.data.treeId), | |||||
checkObj = $$(node, consts.id.CHECK, setting); | |||||
node.check_Focus = true; | |||||
view.setChkClass(setting, checkObj, node); | |||||
return true; | |||||
}, | |||||
onMouseoutCheck: function (event, node) { | |||||
if (node.chkDisabled === true) return false; | |||||
var setting = data.getSetting(event.data.treeId), | |||||
checkObj = $$(node, consts.id.CHECK, setting); | |||||
node.check_Focus = false; | |||||
view.setChkClass(setting, checkObj, node); | |||||
return true; | |||||
} | |||||
}, | |||||
//method of tools for zTree | |||||
_tools = {}, | |||||
//method of operate ztree dom | |||||
_view = { | |||||
checkNodeRelation: function (setting, node) { | |||||
var pNode, i, l, | |||||
r = consts.radio; | |||||
var nodeChecked = data.nodeChecked(setting, node); | |||||
if (setting.check.chkStyle == r.STYLE) { | |||||
var checkedList = data.getRadioCheckedList(setting); | |||||
if (nodeChecked) { | |||||
if (setting.check.radioType == r.TYPE_ALL) { | |||||
for (i = checkedList.length - 1; i >= 0; i--) { | |||||
pNode = checkedList[i]; | |||||
var pNodeChecked = data.nodeChecked(setting, pNode); | |||||
if (pNodeChecked && pNode != node) { | |||||
data.nodeChecked(setting, pNode, false); | |||||
checkedList.splice(i, 1); | |||||
view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode); | |||||
if (pNode.parentTId != node.parentTId) { | |||||
view.repairParentChkClassWithSelf(setting, pNode); | |||||
} | |||||
} | |||||
} | |||||
checkedList.push(node); | |||||
} else { | |||||
var parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting); | |||||
var children = data.nodeChildren(setting, parentNode); | |||||
for (i = 0, l = children.length; i < l; i++) { | |||||
pNode = children[i]; | |||||
var pNodeChecked = data.nodeChecked(setting, pNode); | |||||
if (pNodeChecked && pNode != node) { | |||||
data.nodeChecked(setting, pNode, false); | |||||
view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode); | |||||
} | |||||
} | |||||
} | |||||
} else if (setting.check.radioType == r.TYPE_ALL) { | |||||
for (i = 0, l = checkedList.length; i < l; i++) { | |||||
if (node == checkedList[i]) { | |||||
checkedList.splice(i, 1); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
} else { | |||||
var children = data.nodeChildren(setting, node); | |||||
if (nodeChecked && (!children || children.length == 0 || setting.check.chkboxType.Y.indexOf("s") > -1)) { | |||||
view.setSonNodeCheckBox(setting, node, true); | |||||
} | |||||
if (!nodeChecked && (!children || children.length == 0 || setting.check.chkboxType.N.indexOf("s") > -1)) { | |||||
view.setSonNodeCheckBox(setting, node, false); | |||||
} | |||||
if (nodeChecked && setting.check.chkboxType.Y.indexOf("p") > -1) { | |||||
view.setParentNodeCheckBox(setting, node, true); | |||||
} | |||||
if (!nodeChecked && setting.check.chkboxType.N.indexOf("p") > -1) { | |||||
view.setParentNodeCheckBox(setting, node, false); | |||||
} | |||||
} | |||||
}, | |||||
makeChkClass: function (setting, node) { | |||||
var c = consts.checkbox, r = consts.radio, | |||||
fullStyle = ""; | |||||
var nodeChecked = data.nodeChecked(setting, node); | |||||
if (node.chkDisabled === true) { | |||||
fullStyle = c.DISABLED; | |||||
} else if (node.halfCheck) { | |||||
fullStyle = c.PART; | |||||
} else if (setting.check.chkStyle == r.STYLE) { | |||||
fullStyle = (node.check_Child_State < 1) ? c.FULL : c.PART; | |||||
} else { | |||||
fullStyle = nodeChecked ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL : c.PART) : ((node.check_Child_State < 1) ? c.FULL : c.PART); | |||||
} | |||||
var chkName = setting.check.chkStyle + "_" + (nodeChecked ? c.TRUE : c.FALSE) + "_" + fullStyle; | |||||
chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + "_" + c.FOCUS : chkName; | |||||
return consts.className.BUTTON + " " + c.DEFAULT + " " + chkName; | |||||
}, | |||||
repairAllChk: function (setting, checked) { | |||||
if (setting.check.enable && setting.check.chkStyle === consts.checkbox.STYLE) { | |||||
var root = data.getRoot(setting); | |||||
var children = data.nodeChildren(setting, root); | |||||
for (var i = 0, l = children.length; i < l; i++) { | |||||
var node = children[i]; | |||||
if (node.nocheck !== true && node.chkDisabled !== true) { | |||||
data.nodeChecked(setting, node, checked); | |||||
} | |||||
view.setSonNodeCheckBox(setting, node, checked); | |||||
} | |||||
} | |||||
}, | |||||
repairChkClass: function (setting, node) { | |||||
if (!node) return; | |||||
data.makeChkFlag(setting, node); | |||||
if (node.nocheck !== true) { | |||||
var checkObj = $$(node, consts.id.CHECK, setting); | |||||
view.setChkClass(setting, checkObj, node); | |||||
} | |||||
}, | |||||
repairParentChkClass: function (setting, node) { | |||||
if (!node || !node.parentTId) return; | |||||
var pNode = node.getParentNode(); | |||||
view.repairChkClass(setting, pNode); | |||||
view.repairParentChkClass(setting, pNode); | |||||
}, | |||||
repairParentChkClassWithSelf: function (setting, node) { | |||||
if (!node) return; | |||||
var children = data.nodeChildren(setting, node); | |||||
if (children && children.length > 0) { | |||||
view.repairParentChkClass(setting, children[0]); | |||||
} else { | |||||
view.repairParentChkClass(setting, node); | |||||
} | |||||
}, | |||||
repairSonChkDisabled: function (setting, node, chkDisabled, inherit) { | |||||
if (!node) return; | |||||
if (node.chkDisabled != chkDisabled) { | |||||
node.chkDisabled = chkDisabled; | |||||
} | |||||
view.repairChkClass(setting, node); | |||||
var children = data.nodeChildren(setting, node); | |||||
if (children && inherit) { | |||||
for (var i = 0, l = children.length; i < l; i++) { | |||||
var sNode = children[i]; | |||||
view.repairSonChkDisabled(setting, sNode, chkDisabled, inherit); | |||||
} | |||||
} | |||||
}, | |||||
repairParentChkDisabled: function (setting, node, chkDisabled, inherit) { | |||||
if (!node) return; | |||||
if (node.chkDisabled != chkDisabled && inherit) { | |||||
node.chkDisabled = chkDisabled; | |||||
} | |||||
view.repairChkClass(setting, node); | |||||
view.repairParentChkDisabled(setting, node.getParentNode(), chkDisabled, inherit); | |||||
}, | |||||
setChkClass: function (setting, obj, node) { | |||||
if (!obj) return; | |||||
if (node.nocheck === true) { | |||||
obj.hide(); | |||||
} else { | |||||
obj.show(); | |||||
} | |||||
obj.attr('class', view.makeChkClass(setting, node)); | |||||
}, | |||||
setParentNodeCheckBox: function (setting, node, value, srcNode) { | |||||
var checkObj = $$(node, consts.id.CHECK, setting); | |||||
if (!srcNode) srcNode = node; | |||||
data.makeChkFlag(setting, node); | |||||
if (node.nocheck !== true && node.chkDisabled !== true) { | |||||
data.nodeChecked(setting, node, value); | |||||
view.setChkClass(setting, checkObj, node); | |||||
if (setting.check.autoCheckTrigger && node != srcNode) { | |||||
setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]); | |||||
} | |||||
} | |||||
if (node.parentTId) { | |||||
var pSign = true; | |||||
if (!value) { | |||||
var pNodes = data.nodeChildren(setting, node.getParentNode()); | |||||
for (var i = 0, l = pNodes.length; i < l; i++) { | |||||
var pNode = pNodes[i]; | |||||
var nodeChecked = data.nodeChecked(setting, pNode); | |||||
if ((pNode.nocheck !== true && pNode.chkDisabled !== true && nodeChecked) | |||||
|| ((pNode.nocheck === true || pNode.chkDisabled === true) && pNode.check_Child_State > 0)) { | |||||
pSign = false; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
if (pSign) { | |||||
view.setParentNodeCheckBox(setting, node.getParentNode(), value, srcNode); | |||||
} | |||||
} | |||||
}, | |||||
setSonNodeCheckBox: function (setting, node, value, srcNode) { | |||||
if (!node) return; | |||||
var checkObj = $$(node, consts.id.CHECK, setting); | |||||
if (!srcNode) srcNode = node; | |||||
var hasDisable = false; | |||||
var children = data.nodeChildren(setting, node); | |||||
if (children) { | |||||
for (var i = 0, l = children.length; i < l; i++) { | |||||
var sNode = children[i]; | |||||
view.setSonNodeCheckBox(setting, sNode, value, srcNode); | |||||
if (sNode.chkDisabled === true) hasDisable = true; | |||||
} | |||||
} | |||||
if (node != data.getRoot(setting) && node.chkDisabled !== true) { | |||||
if (hasDisable && node.nocheck !== true) { | |||||
data.makeChkFlag(setting, node); | |||||
} | |||||
if (node.nocheck !== true && node.chkDisabled !== true) { | |||||
data.nodeChecked(setting, node, value); | |||||
if (!hasDisable) node.check_Child_State = (children && children.length > 0) ? (value ? 2 : 0) : -1; | |||||
} else { | |||||
node.check_Child_State = -1; | |||||
} | |||||
view.setChkClass(setting, checkObj, node); | |||||
if (setting.check.autoCheckTrigger && node != srcNode && node.nocheck !== true && node.chkDisabled !== true) { | |||||
setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]); | |||||
} | |||||
} | |||||
} | |||||
}, | |||||
_z = { | |||||
tools: _tools, | |||||
view: _view, | |||||
event: _event, | |||||
data: _data | |||||
}; | |||||
$.extend(true, $.fn.zTree.consts, _consts); | |||||
$.extend(true, $.fn.zTree._z, _z); | |||||
var zt = $.fn.zTree, | |||||
tools = zt._z.tools, | |||||
consts = zt.consts, | |||||
view = zt._z.view, | |||||
data = zt._z.data, | |||||
event = zt._z.event, | |||||
$$ = tools.$; | |||||
data.nodeChecked = function (setting, node, newChecked) { | |||||
if (!node) { | |||||
return false; | |||||
} | |||||
var key = setting.data.key.checked; | |||||
if (typeof newChecked !== 'undefined') { | |||||
if (typeof newChecked === "string") { | |||||
newChecked = tools.eqs(newChecked, "true"); | |||||
} | |||||
newChecked = !!newChecked; | |||||
node[key] = newChecked; | |||||
} else if (typeof node[key] == "string"){ | |||||
node[key] = tools.eqs(node[key], "true"); | |||||
} else { | |||||
node[key] = !!node[key]; | |||||
} | |||||
return node[key]; | |||||
}; | |||||
data.exSetting(_setting); | |||||
data.addInitBind(_bindEvent); | |||||
data.addInitUnBind(_unbindEvent); | |||||
data.addInitCache(_initCache); | |||||
data.addInitNode(_initNode); | |||||
data.addInitProxy(_eventProxy, true); | |||||
data.addInitRoot(_initRoot); | |||||
data.addBeforeA(_beforeA); | |||||
data.addZTreeTools(_zTreeTools); | |||||
var _createNodes = view.createNodes; | |||||
view.createNodes = function (setting, level, nodes, parentNode, index) { | |||||
if (_createNodes) _createNodes.apply(view, arguments); | |||||
if (!nodes) return; | |||||
view.repairParentChkClassWithSelf(setting, parentNode); | |||||
} | |||||
var _removeNode = view.removeNode; | |||||
view.removeNode = function (setting, node) { | |||||
var parentNode = node.getParentNode(); | |||||
if (_removeNode) _removeNode.apply(view, arguments); | |||||
if (!node || !parentNode) return; | |||||
view.repairChkClass(setting, parentNode); | |||||
view.repairParentChkClass(setting, parentNode); | |||||
} | |||||
var _appendNodes = view.appendNodes; | |||||
view.appendNodes = function (setting, level, nodes, parentNode, index, initFlag, openFlag) { | |||||
var html = ""; | |||||
if (_appendNodes) { | |||||
html = _appendNodes.apply(view, arguments); | |||||
} | |||||
if (parentNode) { | |||||
data.makeChkFlag(setting, parentNode); | |||||
} | |||||
return html; | |||||
} | |||||
})(jQuery); |
@@ -0,0 +1,405 @@ | |||||
/* | |||||
* JQuery zTree exHideNodes | |||||
* v3.5.48 | |||||
* http://treejs.cn/ | |||||
* | |||||
* Copyright (c) 2010 Hunter.z | |||||
* | |||||
* Licensed same as jquery - MIT License | |||||
* http://www.opensource.org/licenses/mit-license.php | |||||
* | |||||
* Date: 2020-11-21 | |||||
*/ | |||||
(function ($) { | |||||
var _setting = { | |||||
data: { | |||||
key: { | |||||
isHidden: "isHidden" | |||||
} | |||||
} | |||||
}; | |||||
//default init node of exLib | |||||
var _initNode = function (setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) { | |||||
var isHidden = data.isHidden(setting, n); | |||||
data.isHidden(setting, n, isHidden); | |||||
data.initHideForExCheck(setting, n); | |||||
}, | |||||
//add dom for check | |||||
_beforeA = function (setting, node, html) { | |||||
}, | |||||
//update zTreeObj, add method of exLib | |||||
_zTreeTools = function (setting, zTreeTools) { | |||||
zTreeTools.showNodes = function (nodes, options) { | |||||
view.showNodes(setting, nodes, options); | |||||
} | |||||
zTreeTools.showNode = function (node, options) { | |||||
if (!node) { | |||||
return; | |||||
} | |||||
view.showNodes(setting, [node], options); | |||||
} | |||||
zTreeTools.hideNodes = function (nodes, options) { | |||||
view.hideNodes(setting, nodes, options); | |||||
} | |||||
zTreeTools.hideNode = function (node, options) { | |||||
if (!node) { | |||||
return; | |||||
} | |||||
view.hideNodes(setting, [node], options); | |||||
} | |||||
var _checkNode = zTreeTools.checkNode; | |||||
if (_checkNode) { | |||||
zTreeTools.checkNode = function (node, checked, checkTypeFlag, callbackFlag) { | |||||
if (!!node && !!data.isHidden(setting, node)) { | |||||
return; | |||||
} | |||||
_checkNode.apply(zTreeTools, arguments); | |||||
} | |||||
} | |||||
}, | |||||
//method of operate data | |||||
_data = { | |||||
initHideForExCheck: function (setting, n) { | |||||
var isHidden = data.isHidden(setting, n); | |||||
if (isHidden && setting.check && setting.check.enable) { | |||||
if (typeof n._nocheck == "undefined") { | |||||
n._nocheck = !!n.nocheck | |||||
n.nocheck = true; | |||||
} | |||||
n.check_Child_State = -1; | |||||
if (view.repairParentChkClassWithSelf) { | |||||
view.repairParentChkClassWithSelf(setting, n); | |||||
} | |||||
} | |||||
}, | |||||
initShowForExCheck: function (setting, n) { | |||||
var isHidden = data.isHidden(setting, n); | |||||
if (!isHidden && setting.check && setting.check.enable) { | |||||
if (typeof n._nocheck != "undefined") { | |||||
n.nocheck = n._nocheck; | |||||
delete n._nocheck; | |||||
} | |||||
if (view.setChkClass) { | |||||
var checkObj = $$(n, consts.id.CHECK, setting); | |||||
view.setChkClass(setting, checkObj, n); | |||||
} | |||||
if (view.repairParentChkClassWithSelf) { | |||||
view.repairParentChkClassWithSelf(setting, n); | |||||
} | |||||
} | |||||
} | |||||
}, | |||||
//method of operate ztree dom | |||||
_view = { | |||||
clearOldFirstNode: function (setting, node) { | |||||
var n = node.getNextNode(); | |||||
while (!!n) { | |||||
if (n.isFirstNode) { | |||||
n.isFirstNode = false; | |||||
view.setNodeLineIcos(setting, n); | |||||
break; | |||||
} | |||||
if (n.isLastNode) { | |||||
break; | |||||
} | |||||
n = n.getNextNode(); | |||||
} | |||||
}, | |||||
clearOldLastNode: function (setting, node, openFlag) { | |||||
var n = node.getPreNode(); | |||||
while (!!n) { | |||||
if (n.isLastNode) { | |||||
n.isLastNode = false; | |||||
if (openFlag) { | |||||
view.setNodeLineIcos(setting, n); | |||||
} | |||||
break; | |||||
} | |||||
if (n.isFirstNode) { | |||||
break; | |||||
} | |||||
n = n.getPreNode(); | |||||
} | |||||
}, | |||||
makeDOMNodeMainBefore: function (html, setting, node) { | |||||
var isHidden = data.isHidden(setting, node); | |||||
html.push("<li ", (isHidden ? "style='display:none;' " : ""), "id='", node.tId, "' class='", consts.className.LEVEL, node.level, "' tabindex='0' hidefocus='true' treenode>"); | |||||
}, | |||||
showNode: function (setting, node, options) { | |||||
data.isHidden(setting, node, false); | |||||
data.initShowForExCheck(setting, node); | |||||
$$(node, setting).show(); | |||||
}, | |||||
showNodes: function (setting, nodes, options) { | |||||
if (!nodes || nodes.length == 0) { | |||||
return; | |||||
} | |||||
var pList = {}, i, j; | |||||
for (i = 0, j = nodes.length; i < j; i++) { | |||||
var n = nodes[i]; | |||||
if (!pList[n.parentTId]) { | |||||
var pn = n.getParentNode(); | |||||
pList[n.parentTId] = (pn === null) ? data.getRoot(setting) : n.getParentNode(); | |||||
} | |||||
view.showNode(setting, n, options); | |||||
} | |||||
for (var tId in pList) { | |||||
var children = data.nodeChildren(setting, pList[tId]); | |||||
view.setFirstNodeForShow(setting, children); | |||||
view.setLastNodeForShow(setting, children); | |||||
} | |||||
}, | |||||
hideNode: function (setting, node, options) { | |||||
data.isHidden(setting, node, true); | |||||
node.isFirstNode = false; | |||||
node.isLastNode = false; | |||||
data.initHideForExCheck(setting, node); | |||||
view.cancelPreSelectedNode(setting, node); | |||||
$$(node, setting).hide(); | |||||
}, | |||||
hideNodes: function (setting, nodes, options) { | |||||
if (!nodes || nodes.length == 0) { | |||||
return; | |||||
} | |||||
var pList = {}, i, j; | |||||
for (i = 0, j = nodes.length; i < j; i++) { | |||||
var n = nodes[i]; | |||||
if ((n.isFirstNode || n.isLastNode) && !pList[n.parentTId]) { | |||||
var pn = n.getParentNode(); | |||||
pList[n.parentTId] = (pn === null) ? data.getRoot(setting) : n.getParentNode(); | |||||
} | |||||
view.hideNode(setting, n, options); | |||||
} | |||||
for (var tId in pList) { | |||||
var children = data.nodeChildren(setting, pList[tId]); | |||||
view.setFirstNodeForHide(setting, children); | |||||
view.setLastNodeForHide(setting, children); | |||||
} | |||||
}, | |||||
setFirstNode: function (setting, parentNode) { | |||||
var children = data.nodeChildren(setting, parentNode); | |||||
var isHidden = data.isHidden(setting, children[0], false); | |||||
if (children.length > 0 && !isHidden) { | |||||
children[0].isFirstNode = true; | |||||
} else if (children.length > 0) { | |||||
view.setFirstNodeForHide(setting, children); | |||||
} | |||||
}, | |||||
setLastNode: function (setting, parentNode) { | |||||
var children = data.nodeChildren(setting, parentNode); | |||||
var isHidden = data.isHidden(setting, children[0]); | |||||
if (children.length > 0 && !isHidden) { | |||||
children[children.length - 1].isLastNode = true; | |||||
} else if (children.length > 0) { | |||||
view.setLastNodeForHide(setting, children); | |||||
} | |||||
}, | |||||
setFirstNodeForHide: function (setting, nodes) { | |||||
var n, i, j; | |||||
for (i = 0, j = nodes.length; i < j; i++) { | |||||
n = nodes[i]; | |||||
if (n.isFirstNode) { | |||||
break; | |||||
} | |||||
var isHidden = data.isHidden(setting, n); | |||||
if (!isHidden && !n.isFirstNode) { | |||||
n.isFirstNode = true; | |||||
view.setNodeLineIcos(setting, n); | |||||
break; | |||||
} else { | |||||
n = null; | |||||
} | |||||
} | |||||
return n; | |||||
}, | |||||
setFirstNodeForShow: function (setting, nodes) { | |||||
var n, i, j, first, old; | |||||
for (i = 0, j = nodes.length; i < j; i++) { | |||||
n = nodes[i]; | |||||
var isHidden = data.isHidden(setting, n); | |||||
if (!first && !isHidden && n.isFirstNode) { | |||||
first = n; | |||||
break; | |||||
} else if (!first && !isHidden && !n.isFirstNode) { | |||||
n.isFirstNode = true; | |||||
first = n; | |||||
view.setNodeLineIcos(setting, n); | |||||
} else if (first && n.isFirstNode) { | |||||
n.isFirstNode = false; | |||||
old = n; | |||||
view.setNodeLineIcos(setting, n); | |||||
break; | |||||
} else { | |||||
n = null; | |||||
} | |||||
} | |||||
return {"new": first, "old": old}; | |||||
}, | |||||
setLastNodeForHide: function (setting, nodes) { | |||||
var n, i; | |||||
for (i = nodes.length - 1; i >= 0; i--) { | |||||
n = nodes[i]; | |||||
if (n.isLastNode) { | |||||
break; | |||||
} | |||||
var isHidden = data.isHidden(setting, n); | |||||
if (!isHidden && !n.isLastNode) { | |||||
n.isLastNode = true; | |||||
view.setNodeLineIcos(setting, n); | |||||
break; | |||||
} else { | |||||
n = null; | |||||
} | |||||
} | |||||
return n; | |||||
}, | |||||
setLastNodeForShow: function (setting, nodes) { | |||||
var n, i, j, last, old; | |||||
for (i = nodes.length - 1; i >= 0; i--) { | |||||
n = nodes[i]; | |||||
var isHidden = data.isHidden(setting, n); | |||||
if (!last && !isHidden && n.isLastNode) { | |||||
last = n; | |||||
break; | |||||
} else if (!last && !isHidden && !n.isLastNode) { | |||||
n.isLastNode = true; | |||||
last = n; | |||||
view.setNodeLineIcos(setting, n); | |||||
} else if (last && n.isLastNode) { | |||||
n.isLastNode = false; | |||||
old = n; | |||||
view.setNodeLineIcos(setting, n); | |||||
break; | |||||
} else { | |||||
n = null; | |||||
} | |||||
} | |||||
return {"new": last, "old": old}; | |||||
} | |||||
}, | |||||
_z = { | |||||
view: _view, | |||||
data: _data | |||||
}; | |||||
$.extend(true, $.fn.zTree._z, _z); | |||||
var zt = $.fn.zTree, | |||||
tools = zt._z.tools, | |||||
consts = zt.consts, | |||||
view = zt._z.view, | |||||
data = zt._z.data, | |||||
event = zt._z.event, | |||||
$$ = tools.$; | |||||
data.isHidden = function (setting, node, newIsHidden) { | |||||
if (!node) { | |||||
return false; | |||||
} | |||||
var key = setting.data.key.isHidden; | |||||
if (typeof newIsHidden !== 'undefined') { | |||||
if (typeof newIsHidden === "string") { | |||||
newIsHidden = tools.eqs(newIsHidden, "true"); | |||||
} | |||||
newIsHidden = !!newIsHidden; | |||||
node[key] = newIsHidden; | |||||
} else if (typeof node[key] == "string"){ | |||||
node[key] = tools.eqs(node[key], "true"); | |||||
} else { | |||||
node[key] = !!node[key]; | |||||
} | |||||
return node[key]; | |||||
}; | |||||
data.exSetting(_setting); | |||||
data.addInitNode(_initNode); | |||||
data.addBeforeA(_beforeA); | |||||
data.addZTreeTools(_zTreeTools); | |||||
// Override method in core | |||||
var _dInitNode = data.initNode; | |||||
data.initNode = function (setting, level, node, parentNode, isFirstNode, isLastNode, openFlag) { | |||||
var tmpPNode = (parentNode) ? parentNode : data.getRoot(setting), | |||||
children = tmpPNode[setting.data.key.children]; | |||||
data.tmpHideFirstNode = view.setFirstNodeForHide(setting, children); | |||||
data.tmpHideLastNode = view.setLastNodeForHide(setting, children); | |||||
if (openFlag) { | |||||
view.setNodeLineIcos(setting, data.tmpHideFirstNode); | |||||
view.setNodeLineIcos(setting, data.tmpHideLastNode); | |||||
} | |||||
isFirstNode = (data.tmpHideFirstNode === node); | |||||
isLastNode = (data.tmpHideLastNode === node); | |||||
if (_dInitNode) _dInitNode.apply(data, arguments); | |||||
if (openFlag && isLastNode) { | |||||
view.clearOldLastNode(setting, node, openFlag); | |||||
} | |||||
}; | |||||
var _makeChkFlag = data.makeChkFlag; | |||||
if (!!_makeChkFlag) { | |||||
data.makeChkFlag = function (setting, node) { | |||||
if (!!node && !!data.isHidden(setting, node)) { | |||||
return; | |||||
} | |||||
_makeChkFlag.apply(data, arguments); | |||||
} | |||||
} | |||||
var _getTreeCheckedNodes = data.getTreeCheckedNodes; | |||||
if (!!_getTreeCheckedNodes) { | |||||
data.getTreeCheckedNodes = function (setting, nodes, checked, results) { | |||||
if (!!nodes && nodes.length > 0) { | |||||
var p = nodes[0].getParentNode(); | |||||
if (!!p && !!data.isHidden(setting, p)) { | |||||
return []; | |||||
} | |||||
} | |||||
return _getTreeCheckedNodes.apply(data, arguments); | |||||
} | |||||
} | |||||
var _getTreeChangeCheckedNodes = data.getTreeChangeCheckedNodes; | |||||
if (!!_getTreeChangeCheckedNodes) { | |||||
data.getTreeChangeCheckedNodes = function (setting, nodes, results) { | |||||
if (!!nodes && nodes.length > 0) { | |||||
var p = nodes[0].getParentNode(); | |||||
if (!!p && !!data.isHidden(setting, p)) { | |||||
return []; | |||||
} | |||||
} | |||||
return _getTreeChangeCheckedNodes.apply(data, arguments); | |||||
} | |||||
} | |||||
var _expandCollapseSonNode = view.expandCollapseSonNode; | |||||
if (!!_expandCollapseSonNode) { | |||||
view.expandCollapseSonNode = function (setting, node, expandFlag, animateFlag, callback) { | |||||
if (!!node && !!data.isHidden(setting, node)) { | |||||
return; | |||||
} | |||||
_expandCollapseSonNode.apply(view, arguments); | |||||
} | |||||
} | |||||
var _setSonNodeCheckBox = view.setSonNodeCheckBox; | |||||
if (!!_setSonNodeCheckBox) { | |||||
view.setSonNodeCheckBox = function (setting, node, value, srcNode) { | |||||
if (!!node && !!data.isHidden(setting, node)) { | |||||
return; | |||||
} | |||||
_setSonNodeCheckBox.apply(view, arguments); | |||||
} | |||||
} | |||||
var _repairParentChkClassWithSelf = view.repairParentChkClassWithSelf; | |||||
if (!!_repairParentChkClassWithSelf) { | |||||
view.repairParentChkClassWithSelf = function (setting, node) { | |||||
if (!!node && !!data.isHidden(setting, node)) { | |||||
return; | |||||
} | |||||
_repairParentChkClassWithSelf.apply(view, arguments); | |||||
} | |||||
} | |||||
})(jQuery); |
@@ -930,6 +930,12 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
}) | }) | ||||
}) | }) | ||||
}, reqRepoReader(models.UnitTypeCloudBrain)) | }, reqRepoReader(models.UnitTypeCloudBrain)) | ||||
m.Group("/modelmanage", func() { | |||||
m.Get("/:id", repo.GetCloudbrainModelConvertTask) | |||||
m.Get("/:id/log", repo.CloudbrainForModelConvertGetLog) | |||||
m.Get("/:id/modelartlog", repo.TrainJobForModelConvertGetLog) | |||||
m.Get("/:id/model_list", repo.CloudBrainModelConvertList) | |||||
}, reqRepoReader(models.UnitTypeModelManage)) | |||||
m.Group("/modelarts", func() { | m.Group("/modelarts", func() { | ||||
m.Group("/notebook", func() { | m.Group("/notebook", func() { | ||||
//m.Get("/:jobid", repo.GetModelArtsNotebook) | //m.Get("/:jobid", repo.GetModelArtsNotebook) | ||||
@@ -6,17 +6,19 @@ | |||||
package repo | package repo | ||||
import ( | import ( | ||||
"code.gitea.io/gitea/modules/setting" | |||||
"encoding/json" | "encoding/json" | ||||
"net/http" | "net/http" | ||||
"sort" | "sort" | ||||
"strings" | "strings" | ||||
"time" | "time" | ||||
"code.gitea.io/gitea/modules/setting" | |||||
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
"code.gitea.io/gitea/modules/cloudbrain" | "code.gitea.io/gitea/modules/cloudbrain" | ||||
"code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
"code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
"code.gitea.io/gitea/modules/modelarts" | |||||
"code.gitea.io/gitea/modules/storage" | "code.gitea.io/gitea/modules/storage" | ||||
routerRepo "code.gitea.io/gitea/routers/repo" | routerRepo "code.gitea.io/gitea/routers/repo" | ||||
) | ) | ||||
@@ -217,21 +219,87 @@ func InferencJobResultList(ctx *context.APIContext) { | |||||
} | } | ||||
func CloudbrainGetLog(ctx *context.Context) { | |||||
func GetCloudbrainModelConvertTask(ctx *context.APIContext) { | |||||
var ( | |||||
err error | |||||
) | |||||
ID := ctx.Params(":id") | ID := ctx.Params(":id") | ||||
job, err := models.GetCloudbrainByID(ID) | |||||
job, err := models.QueryModelConvertById(ID) | |||||
if err != nil { | if err != nil { | ||||
log.Error("GetCloudbrainByJobName failed: %v", err, ctx.Data["MsgID"]) | |||||
ctx.ServerError(err.Error(), err) | |||||
ctx.NotFound(err) | |||||
log.Error("GetCloudbrainByID failed:", err) | |||||
return | return | ||||
} | } | ||||
if job.IsGpuTrainTask() { | |||||
jobResult, err := cloudbrain.GetJob(job.CloudBrainTaskId) | |||||
if err != nil { | |||||
ctx.NotFound(err) | |||||
log.Error("GetJob failed:", err) | |||||
return | |||||
} | |||||
result, _ := models.ConvertToJobResultPayload(jobResult.Payload) | |||||
if err != nil { | |||||
ctx.NotFound(err) | |||||
log.Error("ConvertToJobResultPayload failed:", err) | |||||
return | |||||
} | |||||
job.Status = result.JobStatus.State | |||||
taskRoles := result.TaskRoles | |||||
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) | |||||
if result.JobStatus.State != string(models.JobWaiting) && result.JobStatus.State != string(models.JobFailed) { | |||||
job.ContainerIp = taskRes.TaskStatuses[0].ContainerIP | |||||
job.ContainerID = taskRes.TaskStatuses[0].ContainerID | |||||
job.Status = taskRes.TaskStatuses[0].State | |||||
} | |||||
if result.JobStatus.State != string(models.JobWaiting) { | |||||
models.ModelComputeAndSetDuration(job, result) | |||||
err = models.UpdateModelConvert(job) | |||||
if err != nil { | |||||
log.Error("UpdateJob failed:", err) | |||||
} | |||||
} | |||||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||||
"ID": ID, | |||||
"JobName": result.Config.JobName, | |||||
"JobStatus": result.JobStatus.State, | |||||
"SubState": result.JobStatus.SubState, | |||||
"CreatedTime": time.Unix(result.JobStatus.CreatedTime/1000, 0).Format("2006-01-02 15:04:05"), | |||||
"CompletedTime": time.Unix(result.JobStatus.CompletedTime/1000, 0).Format("2006-01-02 15:04:05"), | |||||
}) | |||||
} else { | |||||
result, err := modelarts.GetTrainJob(job.CloudBrainTaskId, job.ModelArtsVersionId) | |||||
if err != nil { | |||||
log.Error("get modelart job failed:", err) | |||||
ctx.NotFound(err) | |||||
return | |||||
} | |||||
job.Status = modelarts.TransTrainJobStatus(result.IntStatus) | |||||
job.RunTime = result.Duration / 1000 | |||||
job.TrainJobDuration = models.ConvertDurationToStr(job.RunTime) | |||||
err = models.UpdateModelConvert(job) | |||||
if err != nil { | |||||
log.Error("UpdateJob failed:", err) | |||||
} | |||||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||||
"ID": ID, | |||||
"JobStatus": job.Status, | |||||
}) | |||||
} | |||||
} | |||||
func CloudbrainGetLogByJobId(jobId string, jobName string) map[string]interface{} { | |||||
var hits []models.Hits | var hits []models.Hits | ||||
result, err := cloudbrain.GetJobLog(job.JobID) | |||||
result, err := cloudbrain.GetJobLog(jobId) | |||||
if err != nil { | if err != nil { | ||||
log.Error("GetJobLog failed: %v", err, ctx.Data["MsgID"]) | |||||
ctx.ServerError(err.Error(), err) | |||||
return | |||||
log.Error("GetJobLog failed: %v", err) | |||||
return nil | |||||
} | } | ||||
hits = result.Hits.Hits | hits = result.Hits.Hits | ||||
@@ -240,7 +308,7 @@ func CloudbrainGetLog(ctx *context.Context) { | |||||
for { | for { | ||||
resultNext, err := cloudbrain.GetJobAllLog(result.ScrollID) | resultNext, err := cloudbrain.GetJobAllLog(result.ScrollID) | ||||
if err != nil { | if err != nil { | ||||
log.Error("GetJobAllLog failed: %v", err, ctx.Data["MsgID"]) | |||||
log.Error("GetJobAllLog failed: %v", err) | |||||
} else { | } else { | ||||
for _, hit := range resultNext.Hits.Hits { | for _, hit := range resultNext.Hits.Hits { | ||||
hits = append(hits, hit) | hits = append(hits, hit) | ||||
@@ -265,12 +333,122 @@ func CloudbrainGetLog(ctx *context.Context) { | |||||
content += log.Source.Message + "\n" | content += log.Source.Message + "\n" | ||||
} | } | ||||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||||
"JobName": job.JobName, | |||||
return map[string]interface{}{ | |||||
"JobName": jobName, | |||||
"Content": content, | "Content": content, | ||||
}) | |||||
} | |||||
} | |||||
func CloudbrainForModelConvertGetLog(ctx *context.Context) { | |||||
ID := ctx.Params(":id") | |||||
job, err := models.QueryModelConvertById(ID) | |||||
if err != nil { | |||||
log.Error("GetCloudbrainByJobName failed: %v", err, ctx.Data["MsgID"]) | |||||
ctx.ServerError(err.Error(), err) | |||||
return | |||||
} | |||||
result := CloudbrainGetLogByJobId(job.CloudBrainTaskId, job.Name) | |||||
if result == nil { | |||||
log.Error("GetJobLog failed: %v", err, ctx.Data["MsgID"]) | |||||
ctx.ServerError(err.Error(), err) | |||||
return | |||||
} | |||||
ctx.JSON(http.StatusOK, result) | |||||
} | |||||
func CloudbrainGetLog(ctx *context.Context) { | |||||
ID := ctx.Params(":id") | |||||
job, err := models.GetCloudbrainByID(ID) | |||||
if err != nil { | |||||
log.Error("GetCloudbrainByJobName failed: %v", err, ctx.Data["MsgID"]) | |||||
ctx.ServerError(err.Error(), err) | |||||
return | |||||
} | |||||
result := CloudbrainGetLogByJobId(job.JobID, job.JobName) | |||||
if result == nil { | |||||
log.Error("GetJobLog failed: %v", err, ctx.Data["MsgID"]) | |||||
ctx.ServerError(err.Error(), err) | |||||
return | |||||
} | |||||
ctx.JSON(http.StatusOK, result) | |||||
} | |||||
func CloudBrainModelConvertList(ctx *context.APIContext) { | |||||
var ( | |||||
err error | |||||
) | |||||
ID := ctx.Params(":id") | |||||
parentDir := ctx.Query("parentDir") | |||||
dirArray := strings.Split(parentDir, "/") | |||||
job, err := models.QueryModelConvertById(ID) | |||||
if err != nil { | |||||
log.Error("GetCloudbrainByJobID(%s) failed:%v", job.Name, err.Error()) | |||||
return | |||||
} | |||||
if job.IsGpuTrainTask() { | |||||
//get dirs | |||||
dirs, err := routerRepo.GetModelDirs(job.ID, parentDir) | |||||
if err != nil { | |||||
log.Error("GetModelDirs failed:%v", err.Error(), ctx.Data["msgID"]) | |||||
ctx.ServerError("GetModelDirs failed:", err) | |||||
return | |||||
} | |||||
var fileInfos []storage.FileInfo | |||||
err = json.Unmarshal([]byte(dirs), &fileInfos) | |||||
if err != nil { | |||||
log.Error("json.Unmarshal failed:%v", err.Error(), ctx.Data["msgID"]) | |||||
ctx.ServerError("json.Unmarshal failed:", err) | |||||
return | |||||
} | |||||
for i, fileInfo := range fileInfos { | |||||
temp, _ := time.Parse("2006-01-02 15:04:05", fileInfo.ModTime) | |||||
fileInfos[i].ModTime = temp.Local().Format("2006-01-02 15:04:05") | |||||
} | |||||
sort.Slice(fileInfos, func(i, j int) bool { | |||||
return fileInfos[i].ModTime > fileInfos[j].ModTime | |||||
}) | |||||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||||
"JobID": ID, | |||||
"VersionName": "", | |||||
"StatusOK": 0, | |||||
"Path": dirArray, | |||||
"Dirs": fileInfos, | |||||
"task": job, | |||||
"PageIsCloudBrain": true, | |||||
}) | |||||
} else { | |||||
var jobID = ctx.Params(":id") | |||||
var versionName = "V0001" | |||||
parentDir := ctx.Query("parentDir") | |||||
dirArray := strings.Split(parentDir, "/") | |||||
models, err := storage.GetObsListObject(job.ID, "output/", parentDir, versionName) | |||||
if err != nil { | |||||
log.Info("get TrainJobListModel failed:", err) | |||||
ctx.ServerError("GetObsListObject:", err) | |||||
return | |||||
} | |||||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||||
"JobID": jobID, | |||||
"VersionName": versionName, | |||||
"StatusOK": 0, | |||||
"Path": dirArray, | |||||
"Dirs": models, | |||||
"task": job, | |||||
"PageIsCloudBrain": true, | |||||
}) | |||||
} | |||||
return | |||||
} | } | ||||
func CloudBrainModelList(ctx *context.APIContext) { | func CloudBrainModelList(ctx *context.APIContext) { | ||||
@@ -6,14 +6,15 @@ | |||||
package repo | package repo | ||||
import ( | import ( | ||||
"code.gitea.io/gitea/modules/grampus" | |||||
"code.gitea.io/gitea/modules/setting" | |||||
"encoding/json" | "encoding/json" | ||||
"net/http" | "net/http" | ||||
"path" | "path" | ||||
"strconv" | "strconv" | ||||
"strings" | "strings" | ||||
"code.gitea.io/gitea/modules/grampus" | |||||
"code.gitea.io/gitea/modules/setting" | |||||
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
"code.gitea.io/gitea/modules/cloudbrain" | "code.gitea.io/gitea/modules/cloudbrain" | ||||
"code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
@@ -242,6 +243,75 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) { | |||||
} | } | ||||
func TrainJobForModelConvertGetLog(ctx *context.APIContext) { | |||||
var ( | |||||
err error | |||||
) | |||||
var jobID = ctx.Params(":id") | |||||
var baseLine = ctx.Query("base_line") | |||||
var order = ctx.Query("order") | |||||
var lines = ctx.Query("lines") | |||||
lines_int, err := strconv.Atoi(lines) | |||||
if err != nil { | |||||
log.Error("change lines(%d) string to int failed", lines_int) | |||||
} | |||||
if order != modelarts.OrderDesc && order != modelarts.OrderAsc { | |||||
log.Error("order(%s) check failed", order) | |||||
ctx.JSON(http.StatusBadRequest, map[string]interface{}{ | |||||
"err_msg": "order check failed", | |||||
}) | |||||
return | |||||
} | |||||
resultLogFile, result, err := trainJobForModelConvertGetLogContent(jobID, baseLine, order, lines_int) | |||||
if err != nil { | |||||
log.Error("trainJobGetLog(%s) failed:%v", jobID, err.Error()) | |||||
// ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | |||||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||||
"JobID": jobID, | |||||
"LogFileName": "", | |||||
"StartLine": "0", | |||||
"EndLine": "0", | |||||
"Content": "", | |||||
"Lines": 0, | |||||
}) | |||||
return | |||||
} | |||||
ctx.Data["log_file_name"] = resultLogFile.LogFileList[0] | |||||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||||
"JobID": jobID, | |||||
"LogFileName": resultLogFile.LogFileList[0], | |||||
"StartLine": result.StartLine, | |||||
"EndLine": result.EndLine, | |||||
"Content": result.Content, | |||||
"Lines": result.Lines, | |||||
}) | |||||
} | |||||
func trainJobForModelConvertGetLogContent(jobID string, baseLine string, order string, lines int) (*models.GetTrainJobLogFileNamesResult, *models.GetTrainJobLogResult, error) { | |||||
task, err := models.QueryModelConvertById(jobID) | |||||
if err != nil { | |||||
log.Error("GetCloudbrainByJobID(%s) failed:%v", jobID, err.Error()) | |||||
return nil, nil, err | |||||
} | |||||
resultLogFile, err := modelarts.GetTrainJobLogFileNames(task.CloudBrainTaskId, task.ModelArtsVersionId) | |||||
if err != nil { | |||||
log.Error("GetTrainJobLogFileNames(%s) failed:%v", task.CloudBrainTaskId, err.Error()) | |||||
return nil, nil, err | |||||
} | |||||
result, err := modelarts.GetTrainJobLog(task.CloudBrainTaskId, task.ModelArtsVersionId, baseLine, resultLogFile.LogFileList[0], order, lines) | |||||
if err != nil { | |||||
log.Error("GetTrainJobLog(%s) failed:%v", task.CloudBrainTaskId, err.Error()) | |||||
return nil, nil, err | |||||
} | |||||
return resultLogFile, result, err | |||||
} | |||||
func TrainJobGetLog(ctx *context.APIContext) { | func TrainJobGetLog(ctx *context.APIContext) { | ||||
var ( | var ( | ||||
err error | err error | ||||
@@ -0,0 +1,795 @@ | |||||
package repo | |||||
import ( | |||||
"bufio" | |||||
"encoding/json" | |||||
"errors" | |||||
"fmt" | |||||
"io" | |||||
"io/ioutil" | |||||
"net/http" | |||||
"os" | |||||
"path" | |||||
"strings" | |||||
"code.gitea.io/gitea/models" | |||||
"code.gitea.io/gitea/modules/cloudbrain" | |||||
"code.gitea.io/gitea/modules/context" | |||||
"code.gitea.io/gitea/modules/git" | |||||
"code.gitea.io/gitea/modules/log" | |||||
"code.gitea.io/gitea/modules/modelarts" | |||||
"code.gitea.io/gitea/modules/setting" | |||||
"code.gitea.io/gitea/modules/storage" | |||||
"code.gitea.io/gitea/modules/timeutil" | |||||
uuid "github.com/satori/go.uuid" | |||||
) | |||||
const ( | |||||
tplModelManageConvertIndex = "repo/modelmanage/convertIndex" | |||||
tplModelConvertInfo = "repo/modelmanage/convertshowinfo" | |||||
PYTORCH_ENGINE = 0 | |||||
TENSORFLOW_ENGINE = 1 | |||||
MINDSPORE_ENGIN = 2 | |||||
ModelMountPath = "/model" | |||||
CodeMountPath = "/code" | |||||
DataSetMountPath = "/dataset" | |||||
LogFile = "log.txt" | |||||
DefaultBranchName = "master" | |||||
SubTaskName = "task1" | |||||
//GpuQueue = "openidgx" | |||||
Success = "S000" | |||||
//GPU_PYTORCH_IMAGE = "dockerhub.pcl.ac.cn:5000/user-images/openi:tensorRT_7_zouap" | |||||
//GPU_TENSORFLOW_IMAGE = "dockerhub.pcl.ac.cn:5000/user-images/openi:tf2onnx" | |||||
//NPU_MINDSPORE_16_IMAGE = "swr.cn-south-222.ai.pcl.cn/openi/mindspore1.6.1_train_v1_openi:v3_ascend" | |||||
//PytorchOnnxBootFile = "convert_pytorch.py" | |||||
//PytorchTrTBootFile = "convert_pytorch_tensorrt.py" | |||||
//MindsporeBootFile = "convert_mindspore.py" | |||||
//TensorFlowNpuBootFile = "convert_tensorflow.py" | |||||
//TensorFlowGpuBootFile = "convert_tensorflow_gpu.py" | |||||
//ConvertRepoPath = "https://git.openi.org.cn/zouap/npu_test" | |||||
CONVERT_FORMAT_ONNX = 0 | |||||
CONVERT_FORMAT_TRT = 1 | |||||
NetOutputFormat_FP32 = 0 | |||||
NetOutputFormat_FP16 = 1 | |||||
NPU_MINDSPORE_IMAGE_ID = 35 | |||||
NPU_TENSORFLOW_IMAGE_ID = 121 | |||||
//GPU_Resource_Specs_ID = 1 //cpu 1, gpu 1 | |||||
//NPU_FlavorCode = "modelarts.bm.910.arm.public.1" | |||||
//NPU_PoolID = "pool7908321a" | |||||
) | |||||
var ( | |||||
TrainResourceSpecs *models.ResourceSpecs | |||||
) | |||||
func SaveModelConvert(ctx *context.Context) { | |||||
log.Info("save model convert start.") | |||||
if !ctx.Repo.CanWrite(models.UnitTypeModelManage) { | |||||
ctx.JSON(200, map[string]string{ | |||||
"result_code": "1", | |||||
"message": ctx.Tr("repo.modelconvert.manage.no_operate_right"), | |||||
}) | |||||
return | |||||
} | |||||
name := ctx.Query("name") | |||||
desc := ctx.Query("desc") | |||||
modelId := ctx.Query("modelId") | |||||
modelPath := ctx.Query("ModelFile") | |||||
SrcEngine := ctx.QueryInt("SrcEngine") | |||||
InputShape := ctx.Query("inputshape") | |||||
InputDataFormat := ctx.Query("inputdataformat") | |||||
DestFormat := ctx.QueryInt("DestFormat") | |||||
NetOutputFormat := ctx.QueryInt("NetOutputFormat") | |||||
task, err := models.QueryModelById(modelId) | |||||
if err != nil { | |||||
log.Error("no such model!", err.Error()) | |||||
ctx.JSON(200, map[string]string{ | |||||
"result_code": "1", | |||||
"message": ctx.Tr("repo.modelconvert.manage.model_not_exist"), | |||||
}) | |||||
return | |||||
} | |||||
convertList, err := models.QueryModelConvertByRepoID(ctx.Repo.Repository.ID) | |||||
if err == nil { | |||||
for _, convert := range convertList { | |||||
if convert.Name == name { | |||||
log.Info("convert.Name=" + name + " convert.id=" + convert.ID) | |||||
ctx.JSON(200, map[string]string{ | |||||
"result_code": "1", | |||||
"message": ctx.Tr("repo.modelconvert.manage.create_error1"), | |||||
}) | |||||
return | |||||
} | |||||
} | |||||
} | |||||
convertList, err = models.QueryModelConvertByUserID(ctx.User.ID) | |||||
if err == nil { | |||||
for _, convert := range convertList { | |||||
if isRunningTask(convert.Status) { | |||||
log.Info("convert.Status=" + convert.Status + " convert.id=" + convert.ID) | |||||
ctx.JSON(200, map[string]string{ | |||||
"result_code": "1", | |||||
"message": ctx.Tr("repo.modelconvert.manage.create_error2"), | |||||
}) | |||||
return | |||||
} | |||||
} | |||||
} | |||||
uuid := uuid.NewV4() | |||||
id := uuid.String() | |||||
modelConvert := &models.AiModelConvert{ | |||||
ID: id, | |||||
Name: name, | |||||
Description: desc, | |||||
Status: string(models.JobWaiting), | |||||
SrcEngine: SrcEngine, | |||||
RepoId: ctx.Repo.Repository.ID, | |||||
ModelName: task.Name, | |||||
ModelVersion: task.Version, | |||||
ModelId: modelId, | |||||
ModelPath: modelPath, | |||||
DestFormat: DestFormat, | |||||
NetOutputFormat: NetOutputFormat, | |||||
InputShape: InputShape, | |||||
InputDataFormat: InputDataFormat, | |||||
UserId: ctx.User.ID, | |||||
} | |||||
models.SaveModelConvert(modelConvert) | |||||
go goCreateTask(modelConvert, ctx, task) | |||||
ctx.JSON(200, map[string]string{ | |||||
"result_code": "0", | |||||
}) | |||||
} | |||||
func isRunningTask(status string) bool { | |||||
stopStatus := []string{"COMPLETED", "STOPPED", "FAILED", "START_FAILED", "STOPPING", "SUCCEEDED"} | |||||
for _, sta := range stopStatus { | |||||
if sta == status { | |||||
return false | |||||
} | |||||
} | |||||
return true | |||||
} | |||||
func goCreateTask(modelConvert *models.AiModelConvert, ctx *context.Context, task *models.AiModelManage) error { | |||||
if modelConvert.IsGpuTrainTask() { | |||||
log.Info("create gpu train job.") | |||||
return createGpuTrainJob(modelConvert, ctx, task) | |||||
} else { | |||||
//create npu job | |||||
log.Info("create npu train job.") | |||||
return createNpuTrainJob(modelConvert, ctx, task.Path) | |||||
} | |||||
} | |||||
func createNpuTrainJob(modelConvert *models.AiModelConvert, ctx *context.Context, modelRelativePath string) error { | |||||
VersionOutputPath := "V0001" | |||||
codeLocalPath := setting.JobPath + modelConvert.ID + modelarts.CodePath | |||||
codeObsPath := "/" + setting.Bucket + modelarts.JobPath + modelConvert.ID + modelarts.CodePath | |||||
outputObsPath := "/" + setting.Bucket + modelarts.JobPath + modelConvert.ID + modelarts.OutputPath + VersionOutputPath + "/" | |||||
logObsPath := "/" + setting.Bucket + modelarts.JobPath + modelConvert.ID + modelarts.LogPath + VersionOutputPath + "/" | |||||
dataPath := "/" + modelRelativePath | |||||
_, err := ioutil.ReadDir(codeLocalPath) | |||||
if err == nil { | |||||
deleteLocalDir(codeLocalPath) | |||||
} | |||||
if err := downloadConvertCode(setting.ModelConvert.ConvertRepoPath, codeLocalPath, DefaultBranchName); err != nil { | |||||
log.Error("downloadCode failed, server timed out: %s (%v)", setting.ModelConvert.ConvertRepoPath, err) | |||||
return err | |||||
} | |||||
if err := obsMkdir(setting.CodePathPrefix + modelConvert.ID + modelarts.OutputPath + VersionOutputPath + "/"); err != nil { | |||||
log.Error("Failed to obsMkdir_output: %s (%v)", modelConvert.ID+modelarts.OutputPath, err) | |||||
return err | |||||
} | |||||
if err := obsMkdir(setting.CodePathPrefix + modelConvert.ID + modelarts.LogPath + VersionOutputPath + "/"); err != nil { | |||||
log.Error("Failed to obsMkdir_log: %s (%v)", modelConvert.ID+modelarts.LogPath, err) | |||||
return err | |||||
} | |||||
if err := uploadCodeToObs(codeLocalPath, modelConvert.ID, ""); err != nil { | |||||
log.Error("Failed to uploadCodeToObs: %s (%v)", modelConvert.ID, err) | |||||
return err | |||||
} | |||||
deleteLocalDir(codeLocalPath) | |||||
intputshape := strings.Split(modelConvert.InputShape, ",") | |||||
n := "256" | |||||
c := "1" | |||||
h := "28" | |||||
w := "28" | |||||
if len(intputshape) == 4 { | |||||
n = intputshape[0] | |||||
c = intputshape[1] | |||||
h = intputshape[2] | |||||
w = intputshape[3] | |||||
} | |||||
var engineId int64 | |||||
engineId = int64(NPU_MINDSPORE_IMAGE_ID) | |||||
bootfile := setting.ModelConvert.MindsporeBootFile | |||||
if modelConvert.SrcEngine == TENSORFLOW_ENGINE { | |||||
engineId = int64(NPU_TENSORFLOW_IMAGE_ID) | |||||
bootfile = setting.ModelConvert.TensorFlowNpuBootFile | |||||
} | |||||
userCommand := "/bin/bash /home/work/run_train.sh 's3://" + codeObsPath + "' 'code/" + bootfile + "' '/tmp/log/train.log' --'data_url'='s3://" + dataPath + "' --'train_url'='s3://" + outputObsPath + "'" | |||||
userCommand += " --'model'='" + modelConvert.ModelPath + "'" | |||||
userCommand += " --'n'='" + fmt.Sprint(n) + "'" | |||||
userCommand += " --'c'='" + fmt.Sprint(c) + "'" | |||||
userCommand += " --'h'='" + fmt.Sprint(h) + "'" | |||||
userCommand += " --'w'='" + fmt.Sprint(w) + "'" | |||||
req := &modelarts.GenerateTrainJobReq{ | |||||
JobName: modelConvert.ID, | |||||
DisplayJobName: modelConvert.Name, | |||||
DataUrl: dataPath, | |||||
Description: modelConvert.Description, | |||||
CodeObsPath: codeObsPath, | |||||
BootFileUrl: codeObsPath + bootfile, | |||||
BootFile: bootfile, | |||||
TrainUrl: outputObsPath, | |||||
FlavorCode: setting.ModelConvert.NPU_FlavorCode, | |||||
WorkServerNumber: 1, | |||||
IsLatestVersion: modelarts.IsLatestVersion, | |||||
EngineID: engineId, | |||||
LogUrl: logObsPath, | |||||
PoolID: setting.ModelConvert.NPU_PoolID, | |||||
//Parameters: param, | |||||
BranchName: DefaultBranchName, | |||||
UserImageUrl: setting.ModelConvert.NPU_MINDSPORE_16_IMAGE, | |||||
UserCommand: userCommand, | |||||
} | |||||
result, err := modelarts.GenerateModelConvertTrainJob(req) | |||||
if err == nil { | |||||
log.Info("jobId=" + fmt.Sprint(result.JobID) + " versionid=" + fmt.Sprint(result.VersionID)) | |||||
models.UpdateModelConvertModelArts(modelConvert.ID, fmt.Sprint(result.JobID), fmt.Sprint(result.VersionID)) | |||||
} else { | |||||
log.Info("create modelarts taks failed.error=" + err.Error()) | |||||
models.UpdateModelConvertFailed(modelConvert.ID, "FAILED", err.Error()) | |||||
} | |||||
return err | |||||
} | |||||
func downloadConvertCode(repopath string, codePath, branchName string) error { | |||||
//add "file:///" prefix to make the depth valid | |||||
if err := git.Clone(repopath, codePath, git.CloneRepoOptions{Branch: branchName, Depth: 1}); err != nil { | |||||
log.Error("Failed to clone repository: %s (%v)", repopath, err) | |||||
return err | |||||
} | |||||
log.Info("srcPath=" + repopath + " codePath=" + codePath) | |||||
configFile, err := os.OpenFile(codePath+"/.git/config", os.O_RDWR, 0666) | |||||
if err != nil { | |||||
log.Error("open file(%s) failed:%v", codePath+"/,git/config", err) | |||||
return err | |||||
} | |||||
defer configFile.Close() | |||||
pos := int64(0) | |||||
reader := bufio.NewReader(configFile) | |||||
for { | |||||
line, err := reader.ReadString('\n') | |||||
if err != nil { | |||||
if err == io.EOF { | |||||
log.Error("not find the remote-url") | |||||
return nil | |||||
} else { | |||||
log.Error("read error: %v", err) | |||||
return err | |||||
} | |||||
} | |||||
if strings.Contains(line, "url") && strings.Contains(line, ".git") { | |||||
originUrl := "\turl = " + repopath + "\n" | |||||
if len(line) > len(originUrl) { | |||||
originUrl += strings.Repeat(" ", len(line)-len(originUrl)) | |||||
} | |||||
bytes := []byte(originUrl) | |||||
_, err := configFile.WriteAt(bytes, pos) | |||||
if err != nil { | |||||
log.Error("WriteAt failed:%v", err) | |||||
return err | |||||
} | |||||
break | |||||
} | |||||
pos += int64(len(line)) | |||||
} | |||||
return nil | |||||
} | |||||
func downloadFromObsToLocal(task *models.AiModelManage, localPath string) error { | |||||
path := Model_prefix + models.AttachmentRelativePath(task.ID) + "/" | |||||
allFile, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, path) | |||||
if err == nil { | |||||
_, errState := os.Stat(localPath) | |||||
if errState != nil { | |||||
if err = os.MkdirAll(localPath, os.ModePerm); err != nil { | |||||
return err | |||||
} | |||||
} | |||||
for _, oneFile := range allFile { | |||||
if oneFile.IsDir { | |||||
log.Info(" dir name:" + oneFile.FileName) | |||||
} else { | |||||
allFileName := localPath + "/" + oneFile.FileName | |||||
index := strings.LastIndex(allFileName, "/") | |||||
if index != -1 { | |||||
parentDir := allFileName[0:index] | |||||
if err = os.MkdirAll(parentDir, os.ModePerm); err != nil { | |||||
log.Info("make dir may be error," + err.Error()) | |||||
} | |||||
} | |||||
fDest, err := os.Create(allFileName) | |||||
if err != nil { | |||||
log.Info("create file error, download file failed: %s\n", err.Error()) | |||||
return err | |||||
} | |||||
body, err := storage.ObsDownloadAFile(setting.Bucket, path+oneFile.FileName) | |||||
if err != nil { | |||||
log.Info("download file failed: %s\n", err.Error()) | |||||
return err | |||||
} else { | |||||
defer body.Close() | |||||
p := make([]byte, 1024) | |||||
var readErr error | |||||
var readCount int | |||||
// 读取对象内容 | |||||
for { | |||||
readCount, readErr = body.Read(p) | |||||
if readCount > 0 { | |||||
fDest.Write(p[:readCount]) | |||||
} | |||||
if readErr != nil { | |||||
break | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} else { | |||||
log.Info("error,msg=" + err.Error()) | |||||
return err | |||||
} | |||||
return nil | |||||
} | |||||
func createGpuTrainJob(modelConvert *models.AiModelConvert, ctx *context.Context, model *models.AiModelManage) error { | |||||
modelRelativePath := model.Path | |||||
command := "" | |||||
IMAGE_URL := setting.ModelConvert.GPU_PYTORCH_IMAGE | |||||
dataActualPath := setting.Attachment.Minio.RealPath + modelRelativePath | |||||
if modelConvert.SrcEngine == PYTORCH_ENGINE { | |||||
if modelConvert.DestFormat == CONVERT_FORMAT_ONNX { | |||||
command = getGpuModelConvertCommand(modelConvert.ID, modelConvert.ModelPath, modelConvert, setting.ModelConvert.PytorchOnnxBootFile) | |||||
} else if modelConvert.DestFormat == CONVERT_FORMAT_TRT { | |||||
command = getGpuModelConvertCommand(modelConvert.ID, modelConvert.ModelPath, modelConvert, setting.ModelConvert.PytorchTrTBootFile) | |||||
} else { | |||||
return errors.New("Not support the format.") | |||||
} | |||||
} else if modelConvert.SrcEngine == TENSORFLOW_ENGINE { | |||||
IMAGE_URL = setting.ModelConvert.GPU_TENSORFLOW_IMAGE | |||||
if modelConvert.DestFormat == CONVERT_FORMAT_ONNX { | |||||
command = getGpuModelConvertCommand(modelConvert.ID, modelConvert.ModelPath, modelConvert, setting.ModelConvert.TensorFlowGpuBootFile) | |||||
} else { | |||||
return errors.New("Not support the format.") | |||||
} | |||||
//如果模型在OBS上,需要下载到本地,并上传到minio中 | |||||
if model.Type == models.TypeCloudBrainTwo { | |||||
relatetiveModelPath := setting.JobPath + modelConvert.ID + "/dataset" | |||||
log.Info("local dataset path:" + relatetiveModelPath) | |||||
downloadFromObsToLocal(model, relatetiveModelPath) | |||||
uploadCodeToMinio(relatetiveModelPath+"/", modelConvert.ID, "/dataset/") | |||||
deleteLocalDir(relatetiveModelPath) | |||||
dataActualPath = setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + modelConvert.ID + "/dataset" | |||||
} | |||||
} | |||||
log.Info("dataActualPath=" + dataActualPath) | |||||
log.Info("command=" + command) | |||||
codePath := setting.JobPath + modelConvert.ID + CodeMountPath | |||||
downloadConvertCode(setting.ModelConvert.ConvertRepoPath, codePath, DefaultBranchName) | |||||
uploadCodeToMinio(codePath+"/", modelConvert.ID, CodeMountPath+"/") | |||||
deleteLocalDir(codePath) | |||||
minioCodePath := setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + modelConvert.ID + "/code" | |||||
log.Info("minio codePath=" + minioCodePath) | |||||
modelPath := setting.JobPath + modelConvert.ID + ModelMountPath + "/" | |||||
log.Info("local modelPath=" + modelPath) | |||||
mkModelPath(modelPath) | |||||
uploadCodeToMinio(modelPath, modelConvert.ID, ModelMountPath+"/") | |||||
deleteLocalDir(modelPath) | |||||
minioModelPath := setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + modelConvert.ID + "/model" | |||||
log.Info("minio model path=" + minioModelPath) | |||||
if TrainResourceSpecs == nil { | |||||
json.Unmarshal([]byte(setting.TrainResourceSpecs), &TrainResourceSpecs) | |||||
} | |||||
resourceSpec := TrainResourceSpecs.ResourceSpec[setting.ModelConvert.GPU_Resource_Specs_ID] | |||||
jobResult, err := cloudbrain.CreateJob(modelConvert.ID, models.CreateJobParams{ | |||||
JobName: modelConvert.ID, | |||||
RetryCount: 1, | |||||
GpuType: setting.ModelConvert.GpuQueue, | |||||
Image: IMAGE_URL, | |||||
TaskRoles: []models.TaskRole{ | |||||
{ | |||||
Name: SubTaskName, | |||||
TaskNumber: 1, | |||||
MinSucceededTaskCount: 1, | |||||
MinFailedTaskCount: 1, | |||||
CPUNumber: resourceSpec.CpuNum, | |||||
GPUNumber: resourceSpec.GpuNum, | |||||
MemoryMB: resourceSpec.MemMiB, | |||||
ShmMB: resourceSpec.ShareMemMiB, | |||||
Command: command, | |||||
NeedIBDevice: false, | |||||
IsMainRole: false, | |||||
UseNNI: false, | |||||
}, | |||||
}, | |||||
Volumes: []models.Volume{ | |||||
{ | |||||
HostPath: models.StHostPath{ | |||||
Path: minioCodePath, | |||||
MountPath: CodeMountPath, | |||||
ReadOnly: false, | |||||
}, | |||||
}, | |||||
{ | |||||
HostPath: models.StHostPath{ | |||||
Path: dataActualPath, | |||||
MountPath: DataSetMountPath, | |||||
ReadOnly: true, | |||||
}, | |||||
}, | |||||
{ | |||||
HostPath: models.StHostPath{ | |||||
Path: minioModelPath, | |||||
MountPath: ModelMountPath, | |||||
ReadOnly: false, | |||||
}, | |||||
}, | |||||
}, | |||||
}) | |||||
if err != nil { | |||||
log.Error("CreateJob failed:", err.Error(), ctx.Data["MsgID"]) | |||||
models.UpdateModelConvertFailed(modelConvert.ID, "FAILED", err.Error()) | |||||
return err | |||||
} | |||||
if jobResult.Code != Success { | |||||
log.Error("CreateJob(%s) failed:%s", modelConvert.ID, jobResult.Msg, ctx.Data["MsgID"]) | |||||
models.UpdateModelConvertFailed(modelConvert.ID, "FAILED", err.Error()) | |||||
return errors.New(jobResult.Msg) | |||||
} | |||||
var jobID = jobResult.Payload["jobId"].(string) | |||||
log.Info("jobId=" + jobID) | |||||
models.UpdateModelConvertCBTI(modelConvert.ID, jobID) | |||||
return nil | |||||
} | |||||
func deleteLocalDir(dirpath string) { | |||||
//TODO delete | |||||
_err := os.RemoveAll(dirpath) | |||||
if _err == nil { | |||||
log.Info("Delete local file:" + dirpath) | |||||
} else { | |||||
log.Info("Delete local file error: path=" + dirpath) | |||||
} | |||||
} | |||||
func getGpuModelConvertCommand(name string, modelFile string, modelConvert *models.AiModelConvert, bootfile string) string { | |||||
var command string | |||||
inputshape := strings.Split(modelConvert.InputShape, ",") | |||||
n := "256" | |||||
c := "1" | |||||
h := "28" | |||||
w := "28" | |||||
if len(inputshape) == 4 { | |||||
n = inputshape[0] | |||||
c = inputshape[1] | |||||
h = inputshape[2] | |||||
w = inputshape[3] | |||||
} | |||||
command += "python3 /code/" + bootfile + " --model " + modelFile + " --n " + n + " --c " + c + " --h " + h + " --w " + w | |||||
if modelConvert.DestFormat == CONVERT_FORMAT_TRT { | |||||
if modelConvert.NetOutputFormat == NetOutputFormat_FP16 { | |||||
command += " --fp16 True" | |||||
} else { | |||||
command += " --fp16 False" | |||||
} | |||||
} | |||||
command += " > " + ModelMountPath + "/" + name + "-" + LogFile | |||||
return command | |||||
} | |||||
func DeleteModelConvert(ctx *context.Context) { | |||||
log.Info("delete model convert start.") | |||||
id := ctx.Params(":id") | |||||
task, err := models.QueryModelConvertById(id) | |||||
if err == nil { | |||||
go deleteCloudBrainTask(task) | |||||
} | |||||
err = models.DeleteModelConvertById(id) | |||||
//TODO delete OBS文件及云脑任务 | |||||
if err != nil { | |||||
ctx.JSON(500, err.Error()) | |||||
} else { | |||||
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelmanage/convert_model") | |||||
} | |||||
} | |||||
func deleteCloudBrainTask(task *models.AiModelConvert) { | |||||
if task.IsGpuTrainTask() { | |||||
log.Info("delete cloudbrain one resource.") | |||||
dirPath := setting.CBCodePathPrefix + task.ID + "/" | |||||
err := storage.Attachments.DeleteDir(dirPath) | |||||
if err != nil { | |||||
log.Error("DeleteDir(%s) failed:%v", dirPath, err) | |||||
} | |||||
} else { | |||||
log.Info("delete cloudbrain two resource.") | |||||
_, err := modelarts.DelTrainJob(task.CloudBrainTaskId) | |||||
if err != nil { | |||||
log.Error("DelTrainJob(%s) failed:%v", task.CloudBrainTaskId, err.Error()) | |||||
} | |||||
DeleteJobStorage(task.ID) | |||||
} | |||||
} | |||||
func StopModelConvert(ctx *context.Context) { | |||||
id := ctx.Params(":id") | |||||
log.Info("stop model convert start.id=" + id) | |||||
job, err := models.QueryModelConvertById(id) | |||||
if err != nil { | |||||
ctx.ServerError("Not found task.", err) | |||||
return | |||||
} | |||||
if job.IsGpuTrainTask() { | |||||
err = cloudbrain.StopJob(job.CloudBrainTaskId) | |||||
if err != nil { | |||||
log.Error("Stop cloudbrain Job(%s) failed:%v", job.CloudBrainTaskId, err) | |||||
} | |||||
} else { | |||||
_, err = modelarts.StopTrainJob(job.CloudBrainTaskId, job.ModelArtsVersionId) | |||||
if err != nil { | |||||
log.Error("Stop modelarts Job(%s) failed:%v", job.CloudBrainTaskId, err) | |||||
} | |||||
} | |||||
job.Status = string(models.JobStopped) | |||||
if job.EndTime == 0 { | |||||
job.EndTime = timeutil.TimeStampNow() | |||||
} | |||||
models.ModelConvertSetDuration(job) | |||||
err = models.UpdateModelConvert(job) | |||||
if err != nil { | |||||
log.Error("UpdateModelConvert failed:", err) | |||||
} | |||||
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelmanage/convert_model") | |||||
} | |||||
func ShowModelConvertInfo(ctx *context.Context) { | |||||
ctx.Data["ID"] = ctx.Query("ID") | |||||
ctx.Data["isModelManage"] = true | |||||
ctx.Data["ModelManageAccess"] = ctx.Repo.CanWrite(models.UnitTypeModelManage) | |||||
job, err := models.QueryModelConvertById(ctx.Query("ID")) | |||||
if err == nil { | |||||
if job.TrainJobDuration == "" { | |||||
job.TrainJobDuration = "00:00:00" | |||||
} | |||||
ctx.Data["task"] = job | |||||
} else { | |||||
ctx.ServerError("Not found task.", err) | |||||
return | |||||
} | |||||
ctx.Data["Name"] = job.Name | |||||
ctx.Data["canDownload"] = isOper(ctx, job.UserId) | |||||
user, err := models.GetUserByID(job.UserId) | |||||
if err == nil { | |||||
job.UserName = user.Name | |||||
job.UserRelAvatarLink = user.RelAvatarLink() | |||||
} | |||||
if job.IsGpuTrainTask() { | |||||
ctx.Data["npu_display"] = "none" | |||||
ctx.Data["gpu_display"] = "block" | |||||
if job.CloudBrainTaskId == "" { | |||||
ctx.Data["ExitDiagnostics"] = "" | |||||
ctx.Data["AppExitDiagnostics"] = "" | |||||
ctx.HTML(200, tplModelConvertInfo) | |||||
return | |||||
} | |||||
result, err := cloudbrain.GetJob(job.CloudBrainTaskId) | |||||
if err != nil { | |||||
log.Info("error:" + err.Error()) | |||||
ctx.Data["error"] = err.Error() | |||||
ctx.HTML(200, tplModelConvertInfo) | |||||
return | |||||
} | |||||
if result != nil { | |||||
jobRes, _ := models.ConvertToJobResultPayload(result.Payload) | |||||
ctx.Data["result"] = jobRes | |||||
taskRoles := jobRes.TaskRoles | |||||
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) | |||||
ctx.Data["taskRes"] = taskRes | |||||
ctx.Data["ExitDiagnostics"] = taskRes.TaskStatuses[0].ExitDiagnostics | |||||
ctx.Data["AppExitDiagnostics"] = jobRes.JobStatus.AppExitDiagnostics | |||||
job.Status = jobRes.JobStatus.State | |||||
if jobRes.JobStatus.State != string(models.JobWaiting) && jobRes.JobStatus.State != string(models.JobFailed) { | |||||
job.ContainerIp = taskRes.TaskStatuses[0].ContainerIP | |||||
job.ContainerID = taskRes.TaskStatuses[0].ContainerID | |||||
job.Status = taskRes.TaskStatuses[0].State | |||||
} | |||||
if jobRes.JobStatus.State != string(models.JobWaiting) { | |||||
models.ModelComputeAndSetDuration(job, jobRes) | |||||
err = models.UpdateModelConvert(job) | |||||
if err != nil { | |||||
log.Error("UpdateModelConvert failed:", err) | |||||
} | |||||
} | |||||
} | |||||
} else { | |||||
if job.CloudBrainTaskId != "" { | |||||
result, err := modelarts.GetTrainJob(job.CloudBrainTaskId, job.ModelArtsVersionId) | |||||
if err != nil { | |||||
log.Info("error:" + err.Error()) | |||||
ctx.Data["error"] = err.Error() | |||||
return | |||||
} | |||||
job.Status = modelarts.TransTrainJobStatus(result.IntStatus) | |||||
job.RunTime = result.Duration / 1000 | |||||
job.TrainJobDuration = models.ConvertDurationToStr(job.RunTime) | |||||
err = models.UpdateModelConvert(job) | |||||
if err != nil { | |||||
log.Error("UpdateJob failed:", err) | |||||
} | |||||
} | |||||
ctx.Data["npu_display"] = "block" | |||||
ctx.Data["gpu_display"] = "none" | |||||
ctx.Data["ExitDiagnostics"] = "" | |||||
ctx.Data["AppExitDiagnostics"] = "" | |||||
} | |||||
ctx.HTML(200, tplModelConvertInfo) | |||||
} | |||||
func ConvertModelTemplate(ctx *context.Context) { | |||||
ctx.Data["isModelManage"] = true | |||||
ctx.Data["TRAIN_COUNT"] = 0 | |||||
SetModelCount(ctx) | |||||
ctx.Data["ModelManageAccess"] = ctx.Repo.CanWrite(models.UnitTypeModelManage) | |||||
ShowModelConvertPageInfo(ctx) | |||||
ctx.HTML(200, tplModelManageConvertIndex) | |||||
} | |||||
func ShowModelConvertPageInfo(ctx *context.Context) { | |||||
log.Info("ShowModelConvertInfo start.") | |||||
if !isQueryRight(ctx) { | |||||
log.Info("no right.") | |||||
ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||||
return | |||||
} | |||||
page := ctx.QueryInt("page") | |||||
if page <= 0 { | |||||
page = 1 | |||||
} | |||||
pageSize := ctx.QueryInt("pageSize") | |||||
if pageSize <= 0 { | |||||
pageSize = setting.UI.IssuePagingNum | |||||
} | |||||
repoId := ctx.Repo.Repository.ID | |||||
modelResult, count, err := models.QueryModelConvert(&models.AiModelQueryOptions{ | |||||
ListOptions: models.ListOptions{ | |||||
Page: page, | |||||
PageSize: pageSize, | |||||
}, | |||||
RepoID: repoId, | |||||
}) | |||||
if err != nil { | |||||
log.Info("query db error." + err.Error()) | |||||
ctx.ServerError("Cloudbrain", err) | |||||
return | |||||
} | |||||
ctx.Data["MODEL_CONVERT_COUNT"] = count | |||||
userIds := make([]int64, len(modelResult)) | |||||
for i, model := range modelResult { | |||||
model.IsCanOper = isOper(ctx, model.UserId) | |||||
model.IsCanDelete = isCanDelete(ctx, model.UserId) | |||||
userIds[i] = model.UserId | |||||
} | |||||
userNameMap := queryUserName(userIds) | |||||
for _, model := range modelResult { | |||||
value := userNameMap[model.UserId] | |||||
if value != nil { | |||||
model.UserName = value.Name | |||||
model.UserRelAvatarLink = value.RelAvatarLink() | |||||
} | |||||
} | |||||
pager := context.NewPagination(int(count), page, pageSize, 5) | |||||
ctx.Data["Page"] = pager | |||||
ctx.Data["Tasks"] = modelResult | |||||
} | |||||
func ModelConvertDownloadModel(ctx *context.Context) { | |||||
log.Info("enter here......") | |||||
id := ctx.Params(":id") | |||||
job, err := models.QueryModelConvertById(id) | |||||
if err != nil { | |||||
ctx.ServerError("Not found task.", err) | |||||
return | |||||
} | |||||
AllDownload := ctx.QueryBool("AllDownload") | |||||
if AllDownload { | |||||
if job.IsGpuTrainTask() { | |||||
path := setting.CBCodePathPrefix + job.ID + "/model/" | |||||
allFile, err := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, path) | |||||
if err == nil { | |||||
returnFileName := job.Name + ".zip" | |||||
MinioDownloadManyFile(path, ctx, returnFileName, allFile) | |||||
} else { | |||||
log.Info("error,msg=" + err.Error()) | |||||
ctx.ServerError("no file to download.", err) | |||||
} | |||||
} else { | |||||
Prefix := path.Join(setting.TrainJobModelPath, job.ID, "output/", "V0001", "") + "/" | |||||
log.Info("bucket=" + setting.Bucket + "prefix=" + Prefix) | |||||
allFile, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, Prefix) | |||||
if err == nil { | |||||
returnFileName := job.Name + ".zip" | |||||
ObsDownloadManyFile(Prefix, ctx, returnFileName, allFile) | |||||
} else { | |||||
log.Info("error,msg=" + err.Error()) | |||||
ctx.ServerError("no file to download.", err) | |||||
} | |||||
} | |||||
} else { | |||||
parentDir := ctx.Query("parentDir") | |||||
fileName := ctx.Query("fileName") | |||||
jobName := ctx.Query("jobName") | |||||
if job.IsGpuTrainTask() { | |||||
filePath := "jobs/" + jobName + "/model/" + parentDir | |||||
url, err := storage.Attachments.PresignedGetURL(filePath, fileName) | |||||
if err != nil { | |||||
log.Error("PresignedGetURL failed: %v", err.Error(), ctx.Data["msgID"]) | |||||
ctx.ServerError("PresignedGetURL", err) | |||||
return | |||||
} | |||||
//ctx.JSON(200, url) | |||||
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusTemporaryRedirect) | |||||
} else { | |||||
ObjectKey := path.Join(setting.TrainJobModelPath, job.ID, "output/", "V0001", parentDir, fileName) | |||||
log.Info("ObjectKey=" + ObjectKey) | |||||
url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, ObjectKey) | |||||
if err != nil { | |||||
log.Error("GetObsCreateSignedUrl failed: %v", err.Error(), ctx.Data["msgID"]) | |||||
ctx.ServerError("GetObsCreateSignedUrl", err) | |||||
return | |||||
} | |||||
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusTemporaryRedirect) | |||||
} | |||||
} | |||||
} |
@@ -26,6 +26,7 @@ const ( | |||||
tplModelInfo = "repo/modelmanage/showinfo" | tplModelInfo = "repo/modelmanage/showinfo" | ||||
MODEL_LATEST = 1 | MODEL_LATEST = 1 | ||||
MODEL_NOT_LATEST = 0 | MODEL_NOT_LATEST = 0 | ||||
MODEL_MAX_SIZE = 1024 * 1024 * 1024 | |||||
) | ) | ||||
func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, engine int, ctx *context.Context) error { | func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, engine int, ctx *context.Context) error { | ||||
@@ -58,14 +59,16 @@ func saveModelByParameters(jobId string, versionName string, name string, versio | |||||
} | } | ||||
} | } | ||||
cloudType := aiTask.Type | cloudType := aiTask.Type | ||||
modelSelectedFile := ctx.Query("modelSelectedFile") | |||||
//download model zip //train type | //download model zip //train type | ||||
if cloudType == models.TypeCloudBrainTwo { | |||||
modelPath, modelSize, err = downloadModelFromCloudBrainTwo(id, aiTask.JobName, "", aiTask.TrainUrl) | |||||
if aiTask.ComputeResource == models.NPUResource { | |||||
modelPath, modelSize, err = downloadModelFromCloudBrainTwo(id, aiTask.JobName, "", aiTask.TrainUrl, modelSelectedFile) | |||||
if err != nil { | if err != nil { | ||||
log.Info("download model from CloudBrainTwo faild." + err.Error()) | log.Info("download model from CloudBrainTwo faild." + err.Error()) | ||||
return err | return err | ||||
} | } | ||||
} else if cloudType == models.TypeCloudBrainOne { | |||||
cloudType = models.TypeCloudBrainTwo | |||||
} else if aiTask.ComputeResource == models.GPUResource { | |||||
var ResourceSpecs *models.ResourceSpecs | var ResourceSpecs *models.ResourceSpecs | ||||
json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs) | json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs) | ||||
for _, tmp := range ResourceSpecs.ResourceSpec { | for _, tmp := range ResourceSpecs.ResourceSpec { | ||||
@@ -74,12 +77,24 @@ func saveModelByParameters(jobId string, versionName string, name string, versio | |||||
aiTask.FlavorName = flaverName | aiTask.FlavorName = flaverName | ||||
} | } | ||||
} | } | ||||
modelPath, modelSize, err = downloadModelFromCloudBrainOne(id, aiTask.JobName, "", aiTask.TrainUrl) | |||||
modelPath, modelSize, err = downloadModelFromCloudBrainOne(id, aiTask.JobName, "", aiTask.TrainUrl, modelSelectedFile) | |||||
if err != nil { | if err != nil { | ||||
log.Info("download model from CloudBrainOne faild." + err.Error()) | log.Info("download model from CloudBrainOne faild." + err.Error()) | ||||
return err | return err | ||||
} | } | ||||
} | |||||
cloudType = models.TypeCloudBrainOne | |||||
} | |||||
// else if cloudType == models.TypeC2Net { | |||||
// if aiTask.ComputeResource == models.NPUResource { | |||||
// modelPath, modelSize, err = downloadModelFromCloudBrainTwo(id, aiTask.JobName, "", aiTask.TrainUrl, modelSelectedFile) | |||||
// if err != nil { | |||||
// log.Info("download model from CloudBrainTwo faild." + err.Error()) | |||||
// return err | |||||
// } | |||||
// } else if aiTask.ComputeResource == models.GPUResource { | |||||
// } | |||||
// } | |||||
accuracy := make(map[string]string) | accuracy := make(map[string]string) | ||||
accuracy["F1"] = "" | accuracy["F1"] = "" | ||||
accuracy["Recall"] = "" | accuracy["Recall"] = "" | ||||
@@ -163,7 +178,8 @@ func SaveModel(ctx *context.Context) { | |||||
description := ctx.Query("Description") | description := ctx.Query("Description") | ||||
engine := ctx.QueryInt("Engine") | engine := ctx.QueryInt("Engine") | ||||
trainTaskCreate := ctx.QueryBool("trainTaskCreate") | trainTaskCreate := ctx.QueryBool("trainTaskCreate") | ||||
log.Info("engine=" + fmt.Sprint(engine)) | |||||
modelSelectedFile := ctx.Query("modelSelectedFile") | |||||
log.Info("engine=" + fmt.Sprint(engine) + " modelSelectedFile=" + modelSelectedFile) | |||||
if !trainTaskCreate { | if !trainTaskCreate { | ||||
if !ctx.Repo.CanWrite(models.UnitTypeModelManage) { | if !ctx.Repo.CanWrite(models.UnitTypeModelManage) { | ||||
//ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | //ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | ||||
@@ -176,6 +192,10 @@ func SaveModel(ctx *context.Context) { | |||||
ctx.Error(500, fmt.Sprintf("JobId or VersionName is null.")) | ctx.Error(500, fmt.Sprintf("JobId or VersionName is null.")) | ||||
return | return | ||||
} | } | ||||
if modelSelectedFile == "" { | |||||
ctx.Error(500, fmt.Sprintf("Not selected model file.")) | |||||
return | |||||
} | |||||
if name == "" || version == "" { | if name == "" || version == "" { | ||||
ctx.Error(500, fmt.Sprintf("name or version is null.")) | ctx.Error(500, fmt.Sprintf("name or version is null.")) | ||||
@@ -193,11 +213,22 @@ func SaveModel(ctx *context.Context) { | |||||
log.Info("save model end.") | log.Info("save model end.") | ||||
} | } | ||||
func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir string, trainUrl string) (string, int64, error) { | |||||
func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir string, trainUrl string, modelSelectedFile string) (string, int64, error) { | |||||
objectkey := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/") | objectkey := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/") | ||||
if trainUrl != "" { | if trainUrl != "" { | ||||
objectkey = strings.Trim(trainUrl[len(setting.Bucket)+1:], "/") | objectkey = strings.Trim(trainUrl[len(setting.Bucket)+1:], "/") | ||||
} | } | ||||
prefix := objectkey + "/" | |||||
filterFiles := strings.Split(modelSelectedFile, ";") | |||||
Files := make([]string, 0) | |||||
for _, shortFile := range filterFiles { | |||||
Files = append(Files, prefix+shortFile) | |||||
} | |||||
totalSize := storage.ObsGetFilesSize(setting.Bucket, Files) | |||||
if float64(totalSize) > setting.MaxModelSize*MODEL_MAX_SIZE { | |||||
return "", 0, errors.New("Cannot create model, as model is exceed " + fmt.Sprint(setting.MaxModelSize) + "G.") | |||||
} | |||||
modelDbResult, err := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, objectkey, "") | modelDbResult, err := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, objectkey, "") | ||||
log.Info("bucket=" + setting.Bucket + " objectkey=" + objectkey) | log.Info("bucket=" + setting.Bucket + " objectkey=" + objectkey) | ||||
@@ -206,26 +237,33 @@ func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir | |||||
return "", 0, err | return "", 0, err | ||||
} | } | ||||
if len(modelDbResult) == 0 { | if len(modelDbResult) == 0 { | ||||
return "", 0, errors.New("cannot create model, as model is empty.") | |||||
return "", 0, errors.New("Cannot create model, as model is empty.") | |||||
} | } | ||||
prefix := objectkey + "/" | |||||
destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" | destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" | ||||
size, err := storage.ObsCopyManyFile(setting.Bucket, prefix, setting.Bucket, destKeyNamePrefix) | |||||
size, err := storage.ObsCopyManyFile(setting.Bucket, prefix, setting.Bucket, destKeyNamePrefix, filterFiles) | |||||
dataActualPath := setting.Bucket + "/" + destKeyNamePrefix | dataActualPath := setting.Bucket + "/" + destKeyNamePrefix | ||||
return dataActualPath, size, nil | return dataActualPath, size, nil | ||||
} | } | ||||
func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir string, trainUrl string) (string, int64, error) { | |||||
func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir string, trainUrl string, modelSelectedFile string) (string, int64, error) { | |||||
modelActualPath := storage.GetMinioPath(jobName, "/model/") | modelActualPath := storage.GetMinioPath(jobName, "/model/") | ||||
log.Info("modelActualPath=" + modelActualPath) | log.Info("modelActualPath=" + modelActualPath) | ||||
modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/" | modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/" | ||||
destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" | destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" | ||||
bucketName := setting.Attachment.Minio.Bucket | bucketName := setting.Attachment.Minio.Bucket | ||||
log.Info("destKeyNamePrefix=" + destKeyNamePrefix + " modelSrcPrefix=" + modelSrcPrefix + " bucket=" + bucketName) | log.Info("destKeyNamePrefix=" + destKeyNamePrefix + " modelSrcPrefix=" + modelSrcPrefix + " bucket=" + bucketName) | ||||
size, err := storage.MinioPathCopy(bucketName, modelSrcPrefix, destKeyNamePrefix) | |||||
filterFiles := strings.Split(modelSelectedFile, ";") | |||||
Files := make([]string, 0) | |||||
for _, shortFile := range filterFiles { | |||||
Files = append(Files, modelSrcPrefix+shortFile) | |||||
} | |||||
totalSize := storage.MinioGetFilesSize(bucketName, Files) | |||||
if float64(totalSize) > setting.MaxModelSize*MODEL_MAX_SIZE { | |||||
return "", 0, errors.New("Cannot create model, as model is exceed " + fmt.Sprint(setting.MaxModelSize) + "G.") | |||||
} | |||||
size, err := storage.MinioCopyFiles(bucketName, modelSrcPrefix, destKeyNamePrefix, filterFiles) | |||||
if err == nil { | if err == nil { | ||||
dataActualPath := bucketName + "/" + destKeyNamePrefix | dataActualPath := bucketName + "/" + destKeyNamePrefix | ||||
return dataActualPath, size, nil | return dataActualPath, size, nil | ||||
@@ -459,6 +497,35 @@ func QueryTrainJobList(ctx *context.Context) { | |||||
} | } | ||||
func QueryTrainModelList(ctx *context.Context) { | |||||
log.Info("query train job list. start.") | |||||
jobName := ctx.Query("jobName") | |||||
taskType := ctx.QueryInt("type") | |||||
VersionName := ctx.Query("VersionName") | |||||
if taskType == models.TypeCloudBrainTwo { | |||||
objectkey := path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, VersionName) + "/" | |||||
modelDbResult, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, objectkey) | |||||
log.Info("bucket=" + setting.Bucket + " objectkey=" + objectkey) | |||||
if err != nil { | |||||
log.Info("get TypeCloudBrainTwo TrainJobListModel failed:", err) | |||||
} else { | |||||
ctx.JSON(200, modelDbResult) | |||||
return | |||||
} | |||||
} else if taskType == models.TypeCloudBrainOne { | |||||
modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/" | |||||
bucketName := setting.Attachment.Minio.Bucket | |||||
modelDbResult, err := storage.GetAllObjectByBucketAndPrefixMinio(bucketName, modelSrcPrefix) | |||||
if err != nil { | |||||
log.Info("get TypeCloudBrainOne TrainJobListModel failed:", err) | |||||
} else { | |||||
ctx.JSON(200, modelDbResult) | |||||
return | |||||
} | |||||
} | |||||
ctx.JSON(200, "") | |||||
} | |||||
func DownloadSingleModelFile(ctx *context.Context) { | func DownloadSingleModelFile(ctx *context.Context) { | ||||
log.Info("DownloadSingleModelFile start.") | log.Info("DownloadSingleModelFile start.") | ||||
id := ctx.Params(":ID") | id := ctx.Params(":ID") | ||||
@@ -984,7 +984,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
flavorCode := form.Flavor | flavorCode := form.Flavor | ||||
params := form.Params | params := form.Params | ||||
poolID := form.PoolID | poolID := form.PoolID | ||||
isSaveParam := form.IsSaveParam | |||||
//isSaveParam := form.IsSaveParam | |||||
repo := ctx.Repo.Repository | repo := ctx.Repo.Repository | ||||
codeLocalPath := setting.JobPath + jobName + modelarts.CodePath | codeLocalPath := setting.JobPath + jobName + modelarts.CodePath | ||||
codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath | codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath | ||||
@@ -1129,45 +1129,45 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
} | } | ||||
//save param config | //save param config | ||||
if isSaveParam == "on" { | |||||
saveparams := append(param, models.Parameter{ | |||||
Label: modelarts.TrainUrl, | |||||
Value: outputObsPath, | |||||
}, models.Parameter{ | |||||
Label: modelarts.DataUrl, | |||||
Value: dataPath, | |||||
}) | |||||
if form.ParameterTemplateName == "" { | |||||
log.Error("ParameterTemplateName is empty") | |||||
trainJobNewDataPrepare(ctx) | |||||
ctx.RenderWithErr("保存作业参数时,作业参数名称不能为空", tplModelArtsTrainJobNew, &form) | |||||
return | |||||
} | |||||
_, err := modelarts.CreateTrainJobConfig(models.CreateConfigParams{ | |||||
ConfigName: form.ParameterTemplateName, | |||||
Description: form.PrameterDescription, | |||||
DataUrl: dataPath, | |||||
AppUrl: codeObsPath, | |||||
BootFileUrl: codeObsPath + bootFile, | |||||
TrainUrl: outputObsPath, | |||||
Flavor: models.Flavor{ | |||||
Code: flavorCode, | |||||
}, | |||||
WorkServerNum: workServerNumber, | |||||
EngineID: int64(engineID), | |||||
LogUrl: logObsPath, | |||||
PoolID: poolID, | |||||
Parameter: saveparams, | |||||
}) | |||||
if err != nil { | |||||
log.Error("Failed to CreateTrainJobConfig: %v", err) | |||||
trainJobErrorNewDataPrepare(ctx, form) | |||||
ctx.RenderWithErr("保存作业参数失败:"+err.Error(), tplModelArtsTrainJobNew, &form) | |||||
return | |||||
} | |||||
} | |||||
// if isSaveParam == "on" { | |||||
// saveparams := append(param, models.Parameter{ | |||||
// Label: modelarts.TrainUrl, | |||||
// Value: outputObsPath, | |||||
// }, models.Parameter{ | |||||
// Label: modelarts.DataUrl, | |||||
// Value: dataPath, | |||||
// }) | |||||
// if form.ParameterTemplateName == "" { | |||||
// log.Error("ParameterTemplateName is empty") | |||||
// trainJobNewDataPrepare(ctx) | |||||
// ctx.RenderWithErr("保存作业参数时,作业参数名称不能为空", tplModelArtsTrainJobNew, &form) | |||||
// return | |||||
// } | |||||
// _, err := modelarts.CreateTrainJobConfig(models.CreateConfigParams{ | |||||
// ConfigName: form.ParameterTemplateName, | |||||
// Description: form.PrameterDescription, | |||||
// DataUrl: dataPath, | |||||
// AppUrl: codeObsPath, | |||||
// BootFileUrl: codeObsPath + bootFile, | |||||
// TrainUrl: outputObsPath, | |||||
// Flavor: models.Flavor{ | |||||
// Code: flavorCode, | |||||
// }, | |||||
// WorkServerNum: workServerNumber, | |||||
// EngineID: int64(engineID), | |||||
// LogUrl: logObsPath, | |||||
// PoolID: poolID, | |||||
// Parameter: saveparams, | |||||
// }) | |||||
// if err != nil { | |||||
// log.Error("Failed to CreateTrainJobConfig: %v", err) | |||||
// trainJobErrorNewDataPrepare(ctx, form) | |||||
// ctx.RenderWithErr("保存作业参数失败:"+err.Error(), tplModelArtsTrainJobNew, &form) | |||||
// return | |||||
// } | |||||
// } | |||||
req := &modelarts.GenerateTrainJobReq{ | req := &modelarts.GenerateTrainJobReq{ | ||||
JobName: jobName, | JobName: jobName, | ||||
@@ -1195,6 +1195,9 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
TotalVersionCount: modelarts.TotalVersionCount, | TotalVersionCount: modelarts.TotalVersionCount, | ||||
DatasetName: datasetNames, | DatasetName: datasetNames, | ||||
} | } | ||||
userCommand, userImageUrl := getUserCommand(engineID, req) | |||||
req.UserCommand = userCommand | |||||
req.UserImageUrl = userImageUrl | |||||
//将params转换Parameters.Parameter,出错时返回给前端 | //将params转换Parameters.Parameter,出错时返回给前端 | ||||
var Parameters modelarts.Parameters | var Parameters modelarts.Parameters | ||||
@@ -1213,6 +1216,30 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | ||||
} | } | ||||
func getUserCommand(engineId int, req *modelarts.GenerateTrainJobReq) (string, string) { | |||||
userImageUrl := "" | |||||
userCommand := "" | |||||
if engineId < 0 { | |||||
userCommand = "/bin/bash /home/work/run_train.sh 's3://" + req.CodeObsPath + "' 'code/" + req.BootFile + "' '/tmp/log/train.log' --'data_url'='s3://" + req.DataUrl + "' --'train_url'='s3://" + req.TrainUrl + "'" | |||||
var versionInfos modelarts.VersionInfo | |||||
if err := json.Unmarshal([]byte(setting.EngineVersions), &versionInfos); err != nil { | |||||
log.Info("json parse err." + err.Error()) | |||||
} else { | |||||
for _, engine := range versionInfos.Version { | |||||
if engine.ID == engineId { | |||||
userImageUrl = engine.Url | |||||
break | |||||
} | |||||
} | |||||
} | |||||
for _, param := range req.Parameters { | |||||
userCommand += " --'" + param.Label + "'='" + param.Value + "'" | |||||
} | |||||
return userCommand, userImageUrl | |||||
} | |||||
return userCommand, userImageUrl | |||||
} | |||||
func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) { | func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) { | ||||
ctx.Data["PageIsTrainJob"] = true | ctx.Data["PageIsTrainJob"] = true | ||||
var jobID = ctx.Params(":jobid") | var jobID = ctx.Params(":jobid") | ||||
@@ -1249,7 +1276,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
flavorCode := form.Flavor | flavorCode := form.Flavor | ||||
params := form.Params | params := form.Params | ||||
poolID := form.PoolID | poolID := form.PoolID | ||||
isSaveParam := form.IsSaveParam | |||||
//isSaveParam := form.IsSaveParam | |||||
repo := ctx.Repo.Repository | repo := ctx.Repo.Repository | ||||
codeLocalPath := setting.JobPath + jobName + modelarts.CodePath | codeLocalPath := setting.JobPath + jobName + modelarts.CodePath | ||||
codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath + VersionOutputPath + "/" | codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath + VersionOutputPath + "/" | ||||
@@ -1369,46 +1396,46 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
}) | }) | ||||
} | } | ||||
//save param config | |||||
if isSaveParam == "on" { | |||||
saveparams := append(param, models.Parameter{ | |||||
Label: modelarts.TrainUrl, | |||||
Value: outputObsPath, | |||||
}, models.Parameter{ | |||||
Label: modelarts.DataUrl, | |||||
Value: dataPath, | |||||
}) | |||||
if form.ParameterTemplateName == "" { | |||||
log.Error("ParameterTemplateName is empty") | |||||
versionErrorDataPrepare(ctx, form) | |||||
ctx.RenderWithErr("保存作业参数时,作业参数名称不能为空", tplModelArtsTrainJobVersionNew, &form) | |||||
return | |||||
} | |||||
_, err := modelarts.CreateTrainJobConfig(models.CreateConfigParams{ | |||||
ConfigName: form.ParameterTemplateName, | |||||
Description: form.PrameterDescription, | |||||
DataUrl: dataPath, | |||||
AppUrl: codeObsPath, | |||||
BootFileUrl: codeObsPath + bootFile, | |||||
TrainUrl: outputObsPath, | |||||
Flavor: models.Flavor{ | |||||
Code: flavorCode, | |||||
}, | |||||
WorkServerNum: workServerNumber, | |||||
EngineID: int64(engineID), | |||||
LogUrl: logObsPath, | |||||
PoolID: poolID, | |||||
Parameter: saveparams, | |||||
}) | |||||
if err != nil { | |||||
log.Error("Failed to CreateTrainJobConfig: %v", err) | |||||
versionErrorDataPrepare(ctx, form) | |||||
ctx.RenderWithErr("保存作业参数失败:"+err.Error(), tplModelArtsTrainJobVersionNew, &form) | |||||
return | |||||
} | |||||
} | |||||
// //save param config | |||||
// if isSaveParam == "on" { | |||||
// saveparams := append(param, models.Parameter{ | |||||
// Label: modelarts.TrainUrl, | |||||
// Value: outputObsPath, | |||||
// }, models.Parameter{ | |||||
// Label: modelarts.DataUrl, | |||||
// Value: dataPath, | |||||
// }) | |||||
// if form.ParameterTemplateName == "" { | |||||
// log.Error("ParameterTemplateName is empty") | |||||
// versionErrorDataPrepare(ctx, form) | |||||
// ctx.RenderWithErr("保存作业参数时,作业参数名称不能为空", tplModelArtsTrainJobVersionNew, &form) | |||||
// return | |||||
// } | |||||
// _, err := modelarts.CreateTrainJobConfig(models.CreateConfigParams{ | |||||
// ConfigName: form.ParameterTemplateName, | |||||
// Description: form.PrameterDescription, | |||||
// DataUrl: dataPath, | |||||
// AppUrl: codeObsPath, | |||||
// BootFileUrl: codeObsPath + bootFile, | |||||
// TrainUrl: outputObsPath, | |||||
// Flavor: models.Flavor{ | |||||
// Code: flavorCode, | |||||
// }, | |||||
// WorkServerNum: workServerNumber, | |||||
// EngineID: int64(engineID), | |||||
// LogUrl: logObsPath, | |||||
// PoolID: poolID, | |||||
// Parameter: saveparams, | |||||
// }) | |||||
// if err != nil { | |||||
// log.Error("Failed to CreateTrainJobConfig: %v", err) | |||||
// versionErrorDataPrepare(ctx, form) | |||||
// ctx.RenderWithErr("保存作业参数失败:"+err.Error(), tplModelArtsTrainJobVersionNew, &form) | |||||
// return | |||||
// } | |||||
// } | |||||
task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, PreVersionName) | task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, PreVersionName) | ||||
if err != nil { | if err != nil { | ||||
@@ -1443,6 +1470,9 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
TotalVersionCount: latestTask.TotalVersionCount + 1, | TotalVersionCount: latestTask.TotalVersionCount + 1, | ||||
DatasetName: datasetNames, | DatasetName: datasetNames, | ||||
} | } | ||||
userCommand, userImageUrl := getUserCommand(engineID, req) | |||||
req.UserCommand = userCommand | |||||
req.UserImageUrl = userImageUrl | |||||
err = modelarts.GenerateTrainJobVersion(ctx, req, jobID) | err = modelarts.GenerateTrainJobVersion(ctx, req, jobID) | ||||
if err != nil { | if err != nil { | ||||
@@ -195,8 +195,11 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) { | |||||
} | } | ||||
ctx.Data["ContextUser"] = ctxUser | ctx.Data["ContextUser"] = ctxUser | ||||
if !form.AutoAgree { | if !form.AutoAgree { | ||||
ctx.Data["CheckedAutoAgree"] = "" | |||||
ctx.RenderWithErr(ctx.Tr("repo.template.one_promise"), tplCreate, form) | ctx.RenderWithErr(ctx.Tr("repo.template.one_promise"), tplCreate, form) | ||||
return | return | ||||
} else { | |||||
ctx.Data["CheckedAutoAgree"] = "checked" | |||||
} | } | ||||
if ctx.HasError() { | if ctx.HasError() { | ||||
ctx.HTML(200, tplCreate) | ctx.HTML(200, tplCreate) | ||||
@@ -500,7 +500,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
m.Get("/email2user", user.Email2User) | m.Get("/email2user", user.Email2User) | ||||
m.Get("/recover_account", user.ResetPasswd) | m.Get("/recover_account", user.ResetPasswd) | ||||
m.Post("/recover_account", user.ResetPasswdPost) | m.Post("/recover_account", user.ResetPasswdPost) | ||||
m.Post("/recover_account_by_phone",bindIgnErr(auth.ResetPassWordByPhoneForm{}), user.ResetPasswdByPhonePost) | |||||
m.Post("/recover_account_by_phone", bindIgnErr(auth.ResetPassWordByPhoneForm{}), user.ResetPasswdByPhonePost) | |||||
m.Get("/forgot_password", user.ForgotPasswd) | m.Get("/forgot_password", user.ForgotPasswd) | ||||
m.Post("/forgot_password", user.ForgotPasswdPost) | m.Post("/forgot_password", user.ForgotPasswdPost) | ||||
m.Post("/logout", user.SignOut) | m.Post("/logout", user.SignOut) | ||||
@@ -1136,19 +1136,26 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
}, context.RepoRef()) | }, context.RepoRef()) | ||||
m.Group("/modelmanage", func() { | m.Group("/modelmanage", func() { | ||||
m.Post("/create_model", reqRepoModelManageWriter, repo.SaveModel) | m.Post("/create_model", reqRepoModelManageWriter, repo.SaveModel) | ||||
m.Post("/create_model_convert", reqRepoModelManageWriter, repo.SaveModelConvert) | |||||
m.Post("/create_new_model", repo.SaveNewNameModel) | m.Post("/create_new_model", repo.SaveNewNameModel) | ||||
m.Delete("/delete_model", repo.DeleteModel) | m.Delete("/delete_model", repo.DeleteModel) | ||||
m.Post("/delete_model_convert/:id", repo.DeleteModelConvert) | |||||
m.Post("/convert_stop/:id", repo.StopModelConvert) | |||||
m.Put("/modify_model", repo.ModifyModelInfo) | m.Put("/modify_model", repo.ModifyModelInfo) | ||||
m.Get("/show_model", reqRepoModelManageReader, repo.ShowModelTemplate) | m.Get("/show_model", reqRepoModelManageReader, repo.ShowModelTemplate) | ||||
m.Get("/convert_model", reqRepoModelManageReader, repo.ConvertModelTemplate) | |||||
m.Get("/show_model_info", repo.ShowModelInfo) | m.Get("/show_model_info", repo.ShowModelInfo) | ||||
m.Get("/show_model_convert_info", repo.ShowModelConvertInfo) | |||||
m.Get("/show_model_info_api", repo.ShowSingleModel) | m.Get("/show_model_info_api", repo.ShowSingleModel) | ||||
m.Get("/show_model_api", repo.ShowModelPageInfo) | m.Get("/show_model_api", repo.ShowModelPageInfo) | ||||
m.Get("/show_model_child_api", repo.ShowOneVersionOtherModel) | m.Get("/show_model_child_api", repo.ShowOneVersionOtherModel) | ||||
m.Get("/query_train_job", reqRepoCloudBrainReader, repo.QueryTrainJobList) | m.Get("/query_train_job", reqRepoCloudBrainReader, repo.QueryTrainJobList) | ||||
m.Get("/query_train_model", reqRepoCloudBrainReader, repo.QueryTrainModelList) | |||||
m.Get("/query_train_job_version", reqRepoCloudBrainReader, repo.QueryTrainJobVersionList) | m.Get("/query_train_job_version", reqRepoCloudBrainReader, repo.QueryTrainJobVersionList) | ||||
m.Get("/query_model_for_predict", reqRepoModelManageReader, repo.QueryModelListForPredict) | m.Get("/query_model_for_predict", reqRepoModelManageReader, repo.QueryModelListForPredict) | ||||
m.Get("/query_modelfile_for_predict", reqRepoModelManageReader, repo.QueryModelFileForPredict) | m.Get("/query_modelfile_for_predict", reqRepoModelManageReader, repo.QueryModelFileForPredict) | ||||
m.Get("/query_onelevel_modelfile", reqRepoModelManageReader, repo.QueryOneLevelModelFile) | m.Get("/query_onelevel_modelfile", reqRepoModelManageReader, repo.QueryOneLevelModelFile) | ||||
m.Get("/download_model_convert/:id", reqRepoModelManageReader, repo.ModelConvertDownloadModel) | |||||
m.Group("/:ID", func() { | m.Group("/:ID", func() { | ||||
m.Get("", repo.ShowSingleModel) | m.Get("", repo.ShowSingleModel) | ||||
m.Get("/downloadsingle", repo.DownloadSingleModelFile) | m.Get("/downloadsingle", repo.DownloadSingleModelFile) | ||||
@@ -64,7 +64,7 @@ | |||||
<div class="dataset list"> | <div class="dataset list"> | ||||
<!-- 表头 --> | <!-- 表头 --> | ||||
<div class="ui grid stackable" style="background: #f0f0f0;;"> | |||||
<div class="ui grid stackable" style="background: #f0f0f0;"> | |||||
<div class="row"> | <div class="row"> | ||||
<div class="three wide column padding0" style="width: 18% !important;"> | <div class="three wide column padding0" style="width: 18% !important;"> | ||||
<span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span> | <span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span> | ||||
@@ -1,4 +1,5 @@ | |||||
{{template "base/head" .}} | {{template "base/head" .}} | ||||
<link rel="stylesheet" href="/self/ztree/css/zTreeStyle/zTreeStyle.css" type="text/css"> | |||||
<style> | <style> | ||||
.according-panel-heading { | .according-panel-heading { | ||||
box-sizing: border-box; | box-sizing: border-box; | ||||
@@ -200,6 +201,19 @@ | |||||
padding-left: 1rem; | padding-left: 1rem; | ||||
padding-top: 0.5rem; | padding-top: 0.5rem; | ||||
} | } | ||||
.menuContent{ | |||||
position: absolute; | |||||
background: #ffffff; | |||||
left: 0; | |||||
right: 26px; | |||||
top: 36px; | |||||
z-index:999; | |||||
border: 1px solid #96c8da; | |||||
border-top: 0; | |||||
border-bottom-right-radius: 4px; | |||||
border-bottom-left-radius: 4px; | |||||
box-shadow: 0 2px 3px 0 rgb(34 36 38 / 15%); | |||||
} | |||||
</style> | </style> | ||||
<div id="mask"> | <div id="mask"> | ||||
<div id="loadingPage"> | <div id="loadingPage"> | ||||
@@ -236,6 +250,16 @@ | |||||
<i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
<span class="accordion-panel-title-content"> | <span class="accordion-panel-title-content"> | ||||
<span> | <span> | ||||
<div style="float: right;"> | |||||
{{if and ($.canDownload) (eq .Status "SUCCEEDED") ($.Permission.CanWrite $.UnitTypeModelManage) }} | |||||
<a class="ti-action-menu-item" id="{{.VersionName}}-create-model" | |||||
onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | |||||
{{else}} | |||||
<a class="ti-action-menu-item disabled" id="{{.VersionName}}-create-model" | |||||
onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | |||||
{{end}} | |||||
</div> | |||||
<div class="ac-display-inblock title_text acc-margin-bottom"> | <div class="ac-display-inblock title_text acc-margin-bottom"> | ||||
<span class="cti-mgRight-sm">{{TimeSinceUnix1 .CreatedUnix}}</span> | <span class="cti-mgRight-sm">{{TimeSinceUnix1 .CreatedUnix}}</span> | ||||
@@ -504,12 +528,278 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<!-- | |||||
<div id="menuContent" class="menuContent" style="display:none; position: absolute;z-index:9999"> | |||||
<ul id="treeDemo" class="ztree" style="margin-top:0; width: 83%; height: 100%;"></ul> | |||||
</div> --> | |||||
<!-- 创建模型 --> | |||||
<div id="newmodel"> | |||||
<div class="ui modal second"> | |||||
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);"> | |||||
<h4 id="model_header">导入新模型</h4> | |||||
</div> | |||||
<div class="content content-padding"> | |||||
<form id="formId" method="POST" class="ui form"> | |||||
<div class="ui error message"> | |||||
</div> | |||||
{{$.CsrfTokenHtml}} | |||||
<input type="hidden" name="trainTaskCreate" value="true"> | |||||
<div class="required inline field"> | |||||
<label>训练任务</label> | |||||
<input type="hidden" class="width83" id="JobId" name="JobId" readonly required> | |||||
<input type="hidden" id="VersionName" name="VersionName" value="V0001"> | |||||
<input style="width: 45%;" id="JobName" readonly required> | |||||
</div> | |||||
<div class="required inline field" id="modelname"> | |||||
<label>模型名称</label> | |||||
<input style="width: 45%;" id="name" name="Name" required maxlength="25" | |||||
onkeyup="this.value=this.value.replace(/[, ]/g,'')"> | |||||
</div> | |||||
<div class="required inline field" id="verionname"> | |||||
<label>模型版本</label> | |||||
<input style="width: 45%;" id="version" name="Version" value="" readonly required maxlength="255"> | |||||
</div> | |||||
<div class="unite min_title inline field required"> | |||||
<label>模型框架</label> | |||||
<div class="ui dropdown selection search width70" id="choice_Engine"> | |||||
<input type="hidden" id="Engine" name="Engine" required> | |||||
<div class="default text">选择模型框架</div> | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu" id="job-Engine"> | |||||
<option class="active item" data-value="0">PyTorch</option> | |||||
<option class="item" data-value="1">TensorFlow</option> | |||||
<option class="item" data-value="4">PaddlePaddle</option> | |||||
<option class="item" data-value="5">OneFlow</option> | |||||
<option class="item" data-value="6">MXNet</option> | |||||
<option class="item" data-value="3">Other</option> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="unite min_title inline fields required"> | |||||
<div class="field required"> | |||||
<label for="modelSelectedFile">模型文件</label> | |||||
</div> | |||||
<div class="thirteen wide field" style="position:relative"> | |||||
<input id="modelSelectedFile" type="text" readonly required onclick="showMenu();" name="modelSelectedFile" > | |||||
<div id="menuContent" class="menuContent" style="display:none;"> | |||||
<ul id="treeDemo" class="ztree"></ul> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="inline field"> | |||||
<label>模型标签</label> | |||||
<input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255" | |||||
placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'> | |||||
</div> | |||||
<div class="inline field"> | |||||
<label for="description">模型描述</label> | |||||
<textarea style="width: 83%;margin-left: 7px;" id="Description" name="Description" rows="3" | |||||
maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}' | |||||
onchange="this.value=this.value.substring(0, 255)" | |||||
onkeydown="this.value=this.value.substring(0, 255)" | |||||
onkeyup="this.value=this.value.substring(0, 256)"></textarea> | |||||
</div> | |||||
<div class="inline field" style="margin-left: 75px;"> | |||||
<button onclick="createModel()" type="button" class="ui create_train_job green button" | |||||
style="position: absolute;"> | |||||
{{.i18n.Tr "repo.model.manage.sava_model"}} | |||||
</button> | |||||
</div> | |||||
</form> | |||||
<div class="actions" style="display: inline-block;margin-left: 180px;"> | |||||
<button class="ui button cancel">{{.i18n.Tr "repo.cloudbrain.cancel"}}</button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | </div> | ||||
{{template "base/footer" .}} | {{template "base/footer" .}} | ||||
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.core.js"></script> | |||||
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.excheck.js"></script> | |||||
<script> | <script> | ||||
var setting = { | |||||
check: { | |||||
enable: true, | |||||
chkboxType: {"Y":"ps", "N":"ps"} | |||||
}, | |||||
view: { | |||||
dblClickExpand: false | |||||
}, | |||||
callback: { | |||||
beforeClick: beforeClick, | |||||
onCheck: onCheck | |||||
} | |||||
}; | |||||
function beforeClick(treeId, treeNode) { | |||||
var zTree = $.fn.zTree.getZTreeObj("treeDemo"); | |||||
zTree.checkNode(treeNode, !treeNode.checked, null, true); | |||||
return false; | |||||
} | |||||
function onCheck(e, treeId, treeNode) { | |||||
var zTree = $.fn.zTree.getZTreeObj("treeDemo"), | |||||
nodes = zTree.getCheckedNodes(true), | |||||
v = ""; | |||||
for (var i=0, l=nodes.length; i<l; i++) { | |||||
if(nodes[i].isParent){ | |||||
continue; | |||||
} | |||||
var pathNodes = nodes[i].getPath(); | |||||
var path =""; | |||||
for(var j=0;j<pathNodes.length;j++){ | |||||
if(j ==0){ | |||||
path += pathNodes[j].name; | |||||
}else{ | |||||
path += "/" + pathNodes[j].name; | |||||
} | |||||
} | |||||
v += path + ";"; | |||||
} | |||||
if (v.length > 0 ) v = v.substring(0, v.length-1); | |||||
var cityObj = $("#modelSelectedFile"); | |||||
cityObj.attr("value", v); | |||||
} | |||||
function showMenu() { | |||||
var cityObj = $("#modelSelectedFile"); | |||||
var cityOffset = $("#modelSelectedFile").offset(); | |||||
//$("#menuContent").css({left:cityOffset.left + "px", top:cityOffset.top + cityObj.outerHeight() + "px"}).slideDown("fast"); | |||||
$("#menuContent").slideDown("fast"); | |||||
$("body").bind("mousedown", onBodyDown); | |||||
} | |||||
function hideMenu() { | |||||
$("#menuContent").fadeOut("fast"); | |||||
$("body").unbind("mousedown", onBodyDown); | |||||
} | |||||
function onBodyDown(event) { | |||||
if (!(event.target.id == "menuBtn" || event.target.id == "modelSelectedFile" || event.target.id == "menuContent" || $(event.target).parents("#menuContent").length>0)) { | |||||
hideMenu(); | |||||
} | |||||
} | |||||
function loadSelectedModelFile(trainJob){ | |||||
console.log("trainJob=" + trainJob); | |||||
$('#choice_file').dropdown('clear') | |||||
$("#model-file").empty() | |||||
if(trainJob ==null || trainJob ==""){ | |||||
console.log("trainJob is null"); | |||||
}else{ | |||||
$.get(`/${userName}/${repoPath}/modelmanage/query_train_model?jobName=${trainJob.JobName}&type=0&VersionName=${trainJob.VersionName}`, (data) => { | |||||
const n_length = data.length | |||||
let file_html='' | |||||
let firstFileName ='' | |||||
var zNodes=[]; | |||||
var nodesMap={}; | |||||
for (let i=0;i<n_length;i++){ | |||||
parentNodeMap = nodesMap; | |||||
var fileSplits = data[i].FileName.split("/"); | |||||
for(let j=0;j < fileSplits.length;j++){ | |||||
if(fileSplits[j] == ""){ | |||||
break; | |||||
} | |||||
if(parentNodeMap[fileSplits[j]] == null){ | |||||
parentNodeMap[fileSplits[j]] = {}; | |||||
} | |||||
parentNodeMap = parentNodeMap[fileSplits[j]] | |||||
} | |||||
} | |||||
convertToNode(zNodes,nodesMap); | |||||
$.fn.zTree.init($("#treeDemo"), setting, zNodes); | |||||
}) | |||||
} | |||||
} | |||||
function convertToNode(nodeList,nodesMap){ | |||||
var keyList = Object.keys(nodesMap); | |||||
keyList.sort(function(a,b){ | |||||
return a-b; | |||||
}); | |||||
var isFirst = true; | |||||
for(var i=0; i<keyList.length;i++){ | |||||
var node = {}; | |||||
node["name"] = keyList[i]; | |||||
nodeList.push(node); | |||||
if(nodesMap[keyList[i]] != null && Object.keys(nodesMap[keyList[i]]).length >0){ | |||||
node["children"]=[]; | |||||
if(isFirst){ | |||||
node["open"] = true; | |||||
isFirst= false; | |||||
} | |||||
convertToNode(node["children"],nodesMap[keyList[i]]); | |||||
} | |||||
} | |||||
} | |||||
function showcreate(obj) { | |||||
$('.ui.modal.second') | |||||
.modal({ | |||||
centered: false, | |||||
onShow: function () { | |||||
$('input[name="Version"]').addClass('model_disabled') | |||||
// $('input[name="JobId"]').text(obj.JobName) | |||||
$('#JobName').val(obj.DisplayJobName).addClass('model_disabled') | |||||
$('input[name="JobId"]').val(obj.JobID) | |||||
$('input[name="VersionName"]').val("V0001") | |||||
$('#choice_Engine .default.text').text("PyTorch"); | |||||
$('#choice_Engine input[name="Engine"]').val(0) | |||||
$('#choice_Engine .default.text').css({ "color": "rgb(0, 0, 0,0.87)" }) | |||||
$('.ui.dimmer').css({ "background-color": "rgb(136, 136, 136,0.7)" }) | |||||
createModelName(); | |||||
loadSelectedModelFile(obj); | |||||
}, | |||||
onHide: function () { | |||||
var cityObj = $("#modelSelectedFile"); | |||||
cityObj.attr("value", ""); | |||||
document.getElementById("formId").reset(); | |||||
$('.ui.dimmer').css({ "background-color": "" }) | |||||
$('.ui.error.message').text() | |||||
$('.ui.error.message').css('display', 'none') | |||||
} | |||||
}) | |||||
.modal('show') | |||||
} | |||||
function createModel() { | |||||
let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model` | |||||
let data = $("#formId").serialize() | |||||
$("#mask").css({ "display": "block", "z-index": "9999" }) | |||||
$.ajax({ | |||||
url: url_href, | |||||
type: 'POST', | |||||
data: data, | |||||
success: function (res) { | |||||
$('input[name="Engine_name"]').val(""); | |||||
$('input[name="Engine"]').val(""); | |||||
location.href = `/${userName}/${repoPath}/modelmanage/show_model` | |||||
$('.ui.modal.second').modal('hide') | |||||
}, | |||||
error: function (xhr) { | |||||
// 隐藏 loading | |||||
// 只有请求不正常(状态码不为200)才会执行 | |||||
$('.ui.error.message').text(xhr.responseText) | |||||
$('.ui.error.message').css('display', 'block') | |||||
}, | |||||
complete: function (xhr) { | |||||
$("#mask").css({ "display": "none", "z-index": "1" }) | |||||
} | |||||
}) | |||||
} | |||||
function createModelName() { | |||||
let repoName = location.pathname.split('/')[2] | |||||
let modelName = repoName + '_model_' + Math.random().toString(36).substr(2, 4) | |||||
$('#name').val(modelName) | |||||
$('#version').val("0.0.1") | |||||
} | |||||
$('.menu .item').tab() | $('.menu .item').tab() | ||||
$(document).ready(function () { | $(document).ready(function () { | ||||
@@ -80,6 +80,15 @@ | |||||
<label>{{.i18n.Tr "repo.template.issue_labels"}}</label> | <label>{{.i18n.Tr "repo.template.issue_labels"}}</label> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="inline field"> | |||||
<div class="ui checkbox" id="auto-init"> | |||||
<input class="hidden" name="auto_agree" type="checkbox" {{.CheckedAutoAgree}}> | |||||
<label | |||||
style="width: 76%;text-align: justify;line-height: 1.5;">{{.i18n.Tr "repo.use_repo_agreement"}} | |||||
<a target="_blank" | |||||
href="/home/term/">{{.i18n.Tr "repo.openi_use_agreement"}}</a></label> | |||||
</div> | |||||
</div> | |||||
</div> | </div> | ||||
<div id="non_template"> | <div id="non_template"> | ||||
@@ -152,7 +161,7 @@ | |||||
</div> | </div> | ||||
<div class="inline field"> | <div class="inline field"> | ||||
<div class="ui checkbox" id="auto-init"> | <div class="ui checkbox" id="auto-init"> | ||||
<input class="hidden" name="auto_agree" type="checkbox"> | |||||
<input class="hidden" name="auto_agree" type="checkbox" {{.CheckedAutoAgree}}> | |||||
<label | <label | ||||
style="width: 76%;text-align: justify;line-height: 1.5;">{{.i18n.Tr "repo.use_repo_agreement"}} | style="width: 76%;text-align: justify;line-height: 1.5;">{{.i18n.Tr "repo.use_repo_agreement"}} | ||||
<a target="_blank" | <a target="_blank" | ||||
@@ -1,4 +1,5 @@ | |||||
{{template "base/head" .}} | {{template "base/head" .}} | ||||
<link rel="stylesheet" href="/self/ztree/css/zTreeStyle/zTreeStyle.css" type="text/css"> | |||||
<style> | <style> | ||||
.according-panel-heading { | .according-panel-heading { | ||||
box-sizing: border-box; | box-sizing: border-box; | ||||
@@ -194,6 +195,19 @@ | |||||
padding-left: 1rem; | padding-left: 1rem; | ||||
padding-top: 0.5rem; | padding-top: 0.5rem; | ||||
} | } | ||||
.menuContent{ | |||||
position: absolute; | |||||
background: #ffffff; | |||||
left: 0; | |||||
right: 26px; | |||||
top: 36px; | |||||
z-index:999; | |||||
border: 1px solid #96c8da; | |||||
border-top: 0; | |||||
border-bottom-right-radius: 4px; | |||||
border-bottom-left-radius: 4px; | |||||
box-shadow: 0 2px 3px 0 rgb(34 36 38 / 15%); | |||||
} | |||||
</style> | </style> | ||||
<div id="mask"> | <div id="mask"> | ||||
<div id="loadingPage"> | <div id="loadingPage"> | ||||
@@ -234,6 +248,7 @@ | |||||
{{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
</div> | </div> | ||||
<div class="ac-display-inblock title_text acc-margin-bottom"> | <div class="ac-display-inblock title_text acc-margin-bottom"> | ||||
<span class="cti-mgRight-sm"> | <span class="cti-mgRight-sm"> | ||||
@@ -260,6 +275,16 @@ | |||||
class="redo icon redo-color"></i></span> | class="redo icon redo-color"></i></span> | ||||
</div> | </div> | ||||
<div style="float: right;"> | |||||
{{if and ($.canDownload) (eq .Status "SUCCEEDED") ($.Permission.CanWrite $.UnitTypeModelManage) }} | |||||
<a class="ti-action-menu-item" id="{{.VersionName}}-create-model" | |||||
onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | |||||
{{else}} | |||||
<a class="ti-action-menu-item disabled" id="{{.VersionName}}-create-model" | |||||
onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | |||||
{{end}} | |||||
</div> | |||||
</span> | </span> | ||||
</span> | </span> | ||||
</div> | </div> | ||||
@@ -514,7 +539,7 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<!-- 创建模型 --> | <!-- 创建模型 --> | ||||
<div id="newmodel"> | |||||
<div id="newmodel"> | |||||
<div class="ui modal second"> | <div class="ui modal second"> | ||||
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);"> | <div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);"> | ||||
<h4 id="model_header">导入新模型</h4> | <h4 id="model_header">导入新模型</h4> | ||||
@@ -526,17 +551,11 @@ | |||||
{{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
<input type="hidden" name="trainTaskCreate" value="true"> | <input type="hidden" name="trainTaskCreate" value="true"> | ||||
<div class="two inline fields "> | |||||
<div class="required ten wide field"> | |||||
<label style="margin-left: -23px;">选择训练任务</label> | |||||
<input type="hidden" class="width83" id="JobId" name="JobId" readonly required> | |||||
<input class="width83" id="JobName" readonly required> | |||||
</div> | |||||
<div class="required six widde field"> | |||||
<label>版本</label> | |||||
<input class="width70" id="VersionName" name="VersionName" readonly required> | |||||
</div> | |||||
<div class="required inline field"> | |||||
<label>训练任务</label> | |||||
<input type="hidden" class="width83" id="JobId" name="JobId" readonly required> | |||||
<input type="hidden" id="VersionName" name="VersionName" value="V0001"> | |||||
<input style="width: 45%;" id="JobName" readonly required> | |||||
</div> | </div> | ||||
<div class="required inline field" id="modelname"> | <div class="required inline field" id="modelname"> | ||||
@@ -546,8 +565,36 @@ | |||||
</div> | </div> | ||||
<div class="required inline field" id="verionname"> | <div class="required inline field" id="verionname"> | ||||
<label>模型版本</label> | <label>模型版本</label> | ||||
<input style="width: 45%;" id="version" name="Version" value="" readonly required | |||||
maxlength="255"> | |||||
<input style="width: 45%;" id="version" name="Version" value="" readonly required maxlength="255"> | |||||
</div> | |||||
<div class="unite min_title inline field required"> | |||||
<label>模型框架</label> | |||||
<div class="ui dropdown selection search width70" id="choice_Engine"> | |||||
<input type="hidden" id="Engine" name="Engine" required> | |||||
<div class="default text">选择模型框架</div> | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu" id="job-Engine"> | |||||
<option class="active item" data-value="0">PyTorch</option> | |||||
<option class="item" data-value="1">TensorFlow</option> | |||||
<option class="item" data-value="2">MindSpore</option> | |||||
<option class="item" data-value="4">PaddlePaddle</option> | |||||
<option class="item" data-value="5">OneFlow</option> | |||||
<option class="item" data-value="6">MXNet</option> | |||||
<option class="item" data-value="3">Other</option> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="unite min_title inline fields required"> | |||||
<div class="field required"> | |||||
<label for="modelSelectedFile">模型文件</label> | |||||
</div> | |||||
<div class="thirteen wide field" style="position:relative"> | |||||
<input id="modelSelectedFile" type="text" readonly required onclick="showMenu();" name="modelSelectedFile" > | |||||
<div id="menuContent" class="menuContent" style="display:none;"> | |||||
<ul id="treeDemo" class="ztree"></ul> | |||||
</div> | |||||
</div> | |||||
</div> | </div> | ||||
<div class="inline field"> | <div class="inline field"> | ||||
<label>模型标签</label> | <label>模型标签</label> | ||||
@@ -578,39 +625,135 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
{{template "base/footer" .}} | {{template "base/footer" .}} | ||||
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.core.js"></script> | |||||
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.excheck.js"></script> | |||||
<script> | <script> | ||||
$('.menu .item').tab() | |||||
$(document).ready(function () { | |||||
$('.ui.accordion').accordion({ selector: { trigger: '.icon' } }); | |||||
}); | |||||
$(document).ready(function () { | |||||
$('.secondary.menu .item').tab(); | |||||
}); | |||||
let userName | |||||
let repoPath | |||||
let jobID | |||||
let downlaodFlag = {{ $.canDownload }} | |||||
$(document).ready(function () { | |||||
let url = window.location.href; | |||||
let urlArr = url.split('/') | |||||
userName = urlArr.slice(-5)[0] | |||||
repoPath = urlArr.slice(-4)[0] | |||||
jobID = urlArr.slice(-1)[0] | |||||
}) | |||||
function stopBubbling(e) { | |||||
e = window.event || e; | |||||
if (e.stopPropagation) { | |||||
e.stopPropagation(); //阻止事件 冒泡传播 | |||||
} else { | |||||
e.cancelBubble = true; //ie兼容 | |||||
} | |||||
var setting = { | |||||
check: { | |||||
enable: true, | |||||
chkboxType: {"Y":"ps", "N":"ps"} | |||||
}, | |||||
view: { | |||||
dblClickExpand: false | |||||
}, | |||||
callback: { | |||||
beforeClick: beforeClick, | |||||
onCheck: onCheck | |||||
} | |||||
}; | |||||
function beforeClick(treeId, treeNode) { | |||||
var zTree = $.fn.zTree.getZTreeObj("treeDemo"); | |||||
zTree.checkNode(treeNode, !treeNode.checked, null, true); | |||||
return false; | |||||
} | |||||
function onCheck(e, treeId, treeNode) { | |||||
var zTree = $.fn.zTree.getZTreeObj("treeDemo"), | |||||
nodes = zTree.getCheckedNodes(true), | |||||
v = ""; | |||||
for (var i=0, l=nodes.length; i<l; i++) { | |||||
if(nodes[i].isParent){ | |||||
continue; | |||||
} | |||||
var pathNodes = nodes[i].getPath(); | |||||
var path =""; | |||||
for(var j=0;j<pathNodes.length;j++){ | |||||
if(j ==0){ | |||||
path += pathNodes[j].name; | |||||
}else{ | |||||
path += "/" + pathNodes[j].name; | |||||
} | |||||
} | |||||
v += path + ";"; | |||||
} | |||||
if (v.length > 0 ) v = v.substring(0, v.length-1); | |||||
var cityObj = $("#modelSelectedFile"); | |||||
cityObj.attr("value", v); | |||||
} | |||||
function showMenu() { | |||||
var cityObj = $("#modelSelectedFile"); | |||||
var cityOffset = $("#modelSelectedFile").offset(); | |||||
//$("#menuContent").css({left:cityOffset.left + "px", top:cityOffset.top + cityObj.outerHeight() + "px"}).slideDown("fast"); | |||||
$("#menuContent").slideDown("fast"); | |||||
$("body").bind("mousedown", onBodyDown); | |||||
} | |||||
function hideMenu() { | |||||
$("#menuContent").fadeOut("fast"); | |||||
$("body").unbind("mousedown", onBodyDown); | |||||
} | |||||
function onBodyDown(event) { | |||||
if (!(event.target.id == "menuBtn" || event.target.id == "modelSelectedFile" || event.target.id == "menuContent" || $(event.target).parents("#menuContent").length>0)) { | |||||
hideMenu(); | |||||
} | |||||
} | |||||
function loadSelectedModelFile(trainJob){ | |||||
console.log("trainJob=" + trainJob); | |||||
$('#choice_file').dropdown('clear') | |||||
$("#model-file").empty() | |||||
if(trainJob ==null || trainJob ==""){ | |||||
console.log("trainJob is null"); | |||||
}else{ | |||||
let type = trainJob.Type; | |||||
if(type == 2){ | |||||
if(trainJob.ComputeResource=="NPU"){ | |||||
type=1; | |||||
}else{ | |||||
type=0; | |||||
} | |||||
} | |||||
$.get(`/${userName}/${repoPath}/modelmanage/query_train_model?jobName=${trainJob.JobName}&type=${type}&VersionName=${trainJob.VersionName}`, (data) => { | |||||
const n_length = data.length | |||||
let file_html='' | |||||
let firstFileName ='' | |||||
var zNodes=[]; | |||||
var nodesMap={}; | |||||
for (let i=0;i<n_length;i++){ | |||||
parentNodeMap = nodesMap; | |||||
var fileSplits = data[i].FileName.split("/"); | |||||
for(let j=0;j < fileSplits.length;j++){ | |||||
if(fileSplits[j] == ""){ | |||||
break; | |||||
} | |||||
if(parentNodeMap[fileSplits[j]] == null){ | |||||
parentNodeMap[fileSplits[j]] = {}; | |||||
} | |||||
parentNodeMap = parentNodeMap[fileSplits[j]] | |||||
} | |||||
} | |||||
convertToNode(zNodes,nodesMap); | |||||
$.fn.zTree.init($("#treeDemo"), setting, zNodes); | |||||
}) | |||||
} | |||||
} | } | ||||
function showcreate(obj) { | |||||
function convertToNode(nodeList,nodesMap){ | |||||
var keyList = Object.keys(nodesMap); | |||||
keyList.sort(function(a,b){ | |||||
return a-b; | |||||
}); | |||||
var isFirst = true; | |||||
for(var i=0; i<keyList.length;i++){ | |||||
var node = {}; | |||||
node["name"] = keyList[i]; | |||||
nodeList.push(node); | |||||
if(nodesMap[keyList[i]] != null && Object.keys(nodesMap[keyList[i]]).length >0){ | |||||
node["children"]=[]; | |||||
if(isFirst){ | |||||
node["open"] = true; | |||||
isFirst= false; | |||||
} | |||||
convertToNode(node["children"],nodesMap[keyList[i]]); | |||||
} | |||||
} | |||||
} | |||||
function showcreate(obj) { | |||||
$('.ui.modal.second') | $('.ui.modal.second') | ||||
.modal({ | .modal({ | ||||
centered: false, | centered: false, | ||||
@@ -619,11 +762,33 @@ | |||||
// $('input[name="JobId"]').text(obj.JobName) | // $('input[name="JobId"]').text(obj.JobName) | ||||
$('#JobName').val(obj.DisplayJobName).addClass('model_disabled') | $('#JobName').val(obj.DisplayJobName).addClass('model_disabled') | ||||
$('input[name="JobId"]').val(obj.JobID) | $('input[name="JobId"]').val(obj.JobID) | ||||
$('input[name="VersionName"]').val(obj.VersionName).addClass('model_disabled') | |||||
$('.ui.dimmer').css({ "background-color": "rgb(136, 136, 136,0.7)" }) | |||||
createModelName() | |||||
$('input[name="VersionName"]').val("V0001") | |||||
if(obj.ComputeResource=="NPU"){ | |||||
if (obj.EngineName != null && obj.EngineName != "") { | |||||
srcEngine = obj.EngineName.split('-')[0] | |||||
srcEngine = srcEngine.trim().toLowerCase(); | |||||
if (srcEngine == 'tensorflow') { | |||||
$('#choice_Engine .default.text').text("TensorFlow"); | |||||
$('#choice_Engine input[name="Engine"]').val(1) | |||||
} | |||||
if (srcEngine == 'mindspore') { | |||||
$('#choice_Engine .default.text').text("MindSpore"); | |||||
$('#choice_Engine input[name="Engine"]').val(1) | |||||
} | |||||
} | |||||
}else{ | |||||
$('#choice_Engine .default.text').text("PyTorch"); | |||||
$('#choice_Engine input[name="Engine"]').val(0) | |||||
} | |||||
$('#choice_Engine .default.text').css({ "color": "rgb(0, 0, 0,0.87)" }) | |||||
$('.ui.dimmer').css({ "background-color": "rgb(136, 136, 136,0.7)" }) | |||||
createModelName(); | |||||
loadSelectedModelFile(obj); | |||||
}, | }, | ||||
onHide: function () { | onHide: function () { | ||||
var cityObj = $("#modelSelectedFile"); | |||||
cityObj.attr("value", ""); | |||||
document.getElementById("formId").reset(); | document.getElementById("formId").reset(); | ||||
$('.ui.dimmer').css({ "background-color": "" }) | $('.ui.dimmer').css({ "background-color": "" }) | ||||
$('.ui.error.message').text() | $('.ui.error.message').text() | ||||
@@ -641,6 +806,8 @@ | |||||
type: 'POST', | type: 'POST', | ||||
data: data, | data: data, | ||||
success: function (res) { | success: function (res) { | ||||
$('input[name="Engine_name"]').val(""); | |||||
$('input[name="Engine"]').val(""); | |||||
location.href = `/${userName}/${repoPath}/modelmanage/show_model` | location.href = `/${userName}/${repoPath}/modelmanage/show_model` | ||||
$('.ui.modal.second').modal('hide') | $('.ui.modal.second').modal('hide') | ||||
}, | }, | ||||
@@ -662,6 +829,48 @@ | |||||
$('#name').val(modelName) | $('#name').val(modelName) | ||||
$('#version').val("0.0.1") | $('#version').val("0.0.1") | ||||
} | } | ||||
$('.menu .item').tab() | |||||
$(document).ready(function () { | |||||
$('.ui.accordion').accordion({ selector: { trigger: '.icon' } }); | |||||
}); | |||||
$(document).ready(function () { | |||||
$('.secondary.menu .item').tab(); | |||||
}); | |||||
let userName | |||||
let repoPath | |||||
let jobID | |||||
let downlaodFlag = {{ $.canDownload }} | |||||
$(document).ready(function () { | |||||
let url = window.location.href; | |||||
let urlArr = url.split('/') | |||||
userName = urlArr.slice(-5)[0] | |||||
repoPath = urlArr.slice(-4)[0] | |||||
jobID = urlArr.slice(-1)[0] | |||||
}) | |||||
function stopBubbling(e) { | |||||
e = window.event || e; | |||||
if (e.stopPropagation) { | |||||
e.stopPropagation(); //阻止事件 冒泡传播 | |||||
} else { | |||||
e.cancelBubble = true; //ie兼容 | |||||
} | |||||
} | |||||
function renderSize(value) { | |||||
if (null == value || value == '') { | |||||
return "0 Bytes"; | |||||
} | |||||
var unitArr = new Array("Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"); | |||||
var index = 0; | |||||
var srcsize = parseFloat(value); | |||||
index = Math.floor(Math.log(srcsize) / Math.log(1024)); | |||||
var size = srcsize / Math.pow(1024, index); | |||||
size = size.toFixed(0);//保留的小数位数 | |||||
return size + unitArr[index]; | |||||
} | |||||
function refreshStatus(version_name) { | function refreshStatus(version_name) { | ||||
$.get(`/api/v1/repos/${userName}/${repoPath}/grampus/train-job/${jobID}?version_name=${version_name}`, (data) => { | $.get(`/api/v1/repos/${userName}/${repoPath}/grampus/train-job/${jobID}?version_name=${version_name}`, (data) => { | ||||
// header status and duration | // header status and duration | ||||
@@ -1,4 +1,5 @@ | |||||
{{template "base/head" .}} | {{template "base/head" .}} | ||||
<link rel="stylesheet" href="/self/ztree/css/zTreeStyle/zTreeStyle.css" type="text/css"> | |||||
<style> | <style> | ||||
.according-panel-heading { | .according-panel-heading { | ||||
box-sizing: border-box; | box-sizing: border-box; | ||||
@@ -200,6 +201,19 @@ | |||||
padding-left: 1rem; | padding-left: 1rem; | ||||
padding-top: 0.5rem; | padding-top: 0.5rem; | ||||
} | } | ||||
.menuContent{ | |||||
position: absolute; | |||||
background: #ffffff; | |||||
left: 0; | |||||
right: 26px; | |||||
top: 36px; | |||||
z-index:999; | |||||
border: 1px solid #96c8da; | |||||
border-top: 0; | |||||
border-bottom-right-radius: 4px; | |||||
border-bottom-left-radius: 4px; | |||||
box-shadow: 0 2px 3px 0 rgb(34 36 38 / 15%); | |||||
} | |||||
</style> | </style> | ||||
<div id="mask"> | <div id="mask"> | ||||
<div id="loadingPage"> | <div id="loadingPage"> | ||||
@@ -565,6 +579,10 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<!-- | |||||
<div id="menuContent" class="menuContent" style="display:none; position: absolute;z-index:9999"> | |||||
<ul id="treeDemo" class="ztree" style="margin-top:0; width: 83%; height: 100%;"></ul> | |||||
</div> --> | |||||
<!-- 创建模型 --> | <!-- 创建模型 --> | ||||
<div id="newmodel"> | <div id="newmodel"> | ||||
<div class="ui modal second"> | <div class="ui modal second"> | ||||
@@ -605,6 +623,17 @@ | |||||
<input type="hidden" id="Engine" name="Engine" required> | <input type="hidden" id="Engine" name="Engine" required> | ||||
<input style="width: 45%;" id="Engine_name" name="Engine_name" readonly required maxlength="255"> | <input style="width: 45%;" id="Engine_name" name="Engine_name" readonly required maxlength="255"> | ||||
</div> | </div> | ||||
<div class="unite min_title inline fields required"> | |||||
<div class="field required"> | |||||
<label for="modelSelectedFile">模型文件</label> | |||||
</div> | |||||
<div class="thirteen wide field" style="position:relative"> | |||||
<input id="modelSelectedFile" type="text" readonly required onclick="showMenu();" name="modelSelectedFile" > | |||||
<div id="menuContent" class="menuContent" style="display:none;"> | |||||
<ul id="treeDemo" class="ztree"></ul> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="inline field"> | <div class="inline field"> | ||||
<label>模型标签</label> | <label>模型标签</label> | ||||
<input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255" | <input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255" | ||||
@@ -637,7 +666,124 @@ | |||||
</div> | </div> | ||||
{{template "base/footer" .}} | {{template "base/footer" .}} | ||||
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.core.js"></script> | |||||
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.excheck.js"></script> | |||||
<script> | <script> | ||||
var setting = { | |||||
check: { | |||||
enable: true, | |||||
chkboxType: {"Y":"ps", "N":"ps"} | |||||
}, | |||||
view: { | |||||
dblClickExpand: false | |||||
}, | |||||
callback: { | |||||
beforeClick: beforeClick, | |||||
onCheck: onCheck | |||||
} | |||||
}; | |||||
function beforeClick(treeId, treeNode) { | |||||
var zTree = $.fn.zTree.getZTreeObj("treeDemo"); | |||||
zTree.checkNode(treeNode, !treeNode.checked, null, true); | |||||
return false; | |||||
} | |||||
function onCheck(e, treeId, treeNode) { | |||||
var zTree = $.fn.zTree.getZTreeObj("treeDemo"), | |||||
nodes = zTree.getCheckedNodes(true), | |||||
v = ""; | |||||
for (var i=0, l=nodes.length; i<l; i++) { | |||||
if(nodes[i].isParent){ | |||||
continue; | |||||
} | |||||
var pathNodes = nodes[i].getPath(); | |||||
var path =""; | |||||
for(var j=0;j<pathNodes.length;j++){ | |||||
if(j ==0){ | |||||
path += pathNodes[j].name; | |||||
}else{ | |||||
path += "/" + pathNodes[j].name; | |||||
} | |||||
} | |||||
v += path + ";"; | |||||
} | |||||
if (v.length > 0 ) v = v.substring(0, v.length-1); | |||||
var cityObj = $("#modelSelectedFile"); | |||||
cityObj.attr("value", v); | |||||
} | |||||
function showMenu() { | |||||
var cityObj = $("#modelSelectedFile"); | |||||
var cityOffset = $("#modelSelectedFile").offset(); | |||||
//$("#menuContent").css({left:cityOffset.left + "px", top:cityOffset.top + cityObj.outerHeight() + "px"}).slideDown("fast"); | |||||
$("#menuContent").slideDown("fast"); | |||||
$("body").bind("mousedown", onBodyDown); | |||||
} | |||||
function hideMenu() { | |||||
$("#menuContent").fadeOut("fast"); | |||||
$("body").unbind("mousedown", onBodyDown); | |||||
} | |||||
function onBodyDown(event) { | |||||
if (!(event.target.id == "menuBtn" || event.target.id == "modelSelectedFile" || event.target.id == "menuContent" || $(event.target).parents("#menuContent").length>0)) { | |||||
hideMenu(); | |||||
} | |||||
} | |||||
function loadSelectedModelFile(trainJob){ | |||||
console.log("trainJob=" + trainJob); | |||||
$('#choice_file').dropdown('clear') | |||||
$("#model-file").empty() | |||||
if(trainJob ==null || trainJob ==""){ | |||||
console.log("trainJob is null"); | |||||
}else{ | |||||
$.get(`/${userName}/${repoPath}/modelmanage/query_train_model?jobName=${trainJob.JobName}&type=1&VersionName=${trainJob.VersionName}`, (data) => { | |||||
const n_length = data.length | |||||
let file_html='' | |||||
let firstFileName ='' | |||||
var zNodes=[]; | |||||
var nodesMap={}; | |||||
for (let i=0;i<n_length;i++){ | |||||
parentNodeMap = nodesMap; | |||||
var fileSplits = data[i].FileName.split("/"); | |||||
for(let j=0;j < fileSplits.length;j++){ | |||||
if(fileSplits[j] == ""){ | |||||
break; | |||||
} | |||||
if(parentNodeMap[fileSplits[j]] == null){ | |||||
parentNodeMap[fileSplits[j]] = {}; | |||||
} | |||||
parentNodeMap = parentNodeMap[fileSplits[j]] | |||||
} | |||||
} | |||||
convertToNode(zNodes,nodesMap); | |||||
$.fn.zTree.init($("#treeDemo"), setting, zNodes); | |||||
}) | |||||
} | |||||
} | |||||
function convertToNode(nodeList,nodesMap){ | |||||
var keyList = Object.keys(nodesMap); | |||||
keyList.sort(function(a,b){ | |||||
return a-b; | |||||
}); | |||||
var isFirst = true; | |||||
for(var i=0; i<keyList.length;i++){ | |||||
var node = {}; | |||||
node["name"] = keyList[i]; | |||||
nodeList.push(node); | |||||
if(nodesMap[keyList[i]] != null && Object.keys(nodesMap[keyList[i]]).length >0){ | |||||
node["children"]=[]; | |||||
if(isFirst){ | |||||
node["open"] = true; | |||||
isFirst= false; | |||||
} | |||||
convertToNode(node["children"],nodesMap[keyList[i]]); | |||||
} | |||||
} | |||||
} | |||||
$('.menu .item').tab() | $('.menu .item').tab() | ||||
$(document).ready(function () { | $(document).ready(function () { | ||||
$('.ui.accordion').accordion({ selector: { trigger: '.icon' } }); | $('.ui.accordion').accordion({ selector: { trigger: '.icon' } }); | ||||
@@ -676,7 +822,7 @@ | |||||
$('#JobName').val(obj.DisplayJobName).addClass('model_disabled') | $('#JobName').val(obj.DisplayJobName).addClass('model_disabled') | ||||
$('input[name="JobId"]').val(obj.JobID) | $('input[name="JobId"]').val(obj.JobID) | ||||
$('input[name="VersionName"]').val(obj.VersionName).addClass('model_disabled') | $('input[name="VersionName"]').val(obj.VersionName).addClass('model_disabled') | ||||
if(obj.EngineID ==122 || obj.EngineID ==35){ | |||||
if(obj.EngineID ==122 || obj.EngineID ==35 || obj.EngineID ==-1){ | |||||
$('input[name="Engine_name"]').val("MindSpore").addClass('model_disabled'); | $('input[name="Engine_name"]').val("MindSpore").addClass('model_disabled'); | ||||
$('input[name="Engine"]').val(2); | $('input[name="Engine"]').val(2); | ||||
} | } | ||||
@@ -685,9 +831,12 @@ | |||||
$('input[name="Engine"]').val(1); | $('input[name="Engine"]').val(1); | ||||
} | } | ||||
$('.ui.dimmer').css({ "background-color": "rgb(136, 136, 136,0.7)" }) | $('.ui.dimmer').css({ "background-color": "rgb(136, 136, 136,0.7)" }) | ||||
createModelName() | |||||
createModelName(); | |||||
loadSelectedModelFile(obj); | |||||
}, | }, | ||||
onHide: function () { | onHide: function () { | ||||
var cityObj = $("#modelSelectedFile"); | |||||
cityObj.attr("value", ""); | |||||
document.getElementById("formId").reset(); | document.getElementById("formId").reset(); | ||||
$('.ui.dimmer').css({ "background-color": "" }) | $('.ui.dimmer').css({ "background-color": "" }) | ||||
$('.ui.error.message').text() | $('.ui.error.message').text() | ||||
@@ -802,5 +951,143 @@ | |||||
console.log(err); | console.log(err); | ||||
}); | }); | ||||
} | } | ||||
function debounce(fn, delay) { | |||||
let timer; | |||||
return (...args) => { | |||||
// 判断定时器是否存在,清除定时器 | |||||
if (timer) { | |||||
clearTimeout(timer); | |||||
} | |||||
// 重新调用setTimeout | |||||
timer = setTimeout(() => { | |||||
fn.apply(this, args); | |||||
}, delay); | |||||
}; | |||||
} | |||||
const fn = debounce(logScroll, 500) | |||||
function logScroll(version_name) { | |||||
let container = document.querySelector(`#log${version_name}`) | |||||
let scrollTop = container.scrollTop | |||||
let scrollHeight = container.scrollHeight | |||||
let clientHeight = container.clientHeight | |||||
let scrollLeft = container.scrollLeft | |||||
if (((parseInt(scrollTop) + clientHeight == scrollHeight || parseInt(scrollTop) + clientHeight + 1 == scrollHeight || parseInt(scrollTop) + clientHeight - 1 == scrollHeight)) && parseInt(scrollTop) !== 0 && scrollLeft == 0) { | |||||
let end_line = $(`#log${version_name} input[name=end_line]`).val() | |||||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${end_line}&lines=50&order=desc`, (data) => { | |||||
if (data.Lines == 0) { | |||||
$(`.message${version_name} #header`).text('您已翻阅至日志底部') | |||||
$(`.message${version_name}`).css('display', 'block') | |||||
setTimeout(function () { | |||||
$(`.message${version_name}`).css('display', 'none') | |||||
}, 1000) | |||||
} else { | |||||
if (end_line === data.EndLine) { | |||||
return | |||||
} | |||||
else { | |||||
$(`#log${version_name} input[name=end_line]`).val(data.EndLine) | |||||
$(`#log${version_name}`).append('<pre>' + data.Content) | |||||
} | |||||
} | |||||
}).fail(function (err) { | |||||
console.log(err); | |||||
}); | |||||
} | |||||
if ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].includes(scrollTop) && scrollLeft == 0) { | |||||
let start_line = $(`#log${version_name} input[name=start_line]`).val() | |||||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${start_line}&lines=50&order=asc`, (data) => { | |||||
if (data.Lines == 0) { | |||||
$(`.message${version_name} #header`).text('您已翻阅至日志顶部') | |||||
$(`.message${version_name}`).css('display', 'block') | |||||
setTimeout(function () { | |||||
$(`.message${version_name}`).css('display', 'none') | |||||
}, 1000) | |||||
} else { | |||||
$(`#log${version_name} input[name=start_line]`).val(data.StartLine) //如果变动就改变所对应的值 | |||||
$(`#log${version_name}`).prepend('<pre>' + data.Content) | |||||
} | |||||
}).fail(function (err) { | |||||
console.log(err); | |||||
}); | |||||
} | |||||
} | |||||
function scrollAnimation(dom, currentY, targetY, currentX) { | |||||
let needScrollTop = targetY - currentY; | |||||
let _currentY = currentY; | |||||
setTimeout(() => { | |||||
// 一次调用滑动帧数,每次调用会不一样 | |||||
//取总距离的十分之一 | |||||
const dist = Math.ceil(needScrollTop / 10); | |||||
_currentY += dist; | |||||
//移动一个十分之一 | |||||
dom.scrollTo(currentX || 0, _currentY, 'smooth'); | |||||
// 如果移动幅度小于十个像素,直接移动,否则递归调用,实现动画效果 | |||||
if (needScrollTop > 10 || needScrollTop < -10) { | |||||
scrollAnimation(dom, _currentY, targetY) | |||||
} else { | |||||
dom.scrollTo(0, targetY, 'smooth') | |||||
} | |||||
}, 1) | |||||
} | |||||
$('.log_top').click(function () { | |||||
// let logContentDom = document.querySelector('.log') | |||||
// if(!logContentDom) | |||||
// return | |||||
// let version_name = $('.log_top').data('version') | |||||
let version_name = $(this).data('version') | |||||
let logContentDom = document.querySelector(`#log${version_name}`) | |||||
$(`#log_file${version_name}`).siblings('pre').remove() | |||||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=&lines=50&order=asc`, (data) => { | |||||
$(`#log${version_name} input[name=end_line]`).val(data.EndLine) //如果变动就改变所对应的值 | |||||
$(`#log${version_name} input[name=start_line]`).val(data.StartLine) | |||||
$(`#log${version_name}`).prepend('<pre>' + data.Content) | |||||
$(`.message${version_name} #header`).text('您已翻阅至日志顶部') | |||||
$(`.message${version_name}`).css('display', 'block') | |||||
setTimeout(function () { | |||||
$(`.message${version_name}`).css('display', 'none') | |||||
}, 1000) | |||||
scrollAnimation(logContentDom, logContentDom.scrollTop, 0); | |||||
}) | |||||
}) | |||||
$('.log_bottom').click(function (e) { | |||||
let version_name = $(this).data('version') | |||||
let logContentDom = document.querySelector(`#log${version_name}`) | |||||
$(`#log_file${version_name}`).siblings('pre').remove() | |||||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=&lines=50&order=desc`, (data) => { | |||||
$(`#log${version_name} input[name=end_line]`).val(data.EndLine) //如果变动就改变所对应的值 | |||||
$(`#log${version_name} input[name=start_line]`).val(data.StartLine) | |||||
$(`#log${version_name}`).append('<pre>' + data.Content) | |||||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${data.EndLine}&lines=50&order=desc`, (data) => { | |||||
if (data.Lines == 0) { | |||||
$(`.message${version_name} #header`).text('您已翻阅至日志底部') | |||||
$(`.message${version_name}`).css('display', 'block') | |||||
setTimeout(function () { | |||||
$(`.message${version_name}`).css('display', 'none') | |||||
}, 1000) | |||||
} else { | |||||
if (end_line === data.EndLine) { | |||||
return | |||||
} | |||||
else { | |||||
$(`#log${version_name} input[name=end_line]`).val(data.EndLine) | |||||
$(`#log${version_name}`).append('<pre>' + data.Content) | |||||
} | |||||
} | |||||
}).fail(function (err) { | |||||
console.log(err); | |||||
}); | |||||
scrollAnimation(logContentDom, logContentDom.scrollTop + 1, logContentDom.scrollHeight - logContentDom.clientHeight); | |||||
}) | |||||
}) | |||||
</script> | </script> |
@@ -0,0 +1,586 @@ | |||||
<!-- 头部导航栏 --> | |||||
{{template "base/head" .}} | |||||
<!-- 弹窗 --> | |||||
<style> | |||||
.inline.fields .right.aligned label{ | |||||
width: 100% !important; | |||||
text-align: right; | |||||
} | |||||
.inline .ui.dropdown .text { | |||||
color: rgba(0, 0, 0, .87) !important; | |||||
left: 15px !important; | |||||
} | |||||
.text_color { | |||||
color: rgb(0 0 0 / 87%); | |||||
} | |||||
</style> | |||||
<div id="mask"> | |||||
<div id="loadingPage"> | |||||
<div class="rect1"></div> | |||||
<div class="rect2"></div> | |||||
<div class="rect3"></div> | |||||
<div class="rect4"></div> | |||||
<div class="rect5"></div> | |||||
</div> | |||||
</div> | |||||
{{$repository := .Repository.ID}} | |||||
<!-- 提示框 --> | |||||
<div class="alert"></div> | |||||
<div class="repository release dataset-list view"> | |||||
{{template "repo/header" .}} | |||||
<!-- 列表容器 --> | |||||
<div class="ui container" id="loadContainer"> | |||||
{{template "base/alert" .}} | |||||
<div class="ui two column stackable grid"> | |||||
<div class="column"> | |||||
<div class="ui blue small menu compact selectcloudbrain"> | |||||
<a class="item" href="{{.RepoLink}}/modelmanage/show_model">{{$.i18n.Tr "repo.model.list"}}</a> | |||||
<a class="active item" href="{{.RepoLink}}/modelmanage/convert_model">{{$.i18n.Tr "repo.model.convert"}}</a> | |||||
</div> | |||||
</div> | |||||
<div class="column right aligned"> | |||||
<!-- --> | |||||
<a class="ui button {{if .Permission.CanWrite $.UnitTypeModelManage}} green {{else}} disabled {{end}}" onclick="showcreate(this)">{{$.i18n.Tr "repo.model.manage.create_new_convert_task"}}</a> | |||||
</div> | |||||
</div> | |||||
{{if eq .MODEL_CONVERT_COUNT 0}} | |||||
<div class="ui placeholder segment bgtask-none"> | |||||
<div class="ui icon header bgtask-header-pic"></div> | |||||
<div class="bgtask-content-header">未创建过模型转换任务</div> | |||||
<div class="bgtask-content"> | |||||
{{if eq .MODEL_COUNT 0}} | |||||
<div class="bgtask-content-txt">请您先导入<a href="{{.RepoLink}}/modelmanage/show_model">模型</a>,然后再对其进行转换。</div> | |||||
{{end}} | |||||
<div class="bgtask-content-txt">使用说明:可以参考启智AI协作平台<a | |||||
href="https://git.openi.org.cn/zeizei/OpenI_Learning">小白训练营课程。</a></div> | |||||
</div> | |||||
</div> | |||||
{{else}} | |||||
<!-- 中下列表展示区 --> | |||||
<div class="ui grid"> | |||||
<div class="row" style="padding-top: 0;"> | |||||
<div class="ui sixteen wide column"> | |||||
<!-- 任务展示 --> | |||||
<div class="dataset list" id="model_convert_list"> | |||||
<!-- 表头 --> | |||||
<div class="ui grid stackable" style="background: #f0f0f0;;"> | |||||
<div class="row"> | |||||
<div class="three wide column padding0"> | |||||
<span style="margin:0 6px">任务名称</span> | |||||
</div> | |||||
<div class="two wide column text center padding0"> | |||||
<span>状态</span> | |||||
</div> | |||||
<div class="two wide column text center padding0"> | |||||
<span>原模型框架</span> | |||||
</div> | |||||
<div class="two wide column text center padding0"> | |||||
<span>转换后格式</span> | |||||
</div> | |||||
<div class="two wide column text center padding0"> | |||||
<span>创建时间</span> | |||||
</div> | |||||
<div class="one wide column text center padding0"> | |||||
<span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span> | |||||
</div> | |||||
<div class="three wide column text center padding0"> | |||||
<span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{{range .Tasks}} | |||||
<div class="ui grid stackable item"> | |||||
<div class="row"> | |||||
<div class="three wide column padding0"> | |||||
<a class="title" href="{{$.RepoLink}}/modelmanage/show_model_convert_info?ID={{.ID}}" title="{{.Name}}" style="font-size: 14px;"> | |||||
<span class="fitted" style="width: 90%;vertical-align: middle;">{{.Name}}</span> | |||||
</a> | |||||
</div> | |||||
<div class="two wide column padding0" style="padding-left: 2.2rem !important;"> | |||||
<span class="job-status" id="{{.ID}}" data-repopath="{{$.RepoRelPath}}/modelmanage" data-jobid="{{.ID}}" data-version=""> | |||||
<span><i id="{{.ID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{.ID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||||
</span> | |||||
</div> | |||||
<div class="two wide column center padding0"> | |||||
<span style="font-size: 12px;">{{if eq .SrcEngine 0}}PyTorch {{else if eq .SrcEngine 1}}TensorFlow{{else if eq .SrcEngine 2}}MindSpore {{end}}</span> | |||||
</div> | |||||
<div class="two wide column center padding0"> | |||||
<span style="font-size: 12px;">{{if eq .DestFormat 0}}ONNX {{else if eq .DestFormat 1}}TensorRT {{end}}</span> | |||||
</div> | |||||
<div class="two wide column center padding0"> | |||||
<span style="font-size: 12px;" class="">{{TimeSinceUnix .CreatedUnix $.Lang}}</span> | |||||
</div> | |||||
<div class="one wide column text center padding0"> | |||||
<a href="{{AppSubUrl}}/{{.UserName}}" title="{{.UserName}}"><img class="ui avatar image" src="{{.UserRelAvatarLink}}"></a> | |||||
</div> | |||||
<div class="three wide column text center padding0"> | |||||
<div class="ui compact buttons" > | |||||
<!-- 停止任务 --> | |||||
<form id="stopForm-{{.ID}}" style="margin-left:-1px;" action="{{$.RepoLink}}/modelmanage/convert_stop/{{.ID}}" method="post"> | |||||
{{$.CsrfTokenHtml}} | |||||
{{if .IsCanDelete}} | |||||
<a id="ai-stop-{{.ID}}" href="javascript:stopTask('{{.ID}}');" class='ui basic model_stop {{if eq .Status "COMPLETED" "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING" "SUCCEEDED"}}disabled {{else}}blue {{end}}button' > | |||||
{{$.i18n.Tr "repo.stop"}} | |||||
</a> | |||||
{{else}} | |||||
<a class="ui basic disabled button">{{$.i18n.Tr "repo.stop"}} </a> | |||||
{{end}} | |||||
</form> | |||||
<!-- 删除任务 --> | |||||
<form id="delForm-{{.ID}}" action="{{$.RepoLink}}/modelmanage/delete_model_convert/{{.ID}}" method="post"> | |||||
{{$.CsrfTokenHtml}} | |||||
{{if .IsCanDelete}} | |||||
<a id="ai-delete-{{.ID}}" class='ui basic ai_delete blue button' style="border-radius: .28571429rem;"> | |||||
{{$.i18n.Tr "repo.delete"}} | |||||
</a> | |||||
{{else}} | |||||
<a class="ui basic disabled button">{{$.i18n.Tr "repo.delete"}} </a> | |||||
{{end}} | |||||
</form> | |||||
{{if .IsCanOper}} | |||||
<a id="ai-download-{{.ID}}" href="{{$.Repository.HTMLURL}}/modelmanage/download_model_convert/{{.ID}}?AllDownload=true&a=1" class='ui basic {{if eq .Status "SUCCEEDED" "COMPLETED"}}blue {{else}}disabled {{end}}button' style="border-radius: .28571429rem;"> | |||||
下载 | |||||
</a> | |||||
{{else}} | |||||
<a class="ui basic disabled button">下载</a> | |||||
{{end}} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{{end}} | |||||
<div id="app" style="margin-top: 2rem;"> | |||||
<div class="center"> | |||||
<el-pagination | |||||
background | |||||
@current-change="handleCurrentChange" | |||||
:current-page="page" | |||||
:page-sizes="[10]" | |||||
:page-size="10" | |||||
layout="total, sizes, prev, pager, next, jumper" | |||||
:total="{{.Page.Paginater.Total}}"> | |||||
</el-pagination> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{{end}} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<!-- 确认模态框 --> | |||||
<div id="deletemodel"> | |||||
<div class="ui basic modal first"> | |||||
<div class="ui icon header"> | |||||
<i class="trash icon"></i> 删除模型 | |||||
</div> | |||||
<div class="content"> | |||||
<p>你确认删除该模型转换任务么?一旦删除不可恢复。</p> | |||||
</div> | |||||
<div class="actions"> | |||||
<div class="ui red basic inverted cancel button"> | |||||
<i class="remove icon"></i> {{.i18n.Tr "cloudbrain.operate_cancel"}} | |||||
</div> | |||||
<div class="ui green basic inverted ok button"> | |||||
<i class="checkmark icon"></i> {{.i18n.Tr "cloudbrain.operate_confirm"}} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div id="newmodelconvert"> | |||||
<div class="ui modal second"> | |||||
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);"> | |||||
<h4 id="model_header"></h4> | |||||
</div> | |||||
<div class="content content-padding"> | |||||
<div id="formdiv" class="ui form" > | |||||
<input type="hidden" name="initModel" value="{{$.MODEL_COUNT}}"> | |||||
<div class="ui error message"> | |||||
<!-- <p>asdasdasd</p> --> | |||||
</div> | |||||
<input type="hidden" name="_csrf" value=""> | |||||
<div class="unite min_title required inline fields" id="task_name"> | |||||
<div class="three wide field right aligned"> | |||||
<label for="model_convert_name">任务名称</label> | |||||
</div> | |||||
<div class="twelve wide field"> | |||||
<input id="model_convert_name" name="model_convert_name" required maxlength="25" onkeyup="this.value=this.value.replace(/[, ]/g,'')"> | |||||
</div> | |||||
</div> | |||||
<div class="unite min_title inline fields required"> | |||||
<div class="three wide field right aligned"> | |||||
<label for="choice_model">模型名称</label> | |||||
</div> | |||||
<div class="ui dropdown selection search eight wide field loading" id="choice_model" name="choice_model"> | |||||
<div class="default text">选择模型</div> | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu" id="model-name"> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="unite min_title inline fields required"> | |||||
<div class="three wide field right aligned"> | |||||
<label for="choice_version">模型版本</label> | |||||
</div> | |||||
<div class="ui dropdown selection search eight wide field" id="choice_version"> | |||||
<input type="hidden" id="ModelVersion" name="ModelVersion" required> | |||||
<div class="default text">选择版本</div> | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu" id="model-version"> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="unite min_title inline fields required"> | |||||
<div class="three wide field right aligned"> | |||||
<label for="choice_file">模型文件</label> | |||||
</div> | |||||
<div class="ui dropdown selection search eight wide field" id="choice_file"> | |||||
<input type="hidden" id="ModelFile" name="ModelFile" required> | |||||
<div class="default text">选择模型文件</div> | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu" id="model-file"> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="unite min_title inline fields required"> | |||||
<div class="three wide field right aligned"> | |||||
<label for="SrcEngine">原模型框架</label> | |||||
</div> | |||||
<select id="SrcEngine" class="ui search dropdown eight wide field" placeholder="" style='color:#000000;' name="SrcEngine" onchange="javascript:srcEngineChanged()"> | |||||
</select> | |||||
</div> | |||||
<div class="unite min_title required inline fields" id="inputdataformat_div"> | |||||
<div class="three wide field right aligned"> | |||||
<label for="inputdataformat">输入数据格式</label> | |||||
</div> | |||||
<select id="inputdataformat" class="ui search dropdown eight wide field" placeholder="" style='width:50%' name="inputdataformat"> | |||||
<option name="NCHW" value="NCHW">NCHW</option> | |||||
<option name="NHWC" value="NHWC">NHWC</option> | |||||
</select> | |||||
</div> | |||||
<div class="unite min_title required inline fields" id="inputshape_div"> | |||||
<div class="three wide field right aligned"> | |||||
<label for="inputshape">输入张量形状</label> | |||||
</div> | |||||
<div class="eight wide field"> | |||||
<input id="inputshape" name="inputshape" placeholder="如:1,1,32,32,与输入数据格式对应。" required maxlength="25"> | |||||
</div> | |||||
</div> | |||||
<div class="unite min_title inline fields required"> | |||||
<div class="three wide field right aligned"> | |||||
<label for="DestFormat">转换后格式</label> | |||||
</div> | |||||
<select id="DestFormat" class="ui search dropdown eight wide field" placeholder="" style='width:50%' name="DestFormat"> | |||||
</select> | |||||
</div> | |||||
<div class="unite min_title inline fields"> | |||||
<div class="three wide field right aligned"> | |||||
<label for="NetOutputFormat">网络输出数据类型 </label> | |||||
</div> | |||||
<select id="NetOutputFormat" class="ui search dropdown eight wide field" placeholder="" style='width:50%' name="NetOutputFormat"> | |||||
</select> | |||||
</div> | |||||
<div class="unite min_title inline fields"> | |||||
<div class="three wide field right aligned"> | |||||
<label for="Description">任务描述 </label> | |||||
</div> | |||||
<div class="twelve wide field"> | |||||
<textarea id="Description" name="Description" rows="1" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}' onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 256)"></textarea> | |||||
</div> | |||||
</div> | |||||
<div class="unite min_title inline field"> | |||||
<button id="submitId" name="submitId" type="button" class="ui create_train_job green button" style="position: absolute;margin-left: 150px;"> | |||||
新建任务 | |||||
</button> | |||||
</div> | |||||
</div> | |||||
<div class="actions" style="display: inline-block;margin-left: 250px;"> | |||||
<button class="ui button cancel" >{{.i18n.Tr "repo.cloudbrain.cancel"}}</button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{{template "base/footer" .}} | |||||
<script> | |||||
let repolink = {{.RepoLink}} | |||||
let repoId = {{$repository}} | |||||
const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config; | |||||
$('input[name="_csrf"]').val(csrf) | |||||
var modelData; | |||||
function inputshapeNotValid(value){ | |||||
if(value == null || value ==""){ | |||||
return true; | |||||
} | |||||
var tmps = value.split(","); | |||||
if(tmps.length ==4){ | |||||
return false; | |||||
}else{ | |||||
return true; | |||||
} | |||||
} | |||||
$('#submitId').click(function(){ | |||||
let data={}; | |||||
data['_csrf']=csrf | |||||
data['name']= $('#model_convert_name').val() | |||||
if(data['name']==""){ | |||||
$('.ui.error.message').text("请输入任务名称。") | |||||
$('.ui.error.message').css('display','block') | |||||
$("#task_name").addClass("error") | |||||
return false | |||||
}else{ | |||||
$("#task_name").removeClass("error") | |||||
} | |||||
data['desc']= $('#Description').val() | |||||
data['modelId'] = $('#ModelVersion').val() | |||||
data['SrcEngine'] = $('#SrcEngine').val(); | |||||
data['inputshape']= $('#inputshape').val(); | |||||
if(inputshapeNotValid(data['inputshape'])){ | |||||
$('.ui.error.message').text("格式输入错误,请输入如:1,1,32,32,与输入数据格式对应。") | |||||
$('.ui.error.message').css('display','block') | |||||
$("#inputshape_div").addClass("error") | |||||
return false | |||||
}else{ | |||||
$("#inputshape_div").removeClass("error") | |||||
} | |||||
data['inputdataformat']= $('#inputdataformat').val(); | |||||
data['DestFormat'] = $('#DestFormat').val(); | |||||
data['NetOutputFormat']= $('#NetOutputFormat').val(); | |||||
data['ModelFile'] = $('#ModelFile').val(); | |||||
$.post(`${repolink}/modelmanage/create_model_convert`,data,(result) => { | |||||
console.log("result=" + result); | |||||
if(result.result_code ==0){ | |||||
$('.ui.modal.second').modal('hide'); | |||||
window.location.reload(); | |||||
}else{ | |||||
$('.ui.error.message').text(result.message) | |||||
$('.ui.error.message').css('display','block') | |||||
} | |||||
}) | |||||
}) | |||||
function stopTask(id){ | |||||
console.log("stop form stopForm-" + id); | |||||
document.getElementById("stopForm-" + id).submit(); | |||||
} | |||||
function createModelName(){ | |||||
let repoName = location.pathname.split('/')[2] | |||||
let modelName = repoName + '_modelConvert_' + Math.random().toString(36).substr(2, 4) | |||||
$('#model_convert_name').val(modelName) | |||||
} | |||||
function showcreate(obj){ | |||||
$('.ui.modal.second') | |||||
.modal({ | |||||
centered: false, | |||||
onShow:function(){ | |||||
$('#model_header').text("创建模型转换任务") | |||||
$('.ui.dimmer').css({"background-color":"rgb(136, 136, 136,0.7)"}) | |||||
createModelName() | |||||
loadModelList() | |||||
}, | |||||
onHide:function(){ | |||||
//document.getElementById("formId").reset(); | |||||
$('#model_convert_name').val("") | |||||
$('#choice_model').dropdown('clear') | |||||
$('#choice_version').dropdown('clear') | |||||
$('#choice_file').dropdown('clear') | |||||
console.log("div hidde ...."); | |||||
$('.ui.dimmer').css({"background-color":""}) | |||||
$('.ui.error.message').text() | |||||
$('.ui.error.message').css('display','none') | |||||
$("#task_name").removeClass("error") | |||||
$("#inputshape_div").removeClass("error") | |||||
} | |||||
}) | |||||
.modal('show') | |||||
} | |||||
$(function(){ | |||||
$('#choice_model').dropdown({ | |||||
onChange:function(value){ | |||||
$("#choice_model").addClass("loading") | |||||
$('#choice_version').dropdown('clear') | |||||
$('#choice_file').dropdown('clear') | |||||
$("#model-version").empty() | |||||
$("#model-file").empty() | |||||
loadModelVersion(value) | |||||
$("#choice_model").removeClass("loading") | |||||
} | |||||
}) | |||||
$('#choice_version').dropdown({ | |||||
onChange:function(value){ | |||||
console.log("model version:" + value); | |||||
$('#choice_version input[name="ModelVersion"]').val(value) | |||||
loadModelFile(value); | |||||
} | |||||
}) | |||||
$('#choice_file').dropdown({ | |||||
onChange:function(value){ | |||||
console.log("model file:" + value); | |||||
$('#choice_file input[name="ModelFile"]').val(value) | |||||
} | |||||
}) | |||||
}) | |||||
function srcEngineChanged(){ | |||||
var ele = window.document.getElementById("SrcEngine"); | |||||
var index=ele.selectedIndex; | |||||
var options=ele.options; | |||||
var option = options[index]; | |||||
console.log("SrcEngine value=" + option); | |||||
let destFormatHtml = "<option name=\"ONNX\" value=\"0\">ONNX</option>"; | |||||
let netOutputFormatHtml = "<option name=\"FP32\" value=\"0\">FP32</option>"; | |||||
if(option==null || option =="undefined" || option.value == 0){ | |||||
destFormatHtml += "<option name=\"TensorRT\" value=\"1\">TensorRT</option>" | |||||
netOutputFormatHtml += "<option name=\"FP16\" value=\"1\">FP16</option>"; | |||||
} | |||||
$('#DestFormat').html(destFormatHtml); | |||||
$('#NetOutputFormat').html(netOutputFormatHtml); | |||||
} | |||||
function loadModelList(){ | |||||
$.get(`${repolink}/modelmanage/query_model_for_predict?repoId=${repoId}`, (data) => { | |||||
modelData = data | |||||
let nameList = data.nameList | |||||
const n_length = nameList.length | |||||
let train_html='' | |||||
for (let i=0;i<n_length;i++){ | |||||
train_html += `<div class="item" data-value="${nameList[i]}">${nameList[i]}</div>` | |||||
train_html += '</div>' | |||||
} | |||||
$("#model-name").append(train_html) | |||||
$("#choice_model").removeClass("loading") | |||||
$('#choice_model .default.text').text(nameList[0]) | |||||
loadModelVersion(nameList[0]) | |||||
}) | |||||
} | |||||
function loadModelFile(modelId){ | |||||
console.log("modelId=" + modelId); | |||||
$('#choice_file').dropdown('clear') | |||||
$("#model-file").empty() | |||||
if(modelId ==null || modelId ==""){ | |||||
console.log("modelId is null"); | |||||
}else{ | |||||
$.get(`${repolink}/modelmanage/query_modelfile_for_predict?ID=${modelId}`, (data) => { | |||||
const n_length = data.length | |||||
let file_html='' | |||||
let firstFileName ='' | |||||
for (let i=0;i<n_length;i++){ | |||||
if(isModel(data[i].FileName)){ | |||||
if(firstFileName ==''){ | |||||
firstFileName = data[i].FileName; | |||||
} | |||||
file_html += `<div class="item" data-value="${data[i].FileName}">${data[i].FileName}</div>` | |||||
file_html += '</div>' | |||||
}else{ | |||||
console.log("not model. filename=" + data[i].FileName); | |||||
} | |||||
} | |||||
$("#model-file").append(file_html) | |||||
$('#choice_file .default.text').text(firstFileName) | |||||
$('#choice_file input[name="ModelFile"]').val(firstFileName) | |||||
}) | |||||
} | |||||
} | |||||
function isModel(filename){ | |||||
var postfix=[".pth",".pkl",".onnx",".mindir",".ckpt",".pb"]; | |||||
for(var i =0; i<postfix.length;i++){ | |||||
if(filename.substring(filename.length-postfix[i].length)==postfix[i]){ | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
function loadModelVersion(value){ | |||||
console.log("value=" + value); | |||||
if(value ==null || value ==""){ | |||||
}else{ | |||||
let nameMap = modelData.nameMap | |||||
let versionList = nameMap[value] | |||||
n_length = versionList.length | |||||
let train_html='' | |||||
for (let i=0;i<n_length;i++){ | |||||
train_html += `<div class="item" data-value="${versionList[i].ID}">${versionList[i].Version}</div>` | |||||
train_html += '</div>' | |||||
} | |||||
$("#model-version").append(train_html) | |||||
$('#choice_version .default.text').text(versionList[0].Version) | |||||
$('#choice_version input[name="ModelVersion"]').val(versionList[0].ID) | |||||
loadModelFile(versionList[0].ID); | |||||
} | |||||
setEngineValue(value); | |||||
} | |||||
function setEngineValue(value){ | |||||
$('#SrcEngine').dropdown('clear'); | |||||
console.log("setEngineValue value=" + value); | |||||
let html = "" | |||||
html +="<option name=\"PyTorch\" " + getSelected(0,value) + " value=\"0\">PyTorch</option>"; | |||||
html +="<option name=\"TensorFlow\" " + getSelected(1,value) + " value=\"1\">TensorFlow</option>"; | |||||
html +="<option name=\"MindSpore\" " + getSelected(2,value) + " value=\"2\">MindSpore</option>"; | |||||
$('#SrcEngine').html(html); | |||||
srcEngineChanged(); | |||||
} | |||||
function getSelected(engineOption, modelName){ | |||||
if(modelName ==null || modelName ==""){ | |||||
return ""; | |||||
} | |||||
let nameMap = modelData.nameMap | |||||
let versionList = nameMap[modelName] | |||||
if(versionList != null && versionList.length >0){ | |||||
if(versionList[0].Engine == engineOption){ | |||||
return "selected=\"selected\""; | |||||
}else{ | |||||
if(versionList[0].Engine==122 && engineOption==2){ | |||||
return "selected=\"selected\""; | |||||
} | |||||
if(versionList[0].Engine==121 && engineOption==1){ | |||||
return "selected=\"selected\""; | |||||
} | |||||
} | |||||
} | |||||
return ""; | |||||
} | |||||
</script> | |||||
@@ -0,0 +1,854 @@ | |||||
{{template "base/head" .}} | |||||
<style> | |||||
.according-panel-heading{ | |||||
box-sizing: border-box; | |||||
padding: 8px 16px; | |||||
color: #252b3a; | |||||
background-color: #f2f5fc; | |||||
line-height: 1.5; | |||||
cursor: pointer; | |||||
-moz-user-select: none; | |||||
-webkit-user-select: none; | |||||
-ms-user-select: none; | |||||
-khtml-user-select: none; | |||||
user-select: none; | |||||
} | |||||
.accordion-panel-title { | |||||
margin-top: 0; | |||||
margin-bottom: 0; | |||||
color: #252b3a; | |||||
} | |||||
.accordion-panel-title-content{ | |||||
vertical-align: middle; | |||||
display: inline-block; | |||||
width: calc(100% - 32px); | |||||
cursor: default; | |||||
} | |||||
.acc-margin-bottom { | |||||
margin-bottom: 5px; | |||||
} | |||||
.title_text { | |||||
font-size: 12px; | |||||
} | |||||
.ac-display-inblock { | |||||
display: inline-block; | |||||
} | |||||
.cti-mgRight-sm { | |||||
margin-right: 8px; | |||||
} | |||||
.ac-text-normal { | |||||
font-size: 14px; | |||||
color: #575d6c; | |||||
} | |||||
.uc-accordionTitle-black { | |||||
color: #333; | |||||
} | |||||
.accordion-border{ | |||||
border:1px solid #cce2ff; | |||||
} | |||||
.padding0{ | |||||
padding: 0 !important; | |||||
} | |||||
.content-pad{ | |||||
padding: 15px 35px; | |||||
} | |||||
.content-margin{ | |||||
margin:10px 5px ; | |||||
} | |||||
.tab_2_content { | |||||
min-height: 360px; | |||||
margin-left: 10px; | |||||
} | |||||
.ac-grid { | |||||
display: block; | |||||
*zoom: 1; | |||||
} | |||||
.ac-grid-col { | |||||
float: left; | |||||
width: 100%; | |||||
} | |||||
.ac-grid-col2 .ac-grid-col { | |||||
width: 50%; | |||||
} | |||||
.ti-form { | |||||
text-align: left; | |||||
max-width: 100%; | |||||
vertical-align: middle; | |||||
} | |||||
.ti-form>tbody { | |||||
font-size: 12px; | |||||
} | |||||
.ti-form>tbody, .ti-form>tbody>tr { | |||||
vertical-align: inherit; | |||||
} | |||||
.ti-text-form-label { | |||||
padding-bottom: 20px; | |||||
padding-right: 20px; | |||||
color: #8a8e99; | |||||
font-size: 12px; | |||||
white-space: nowrap !important; | |||||
width: 80px; | |||||
line-height: 30px; | |||||
} | |||||
.ti-text-form-content{ | |||||
line-height: 30px; | |||||
padding-bottom: 20px; | |||||
} | |||||
.ti-form>tbody>tr>td { | |||||
vertical-align: top; | |||||
white-space: normal; | |||||
} | |||||
td, th { | |||||
padding: 0; | |||||
} | |||||
.info_text { | |||||
padding-bottom: 20px; | |||||
padding-right: 20px; | |||||
font-size: 12px; | |||||
} | |||||
.ac-grid-col .text-span { | |||||
width: 450px; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
white-space: nowrap; | |||||
} | |||||
.redo-color{ | |||||
color: #3291F8; | |||||
} | |||||
.ti-action-menu-item:not(:last-child){ | |||||
margin-right: 10px; | |||||
padding-right: 11px; | |||||
text-decoration: none!important; | |||||
color: #526ecc; | |||||
cursor: pointer; | |||||
display: inline-block; | |||||
-moz-user-select: none; | |||||
-webkit-user-select: none; | |||||
-ms-user-select: none; | |||||
-khtml-user-select: none; | |||||
user-select: none; | |||||
position: relative; | |||||
} | |||||
.ti-action-menu-item:not(:last-child):after { | |||||
content: ""; | |||||
display: inline-block; | |||||
position: absolute; | |||||
height: 12px; | |||||
right: 0; | |||||
top: 50%; | |||||
-webkit-transform: translateY(-6px); | |||||
-ms-transform: translateY(-6px); | |||||
-o-transform: translateY(-6px); | |||||
transform: translateY(-6px); | |||||
border-right: 1px solid #dfe1e6; | |||||
} | |||||
.text-width80{ | |||||
width: 100px; | |||||
line-height: 30px; | |||||
} | |||||
.border-according-model{ | |||||
border: 1px solid #dfe1e6; | |||||
} | |||||
.disabled { | |||||
cursor: default; | |||||
pointer-events: none; | |||||
color: rgba(0,0,0,.6) !important; | |||||
opacity: .45 !important; | |||||
} | |||||
.pad20{ | |||||
border:0px !important; | |||||
} | |||||
.model_file_bread{ | |||||
margin-bottom: -0.5rem !important; | |||||
padding-left: 1rem; | |||||
padding-top: 0.5rem ; | |||||
} | |||||
</style> | |||||
<div id="mask"> | |||||
<div id="loadingPage"> | |||||
<div class="rect1"></div> | |||||
<div class="rect2"></div> | |||||
<div class="rect3"></div> | |||||
<div class="rect4"></div> | |||||
<div class="rect5"></div> | |||||
</div> | |||||
</div> | |||||
<div class="repository"> | |||||
{{template "repo/header" .}} | |||||
<div class="ui container"> | |||||
<h4 class="ui header" id="vertical-segment"> | |||||
<div class="ui breadcrumb"> | |||||
<a class="section" href="{{$.RepoLink}}/modelmanage/convert_model"> | |||||
模型转换任务 | |||||
</a> | |||||
<div class="divider"> / </div> | |||||
<div class="active section">{{.Name}}</div> | |||||
</div> | |||||
</h4> | |||||
{{with .task}} | |||||
<div class="ui accordion border-according-model" id="accordion" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.CloudBrainTaskId}}" data-version="1"> | |||||
<input type="hidden" id="jobId_input" name="jobId_input" value="{{.CloudBrainTaskId}}"> | |||||
<div class="active title padding0"> | |||||
<div class="according-panel-heading"> | |||||
<div class="accordion-panel-title"> | |||||
<i class="dropdown icon"></i> | |||||
<span class="accordion-panel-title-content"> | |||||
<span> | |||||
<div class="ac-display-inblock title_text acc-margin-bottom"> | |||||
<span class="cti-mgRight-sm">{{TimeSinceUnix1 .CreatedUnix}}</span> | |||||
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}: | |||||
<span id="status-span"><i id="icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||||
</span> | |||||
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span> | |||||
<span class="cti-mgRight-sm uc-accordionTitle-black" id="duration-span">{{.TrainJobDuration}}</span> | |||||
</div> | |||||
</span> | |||||
</span> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="active content"> | |||||
<div class="content-pad"> | |||||
<div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);"> | |||||
<a class="active item" data-tab="first">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a> | |||||
<a id="gpuruntimeinfo" style="display: {{$.gpu_display}};" class="item" data-tab="second" onclick="javascript:parseInfo()">{{$.i18n.Tr "repo.cloudbrain.runinfo"}}</a> | |||||
<a id="gpulog" style="display: {{$.gpu_display}};" class="item" data-tab="third" onclick="loadLog()">{{$.i18n.Tr "repo.modelarts.log"}}</a> | |||||
<a id="npulog" style="display: {{$.npu_display}};" class="item log_bottom" data-tab="five" data-version="">{{$.i18n.Tr "repo.modelarts.log"}}</a> | |||||
<a class="item" data-tab="four" onclick="loadModelFile()">{{$.i18n.Tr "repo.model_download"}}</a> | |||||
</div> | |||||
<div class="ui tab active" data-tab="first"> | |||||
<div style="padding-top: 10px;"> | |||||
<div class="tab_2_content"> | |||||
<div class="ac-grid ac-grid-col2"> | |||||
<div class="ac-grid-col"> | |||||
<table class="ti-form"> | |||||
<tbody class="ti-text-form"> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain_task"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{.Name}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.status"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="status"> | |||||
{{.Status}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
输入张量形状 | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="InputShape"> | |||||
{{.InputShape}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
输入数据格式 | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="InputDataFormat"> | |||||
{{.InputDataFormat}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.start_time"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
<span style="font-size: 12px;" class="">{{TimeSinceUnix1 .CreatedUnix}}</span> | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="duration"> | |||||
{{.TrainJobDuration}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
网络输出数据类型 | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="duration"> | |||||
{{if eq .NetOutputFormat 0}}FP32 {{else if eq .NetOutputFormat 1}}FP16 {{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
<div class="ac-grid-col"> | |||||
<table class="ti-form"> | |||||
<tbody class="ti-text-form"> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
模型名称 | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{.ModelName}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
模型版本 | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{.ModelVersion}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
模型文件 | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{.ModelPath}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
原模型框架 | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{if eq .SrcEngine 0}}PyTorch {{else if eq .SrcEngine 1}}Tensorflow{{else if eq .SrcEngine 2}}MindSpore {{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
转换后格式 | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{if eq .DestFormat 0}}ONNX {{else if eq .DestFormat 1}}TensorRT {{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.description"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" title="{{.Description}}"> | |||||
{{.Description}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain_creator"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="username"> | |||||
{{.UserName}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="ui tab" data-tab="second"> | |||||
<div> | |||||
<div class="ui message message" style="display: none;"> | |||||
<div id="header"></div> | |||||
</div> | |||||
<div class="ui attached log" id="log" style="height: 390px !important; overflow: auto;"> | |||||
<input type="hidden" id="json_value" value="{{$.AppExitDiagnostics}}"> | |||||
<input type="hidden" id="ExitDiagnostics" value="{{$.ExitDiagnostics}}"> | |||||
<span id="info_display" class="info_text"> | |||||
</span> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="ui tab" data-tab="third"> | |||||
<div> | |||||
<div class="ui message message" style="display: none;"> | |||||
<div id="header"></div> | |||||
</div> | |||||
<div class="ui attached log" id="log" style="height: 300px !important; overflow: auto;"> | |||||
<input type="hidden" name="end_line"> | |||||
<input type="hidden" name="start_line"> | |||||
<pre id="log_file"></pre> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="ui tab" data-tab="five"> | |||||
<div style="position: relative;"> | |||||
<span> | |||||
<a title="滚动到顶部" style="position: absolute; right: -32px;cursor: pointer;" class="log_top" data-version="V0001"><i class="icon-to-top"></i></a> | |||||
</span> | |||||
<span> | |||||
<a title="滚动到底部" style="position: absolute; bottom: 10px;right: -32px;cursor: pointer;" class="log_bottom" data-version="V0001"><i class="icon-to-bottom"></i></a> | |||||
</span> | |||||
<div id="log_npu_message" class="ui message message" style="display: none;"> | |||||
<div id="log_npu_header"></div> | |||||
</div> | |||||
<div class="ui attached log" onscroll="fn()" id="log_npu" style="height: 300px !important; overflow: auto;"> | |||||
<input type="hidden" name="end_line" value> | |||||
<input type="hidden" name="start_line" value> | |||||
<pre id="log_file_npu"></pre> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="ui tab" data-tab="four"> | |||||
<input type="hidden" name="model" value="-1"> | |||||
<input type="hidden" name="modelback" value="-1"> | |||||
<div class='ui breadcrumb model_file_bread' id='file_breadcrumb'> | |||||
<div class="active section"></div> | |||||
<div class="divider"> / </div> | |||||
</div> | |||||
<div id="dir_list"> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{{end}} {{template "base/paginate" .}} | |||||
</div> | |||||
<!-- 确认模态框 --> | |||||
</div> | |||||
{{template "base/footer" .}} | |||||
<script> | |||||
$('.menu .item').tab() | |||||
$(document).ready(function(){ | |||||
$('.ui.accordion').accordion({selector:{trigger:'.icon'}}); | |||||
}); | |||||
$(document).ready(function(){ | |||||
$('.secondary.menu .item').tab(); | |||||
}); | |||||
let userName | |||||
let repoPath | |||||
let jobID = {{$.task.CloudBrainTaskId}} | |||||
let downlaodFlag = {{$.canDownload}} | |||||
let taskID = {{$.task.ID}} | |||||
let realJobName = {{$.task.ID}} | |||||
$(document).ready(function(){ | |||||
let url = window.location.href; | |||||
let urlArr = url.split('/') | |||||
userName = urlArr.slice(-4)[0] | |||||
repoPath = urlArr.slice(-3)[0] | |||||
console.log("userName=" + userName + " repoPath=" + repoPath); | |||||
}) | |||||
function stopBubbling(e) { | |||||
e = window.event || e; | |||||
if (e.stopPropagation) { | |||||
e.stopPropagation(); //阻止事件 冒泡传播 | |||||
} else { | |||||
e.cancelBubble = true; //ie兼容 | |||||
} | |||||
} | |||||
let timeid = window.setInterval(loadJobStatus, 30000); | |||||
$(document).ready(loadJobStatus); | |||||
function loadLog(version_name){ | |||||
document.getElementById("mask").style.display = "block" | |||||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelmanage/${taskID}/log?version_name=${version_name}&lines=50&order=asc`, (data) => { | |||||
$('input[name=end_line]').val(data.EndLine) | |||||
$('input[name=start_line]').val(data.StartLine) | |||||
$(`#log_file`).text(data.Content) | |||||
document.getElementById("mask").style.display = "none" | |||||
}).fail(function(err) { | |||||
console.log(err); | |||||
document.getElementById("mask").style.display = "none" | |||||
}); | |||||
} | |||||
function loadModelFile(version_name,parents,filename,init){ | |||||
parents = parents || '' | |||||
filename = filename || '' | |||||
init = init || '' | |||||
console.log("start") | |||||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelmanage/${taskID}/model_list?version_name=${version_name}&parentDir=${parents}`, (data) => { | |||||
$(`#dir_list`).empty() | |||||
renderDir(data,version_name) | |||||
if(init==="init"){ | |||||
$(`input[name=model]`).val("") | |||||
$(`input[name=modelback]`).val(version_name) | |||||
$(`#file_breadcrumb`).empty() | |||||
let htmlBread = "/" | |||||
$(`#file_breadcrumb`).append(htmlBread) | |||||
}else{ | |||||
renderBrend(version_name,parents,filename,init) | |||||
} | |||||
}).fail(function(err) { | |||||
console.log(err,version_name); | |||||
}); | |||||
} | |||||
function renderBrend(version_name,parents,filename,init){ | |||||
if(init=="folder"){ | |||||
let htmlBrend = "" | |||||
let sectionName=$(`#file_breadcrumb .active.section`).text() | |||||
let parents1 = $(`input[name=model]`).val() | |||||
let filename1 = $(`input[name=modelback]`).val() | |||||
if(parents1===""){ | |||||
$(`#file_breadcrumb .active.section`).replaceWith(`<a class='section' onclick="loadModelFile('${version_name}','${parents1}','','init')">${sectionName}</a>`) | |||||
}else{ | |||||
$(`#file_breadcrumb .active.section`).replaceWith(`<a class='section' onclick="loadModelFile('${version_name}','${parents1}','${filename1}')">${sectionName}</a>`) | |||||
} | |||||
htmlBrend += `<div class='active section'>${filename}</div>` | |||||
htmlBrend += "<div class='divider'> / </div>" | |||||
$(`#file_breadcrumb`).append(htmlBrend) | |||||
$(`input[name=model]`).val(parents) | |||||
$(`input[name=modelback]`).val(filename) | |||||
}else{ | |||||
$(`input[name=model]`).val(parents) | |||||
$(`input[name=modelback]`).val(filename) | |||||
$(`#file_breadcrumb a.section:contains(${filename})`).nextAll().remove() | |||||
$(`#file_breadcrumb a.section:contains(${filename})`).replaceWith(`<div class='active section'>${filename}</div>`) | |||||
//$(`#file_breadcrumb div.section:contains(${filename})`).append("<div class='divider'> / </div>") | |||||
} | |||||
} | |||||
function renderDir(data,version_name){ | |||||
let html="" | |||||
html += "<div class='ui grid' style='margin:0;'>" | |||||
html += "<div class='row' style='padding: 0;'>" | |||||
html += "<div class='ui sixteen wide column' style='padding:1rem;'>" | |||||
html += "<div class='dir list'>" | |||||
html += "<table id='repo-files-table' class='ui single line table pad20'>" | |||||
html += '<tbody>' | |||||
for(let i=0;i<data.Dirs.length;i++){ | |||||
let dirs_size = renderSize(data.Dirs[i].Size) | |||||
html += "<tr>" | |||||
html += "<td class='name six wid'>" | |||||
html += "<span class='truncate'>" | |||||
html += "<span class='octicon octicon-file-directory'>" | |||||
html += "</span>" | |||||
if(data.Dirs[i].IsDir){ | |||||
html += `<a onclick="loadModelFile('${version_name}','${data.Dirs[i].ParenDir}','${data.Dirs[i].FileName}','folder')">` | |||||
html += "<span class='fitted'><i class='folder icon' width='16' height='16' aria-hidden='true'></i>" + data.Dirs[i].FileName + "</span>" | |||||
}else{ | |||||
if(downlaodFlag){ | |||||
html += `<a href="/${userName}/${repoPath}/modelmanage/download_model_convert/${taskID}?fileName=${data.Dirs[i].FileName}&parentDir=${data.Dirs[i].ParenDir}&jobName=${realJobName}">` | |||||
} | |||||
else{ | |||||
html += `<a class="disabled">` | |||||
} | |||||
html += "<span class='fitted'><i class='file icon' width='16' height='16' aria-hidden='true'></i>" + data.Dirs[i].FileName + "</span>" | |||||
} | |||||
html += '</a>' | |||||
html += "</span>" | |||||
html += "</td>" | |||||
html += "<td class='message seven wide'>" | |||||
if(data.Dirs[i].IsDir){ | |||||
html += "<span class='truncate has-emoji'></span>" | |||||
}else{ | |||||
html += "<span class='truncate has-emoji'>"+ `${dirs_size}` + "</span>" | |||||
} | |||||
html += "</td>" | |||||
html += "<td class='text right age three wide'>" | |||||
html += "<span class='truncate has-emoji'>" + data.Dirs[i].ModTime + "</span>" | |||||
html += "</td>" | |||||
html += "</tr>" | |||||
} | |||||
html += "</tbody>" | |||||
html += "</table>" | |||||
html += "</div>" | |||||
html += "</div>" | |||||
html += "</div>" | |||||
html += "</div>" | |||||
$(`#dir_list`).append(html) | |||||
} | |||||
function renderSize(value){ | |||||
if(null==value||value==''){ | |||||
return "0 Bytes"; | |||||
} | |||||
var unitArr = new Array("Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"); | |||||
var index=0; | |||||
var srcsize = parseFloat(value); | |||||
index=Math.floor(Math.log(srcsize)/Math.log(1024)); | |||||
var size =srcsize/Math.pow(1024,index); | |||||
size=size.toFixed(0);//保留的小数位数 | |||||
return size+unitArr[index]; | |||||
} | |||||
function loadJobStatus() { | |||||
$(".ui.accordion.border-according-model").each((index, job) => { | |||||
const jobID = job.dataset.jobid; | |||||
const repoPath = job.dataset.repopath; | |||||
const versionname = job.dataset.version | |||||
let status = $(`#status-span`).text() | |||||
if(['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED','SUCCEEDED','STOPPED'].includes(status)){ | |||||
return | |||||
} | |||||
let stopArray=["KILLED","FAILED","START_FAILED","KILLING","COMPLETED","SUCCEEDED","STOPPED"] | |||||
$.get(`/api/v1/repos/${repoPath}/modelmanage/${taskID}?version_name=${versionname}`, (data) => { | |||||
$(`#status-span span`).text(data.JobStatus) | |||||
$(`#status-span i`).attr("class",data.JobStatus) | |||||
$('#status').text(data.JobStatus) | |||||
}).fail(function(err) { | |||||
console.log(err); | |||||
}); | |||||
}); | |||||
}; | |||||
function parseInfo(){ | |||||
let jsonValue = document.getElementById("json_value").value; | |||||
let jsonObj = JSON.parse(jsonValue); | |||||
let podRoleName = jsonObj["podRoleName"]; | |||||
let html = ""; | |||||
if (podRoleName != null){ | |||||
let task0 = podRoleName["task1-0"]; | |||||
let podEvents = jsonObj["podEvents"]; | |||||
let podEventArray = podEvents[task0]; | |||||
if(podEventArray != null){ | |||||
for(var i=0; i < podEventArray.length;i++){ | |||||
if (podEventArray[i]["reason"]!="") { | |||||
html +="<p><b>[" +podEventArray[i]["reason"] + "]</b></p>"; | |||||
html +="<p>" +podEventArray[i]["message"] + "</p>"; | |||||
html +="<p>" +podEventArray[i]["action"] + "</p>"; | |||||
} | |||||
} | |||||
} | |||||
let extras= jsonObj["extras"]; | |||||
if(extras != null){ | |||||
for(var i=0; i < extras.length;i++){ | |||||
if (extras[i]["reason"]!="") { | |||||
html +="<p><b>[" +extras[i]["reason"] + "]</b></p>"; | |||||
html +="<p>" +extras[i]["message"] + "</p>"; | |||||
html +="<p>" +extras[i]["action"] + "</p>"; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
let string = document.getElementById("ExitDiagnostics").value; | |||||
string = string.replace(/\r\n/g,"<br>") | |||||
string = string.replace(/\n/g,"<br>"); | |||||
string = string.replace(/(\r\n)|(\n)/g,'<br>'); | |||||
if (string!=""){ | |||||
html +="<p><b>[ExitDiagnostics]</b></p>"; | |||||
html +="<p>" +string + "</p>"; | |||||
} | |||||
document.getElementById("info_display").innerHTML=html; | |||||
} | |||||
function debounce(fn,delay){ | |||||
let timer; | |||||
return (...args) => { | |||||
// 判断定时器是否存在,清除定时器 | |||||
if (timer) { | |||||
clearTimeout(timer); | |||||
} | |||||
// 重新调用setTimeout | |||||
timer = setTimeout(() => { | |||||
fn.apply(this, args); | |||||
}, delay); | |||||
}; | |||||
} | |||||
const fn = debounce(logScroll, 500) | |||||
function logScroll(version_name) { | |||||
let container = document.querySelector(`#log_npu`) | |||||
let scrollTop = container.scrollTop | |||||
let scrollHeight = container.scrollHeight | |||||
let clientHeight = container.clientHeight | |||||
let scrollLeft = container.scrollLeft | |||||
if(((parseInt(scrollTop) + clientHeight == scrollHeight || parseInt(scrollTop) + clientHeight +1 == scrollHeight || parseInt(scrollTop) + clientHeight - 1 == scrollHeight)) && parseInt(scrollTop)!==0 && scrollLeft==0){ | |||||
let end_line = $(`#log_npu input[name=end_line]`).val() | |||||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelmanage/${taskID}/modelartlog?version_name=V0001&base_line=${end_line}&lines=50&order=desc`, (data) => { | |||||
if (data.Lines == 0){ | |||||
$(`#log_npu_header`).text('您已翻阅至日志底部') | |||||
$(`#log_npu_message`).css('display', 'block') | |||||
setTimeout(function(){ | |||||
$(`#log_npu_message`).css('display', 'none') | |||||
}, 1000) | |||||
}else{ | |||||
if(end_line===data.EndLine){ | |||||
return | |||||
} | |||||
else{ | |||||
$(`#log_npu input[name=end_line]`).val(data.EndLine) | |||||
$(`#log_npu`).append('<pre>' + data.Content) | |||||
} | |||||
} | |||||
}).fail(function(err) { | |||||
console.log(err); | |||||
}); | |||||
} | |||||
if([0,1,2,3,4,5,6,7,8,9,10].includes(scrollTop) && scrollLeft==0){ | |||||
let start_line = $(`#log_npu input[name=start_line]`).val() | |||||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelmanage/${taskID}/modelartlog?version_name=V0001&base_line=${start_line}&lines=50&order=asc`, (data) => { | |||||
if (data.Lines == 0){ | |||||
$(`#log_npu_header`).text('您已翻阅至日志顶部') | |||||
$(`#log_npu_message`).css('display', 'block') | |||||
setTimeout(function(){ | |||||
$(`#log_npu_message`).css('display', 'none') | |||||
}, 1000) | |||||
}else{ | |||||
$(`#log_npu input[name=start_line]`).val(data.StartLine) //如果变动就改变所对应的值 | |||||
$(`#log_npu`).prepend('<pre>' + data.Content) | |||||
} | |||||
}).fail(function(err) { | |||||
console.log(err); | |||||
}); | |||||
} | |||||
} | |||||
function scrollAnimation(dom, currentY, targetY, currentX) { | |||||
let needScrollTop = targetY - currentY; | |||||
let _currentY = currentY; | |||||
setTimeout(() => { | |||||
// 一次调用滑动帧数,每次调用会不一样 | |||||
//取总距离的十分之一 | |||||
const dist = Math.ceil(needScrollTop / 10); | |||||
_currentY += dist; | |||||
//移动一个十分之一 | |||||
dom.scrollTo(currentX || 0, _currentY,'smooth'); | |||||
// 如果移动幅度小于十个像素,直接移动,否则递归调用,实现动画效果 | |||||
if (needScrollTop > 10 || needScrollTop < -10) { | |||||
scrollAnimation(dom, _currentY, targetY) | |||||
} else { | |||||
dom.scrollTo(0, targetY,'smooth') | |||||
} | |||||
}, 1) | |||||
} | |||||
$('.log_top').click(function(){ | |||||
let logContentDom = document.querySelector(`#log_npu`) | |||||
$(`#log_file_npu`).siblings('pre').remove() | |||||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelmanage/${taskID}/modelartlog?version_name=V0001&base_line=&lines=50&order=asc`, (data) => { | |||||
$(`#log_npu input[name=end_line]`).val(data.EndLine) //如果变动就改变所对应的值 | |||||
$(`#log_npu input[name=start_line]`).val(data.StartLine) | |||||
$(`#log_npu`).prepend('<pre>' + data.Content) | |||||
$(`#log_npu_header`).text('您已翻阅至日志顶部') | |||||
$(`#log_npu_message`).css('display', 'block') | |||||
setTimeout(function(){ | |||||
$(`#log_npu_message`).css('display', 'none') | |||||
}, 1000) | |||||
scrollAnimation(logContentDom, logContentDom.scrollTop, 0); | |||||
}) | |||||
}) | |||||
$('.log_bottom').click(function(e){ | |||||
let logContentDom = document.querySelector(`#log_npu`) | |||||
$(`#log_file_npu`).siblings('pre').remove() | |||||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelmanage/${taskID}/modelartlog?version_name=V0001&base_line=&lines=50&order=desc`, (data) => { | |||||
$(`#log_npu input[name=end_line]`).val(data.EndLine) //如果变动就改变所对应的值 | |||||
$(`#log_npu input[name=start_line]`).val(data.StartLine) | |||||
$(`#log_npu`).append('<pre>' + data.Content) | |||||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelmanage/${taskID}/modelartlog?version_name=V0001&base_line=${data.EndLine}&lines=50&order=desc`, (data) => { | |||||
if (data.Lines == 0){ | |||||
$(`#log_npu_header`).text('您已翻阅至日志底部') | |||||
$(`#log_npu_message`).css('display', 'block') | |||||
setTimeout(function(){ | |||||
$(`#log_npu_message`).css('display', 'none') | |||||
}, 1000) | |||||
}else{ | |||||
if(end_line===data.EndLine){ | |||||
return | |||||
} | |||||
else{ | |||||
$(`#log_npu input[name=end_line]`).val(data.EndLine) | |||||
$(`#log_npu`).append('<pre>' + data.Content) | |||||
} | |||||
} | |||||
}).fail(function(err) { | |||||
console.log(err); | |||||
}); | |||||
scrollAnimation(logContentDom, logContentDom.scrollTop+1, logContentDom.scrollHeight - logContentDom.clientHeight); | |||||
}) | |||||
}) | |||||
</script> |
@@ -1,10 +1,33 @@ | |||||
<!-- 头部导航栏 --> | <!-- 头部导航栏 --> | ||||
{{template "base/head" .}} | {{template "base/head" .}} | ||||
<style> | <style> | ||||
.inline.fields .right.aligned label{ | |||||
width: 100% !important; | |||||
text-align: right; | |||||
} | |||||
.inline .ui.dropdown .text { | .inline .ui.dropdown .text { | ||||
color: rgba(0, 0, 0, .87) !important | color: rgba(0, 0, 0, .87) !important | ||||
} | } | ||||
.newtext{ | |||||
left: 15px !important | |||||
} | |||||
.menuContent{ | |||||
position: absolute; | |||||
background: #ffffff; | |||||
left: 0; | |||||
right: 26px; | |||||
top: 36px; | |||||
z-index:999; | |||||
border: 1px solid #96c8da; | |||||
border-top: 0; | |||||
border-bottom-right-radius: 4px; | |||||
border-bottom-left-radius: 4px; | |||||
box-shadow: 0 2px 3px 0 rgb(34 36 38 / 15%); | |||||
} | |||||
</style> | </style> | ||||
<link rel="stylesheet" href="/self/ztree/css/zTreeStyle/zTreeStyle.css" type="text/css"> | |||||
<!-- 弹窗 --> | <!-- 弹窗 --> | ||||
<div id="mask"> | <div id="mask"> | ||||
<div id="loadingPage"> | <div id="loadingPage"> | ||||
@@ -25,7 +48,12 @@ | |||||
<div class="ui container {{if ne $.MODEL_COUNT 0}}active loader {{end}}" id="loadContainer"> | <div class="ui container {{if ne $.MODEL_COUNT 0}}active loader {{end}}" id="loadContainer"> | ||||
{{template "base/alert" .}} | {{template "base/alert" .}} | ||||
<div class="ui two column stackable grid"> | <div class="ui two column stackable grid"> | ||||
<div class="column"></div> | |||||
<div class="column"> | |||||
<div class="ui blue small menu compact selectcloudbrain"> | |||||
<a class="active item" href="{{.RepoLink}}/modelmanage/show_model">{{$.i18n.Tr "repo.model.list"}}</a> | |||||
<a class="item" href="{{.RepoLink}}/modelmanage/convert_model">{{$.i18n.Tr "repo.model.convert"}}</a> | |||||
</div> | |||||
</div> | |||||
<div class="column right aligned"> | <div class="column right aligned"> | ||||
<!-- --> | <!-- --> | ||||
<a class="ui button {{if .Permission.CanWrite $.UnitTypeModelManage}} green {{else}} disabled {{end}}" | <a class="ui button {{if .Permission.CanWrite $.UnitTypeModelManage}} green {{else}} disabled {{end}}" | ||||
@@ -95,6 +123,7 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div id="newmodel"> | <div id="newmodel"> | ||||
<div class="ui modal second"> | <div class="ui modal second"> | ||||
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);"> | <div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);"> | ||||
@@ -107,20 +136,21 @@ | |||||
<!-- <p>asdasdasd</p> --> | <!-- <p>asdasdasd</p> --> | ||||
</div> | </div> | ||||
<input type="hidden" name="_csrf" value=""> | <input type="hidden" name="_csrf" value=""> | ||||
<div class="two inline fields "> | |||||
<div class="required ten wide field"> | |||||
<label style="margin-left: -23px;">选择训练任务</label> | |||||
<div class="ui dropdown selection search width83 loading" id="choice_model"> | |||||
<div class="inline fields"> | |||||
<div class="required two wide field right aligned"> | |||||
<label for="JobId">选择训练任务</label> | |||||
</div> | |||||
<div class="required thirteen wide inline field"> | |||||
<div class="ui dropdown selection search loading" id="choice_model"> | |||||
<input type="hidden" id="JobId" name="JobId" required> | <input type="hidden" id="JobId" name="JobId" required> | ||||
<div class="default text">选择训练任务</div> | <div class="default text">选择训练任务</div> | ||||
<i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
<div class="menu" id="job-name"> | <div class="menu" id="job-name"> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | |||||
<div class="required six widde field"> | |||||
<label>版本</label> | |||||
<div class="ui dropdown selection search width70" id="choice_version"> | |||||
<label for="VersionName">版本</label> | |||||
<span> </span> | |||||
<div class="ui dropdown selection search" id="choice_version"> | |||||
<input type="hidden" id="VersionName" name="VersionName" required> | <input type="hidden" id="VersionName" name="VersionName" required> | ||||
<div class="default text">选择版本</div> | <div class="default text">选择版本</div> | ||||
<i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
@@ -130,21 +160,30 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="required inline field" id="modelname"> | |||||
<label>模型名称</label> | |||||
<input style="width: 45%;" id="name" name="Name" required maxlength="25" | |||||
onkeyup="this.value=this.value.replace(/[, ]/g,'')"> | |||||
<div class="required inline fields" id="modelname"> | |||||
<div class="two wide field right aligned"> | |||||
<label for="Name">模型名称</label> | |||||
</div> | |||||
<div class="eight wide field"> | |||||
<input id="name" name="Name" required maxlength="25" onkeyup="this.value=this.value.replace(/[, ]/g,'')"> | |||||
</div> | |||||
</div> | </div> | ||||
<div class="required inline field" id="verionname"> | |||||
<label>模型版本</label> | |||||
<input style="width: 45%;" id="version" name="Version" value="" readonly required maxlength="255"> | |||||
<div class="required inline fields" id="verionname"> | |||||
<div class="two wide field right aligned"> | |||||
<label for="Version">模型版本</label> | |||||
</div> | |||||
<div class="eight wide field"> | |||||
<input id="version" name="Version" value="" readonly required maxlength="255"> | |||||
</div> | |||||
</div> | </div> | ||||
<div class="unite min_title inline field required"> | |||||
<label>模型框架</label> | |||||
<div class="ui dropdown selection search width70" id="choice_Engine"> | |||||
<div class="unite min_title inline fields required"> | |||||
<div class="two wide field right aligned"> | |||||
<label for="Engine">模型框架</label> | |||||
</div> | |||||
<div class="ui ten wide field dropdown selection search" id="choice_Engine"> | |||||
<input type="hidden" id="Engine" name="Engine" required> | <input type="hidden" id="Engine" name="Engine" required> | ||||
<div class="default text">选择模型框架</div> | |||||
<div class="default text newtext">选择模型框架</div> | |||||
<i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
<div class="menu" id="job-Engine"> | <div class="menu" id="job-Engine"> | ||||
@@ -152,28 +191,48 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="inline field"> | |||||
<label>模型标签</label> | |||||
<input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255" | |||||
placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'> | |||||
<div class="unite min_title inline fields required"> | |||||
<div class="two wide field right aligned"> | |||||
<label for="modelSelectedFile">模型文件</label> | |||||
</div> | |||||
<div class="thirteen wide field" style="position:relative"> | |||||
<input id="modelSelectedFile" type="text" readonly required onclick="showMenu();" name="modelSelectedFile" > | |||||
<div id="menuContent" class="menuContent" style="display:none;"> | |||||
<ul id="treeDemo" class="ztree"></ul> | |||||
</div> | |||||
</div> | |||||
</div> | </div> | ||||
<div class="inline field"> | |||||
<label for="description">模型描述</label> | |||||
<textarea style="width: 83%;margin-left: 7px;" id="Description" name="Description" rows="3" | |||||
maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}' | |||||
onchange="this.value=this.value.substring(0, 255)" | |||||
onkeydown="this.value=this.value.substring(0, 255)" | |||||
onkeyup="this.value=this.value.substring(0, 256)"></textarea> | |||||
<div class="inline fields"> | |||||
<div class="two wide field right aligned"> | |||||
<label for="Label">模型标签  </label> | |||||
</div> | |||||
<div class="thirteen wide field"> | |||||
<input id="label" name="Label" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'> | |||||
</div> | |||||
</div> | |||||
<div class="inline fields"> | |||||
<div class="two wide field right aligned"> | |||||
<label for="description">模型描述  </label> | |||||
</div> | |||||
<div class="thirteen wide field"> | |||||
<textarea id="Description" name="Description" rows="3" | |||||
maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}' | |||||
onchange="this.value=this.value.substring(0, 255)" | |||||
onkeydown="this.value=this.value.substring(0, 255)" | |||||
onkeyup="this.value=this.value.substring(0, 256)"></textarea> | |||||
</div> | |||||
</div> | </div> | ||||
<div class="inline field" style="margin-left: 75px;"> | |||||
<div class="inline field" style="margin-left: 105px;"> | |||||
<button id="submitId" type="button" class="ui create_train_job green button" | <button id="submitId" type="button" class="ui create_train_job green button" | ||||
style="position: absolute;"> | style="position: absolute;"> | ||||
{{.i18n.Tr "repo.model.manage.sava_model"}} | {{.i18n.Tr "repo.model.manage.sava_model"}} | ||||
</button> | </button> | ||||
</div> | </div> | ||||
</form> | </form> | ||||
<div class="actions" style="display: inline-block;margin-left: 180px;"> | |||||
<div class="actions" style="display: inline-block;margin-left: 220px;"> | |||||
<button class="ui button cancel">{{.i18n.Tr "repo.cloudbrain.cancel"}}</button> | <button class="ui button cancel">{{.i18n.Tr "repo.cloudbrain.cancel"}}</button> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -181,10 +240,79 @@ | |||||
</div> | </div> | ||||
{{template "base/footer" .}} | {{template "base/footer" .}} | ||||
<script> | |||||
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.core.js"></script> | |||||
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.excheck.js"></script> | |||||
<script type="text/javascript"> | |||||
var setting = { | |||||
check: { | |||||
enable: true, | |||||
chkboxType: {"Y":"ps", "N":"ps"} | |||||
}, | |||||
view: { | |||||
dblClickExpand: false | |||||
}, | |||||
callback: { | |||||
beforeClick: beforeClick, | |||||
onCheck: onCheck | |||||
} | |||||
}; | |||||
function beforeClick(treeId, treeNode) { | |||||
var zTree = $.fn.zTree.getZTreeObj("treeDemo"); | |||||
zTree.checkNode(treeNode, !treeNode.checked, null, true); | |||||
return false; | |||||
} | |||||
function onCheck(e, treeId, treeNode) { | |||||
var zTree = $.fn.zTree.getZTreeObj("treeDemo"), | |||||
nodes = zTree.getCheckedNodes(true), | |||||
v = ""; | |||||
for (var i=0, l=nodes.length; i<l; i++) { | |||||
if(nodes[i].isParent){ | |||||
continue; | |||||
} | |||||
var pathNodes = nodes[i].getPath(); | |||||
var path =""; | |||||
for(var j=0;j<pathNodes.length;j++){ | |||||
if(j ==0){ | |||||
path += pathNodes[j].name; | |||||
}else{ | |||||
path += "/" + pathNodes[j].name; | |||||
} | |||||
} | |||||
v += path + ";"; | |||||
} | |||||
if (v.length > 0 ) v = v.substring(0, v.length-1); | |||||
var cityObj = $("#modelSelectedFile"); | |||||
cityObj.attr("value", v); | |||||
} | |||||
function showMenu() { | |||||
var cityObj = $("#modelSelectedFile"); | |||||
var cityOffset = $("#modelSelectedFile").offset(); | |||||
// $("#menuContent").css({left:cityOffset.left + "px", top:cityOffset.top + cityObj.outerHeight() + "px"}).slideDown("fast"); | |||||
$("#menuContent").slideDown("fast"); | |||||
$("body").bind("mousedown", onBodyDown); | |||||
} | |||||
function hideMenu() { | |||||
$("#menuContent").fadeOut("fast"); | |||||
$("body").unbind("mousedown", onBodyDown); | |||||
} | |||||
function onBodyDown(event) { | |||||
if (!(event.target.id == "menuBtn" || event.target.id == "modelSelectedFile" || event.target.id == "menuContent" || $(event.target).parents("#menuContent").length>0)) { | |||||
hideMenu(); | |||||
} | |||||
} | |||||
$(document).ready(function(){ | |||||
//$.fn.zTree.init($("#treeDemo"), setting, zNodes); | |||||
}); | |||||
let repolink = {{.RepoLink }} | let repolink = {{.RepoLink }} | ||||
let repoId = {{ $repository }} | let repoId = {{ $repository }} | ||||
const { _AppSubUrl, _StaticUrlPrefix, csrf } = window.config; | const { _AppSubUrl, _StaticUrlPrefix, csrf } = window.config; | ||||
@@ -207,9 +335,10 @@ | |||||
$("#job-name").empty() | $("#job-name").empty() | ||||
createModelName() | createModelName() | ||||
loadTrainList() | loadTrainList() | ||||
}, | }, | ||||
onHide: function () { | onHide: function () { | ||||
var cityObj = $("#modelSelectedFile"); | |||||
cityObj.attr("value", ""); | |||||
document.getElementById("formId").reset(); | document.getElementById("formId").reset(); | ||||
$('#choice_model').dropdown('clear') | $('#choice_model').dropdown('clear') | ||||
$('#choice_version').dropdown('clear') | $('#choice_version').dropdown('clear') | ||||
@@ -226,7 +355,7 @@ | |||||
$(function () { | $(function () { | ||||
$('#choice_model').dropdown({ | $('#choice_model').dropdown({ | ||||
onChange: function (value) { | onChange: function (value) { | ||||
$(".ui.dropdown.selection.search.width70").addClass("loading") | |||||
$("#choice_version").addClass("loading") | |||||
$('#choice_version').dropdown('clear') | $('#choice_version').dropdown('clear') | ||||
$("#job-version").empty() | $("#job-version").empty() | ||||
loadTrainVersion(value) | loadTrainVersion(value) | ||||
@@ -240,6 +369,7 @@ | |||||
for (var i = 0; i < modelData.length; i++) { | for (var i = 0; i < modelData.length; i++) { | ||||
if (modelData[i].VersionName == value) { | if (modelData[i].VersionName == value) { | ||||
setEngine(modelData[i]) | setEngine(modelData[i]) | ||||
loadModelFile(modelData[i]) | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
@@ -273,12 +403,12 @@ | |||||
train_html += '</div>' | train_html += '</div>' | ||||
} | } | ||||
$("#job-name").append(train_html) | $("#job-name").append(train_html) | ||||
$(".ui.dropdown.selection.search.width83").removeClass("loading") | |||||
$("#choice_model").removeClass("loading") | |||||
$('#choice_model .default.text').text(data[0].DisplayJobName) | $('#choice_model .default.text').text(data[0].DisplayJobName) | ||||
$('#choice_model input[name="JobId"]').val(data[0].JobID) | $('#choice_model input[name="JobId"]').val(data[0].JobID) | ||||
loadTrainVersion() | loadTrainVersion() | ||||
}else{ | }else{ | ||||
$(".ui.dropdown.selection.search.width83").removeClass("loading") | |||||
$("#choice_model").removeClass("loading") | |||||
} | } | ||||
}) | }) | ||||
} | } | ||||
@@ -294,7 +424,7 @@ | |||||
} | } | ||||
if (data.length) { | if (data.length) { | ||||
$("#job-version").append(train_html) | $("#job-version").append(train_html) | ||||
$(".ui.dropdown.selection.search.width70").removeClass("loading") | |||||
$("#choice_version").removeClass("loading") | |||||
var versionName = data[0].VersionName; | var versionName = data[0].VersionName; | ||||
if (versionName == null || versionName == "") { | if (versionName == null || versionName == "") { | ||||
versionName = "V0001"; | versionName = "V0001"; | ||||
@@ -302,47 +432,112 @@ | |||||
$('#choice_version .default.text').text(versionName) | $('#choice_version .default.text').text(versionName) | ||||
$('#choice_version input[name="VersionName"]').val(versionName) | $('#choice_version input[name="VersionName"]').val(versionName) | ||||
setEngine(data[0]) | setEngine(data[0]) | ||||
loadModelFile(data[0]) | |||||
} | } | ||||
}) | }) | ||||
} | } | ||||
function loadModelFile(trainJob){ | |||||
console.log("trainJob=" + trainJob); | |||||
$('#choice_file').dropdown('clear') | |||||
$("#model-file").empty() | |||||
if(trainJob ==null || trainJob ==""){ | |||||
console.log("trainJob is null"); | |||||
}else{ | |||||
let type = trainJob.Type; | |||||
if(type == 2){ | |||||
if(trainJob.ComputeResource=="NPU"){ | |||||
type=1; | |||||
}else{ | |||||
type=0; | |||||
} | |||||
} | |||||
$.get(`${repolink}/modelmanage/query_train_model?jobName=${trainJob.JobName}&type=${type}&VersionName=${trainJob.VersionName}`, (data) => { | |||||
const n_length = data.length | |||||
let file_html='' | |||||
let firstFileName ='' | |||||
var zNodes=[]; | |||||
var nodesMap={}; | |||||
for (let i=0;i<n_length;i++){ | |||||
parentNodeMap = nodesMap; | |||||
var fileSplits = data[i].FileName.split("/"); | |||||
for(let j=0;j < fileSplits.length;j++){ | |||||
if(fileSplits[j] == ""){ | |||||
break; | |||||
} | |||||
if(parentNodeMap[fileSplits[j]] == null){ | |||||
parentNodeMap[fileSplits[j]] = {}; | |||||
} | |||||
parentNodeMap = parentNodeMap[fileSplits[j]] | |||||
} | |||||
} | |||||
convertToNode(zNodes,nodesMap); | |||||
$.fn.zTree.init($("#treeDemo"), setting, zNodes); | |||||
}) | |||||
} | |||||
} | |||||
function convertToNode(nodeList,nodesMap){ | |||||
var keyList = Object.keys(nodesMap); | |||||
keyList.sort(function(a,b){ | |||||
return a-b; | |||||
}); | |||||
var isFirst = true; | |||||
for(var i=0; i<keyList.length;i++){ | |||||
var node = {}; | |||||
node["name"] = keyList[i]; | |||||
nodeList.push(node); | |||||
if(nodesMap[keyList[i]] != null && Object.keys(nodesMap[keyList[i]]).length >0){ | |||||
node["children"]=[]; | |||||
if(isFirst){ | |||||
node["open"] = true; | |||||
isFirst= false; | |||||
} | |||||
convertToNode(node["children"],nodesMap[keyList[i]]); | |||||
} | |||||
} | |||||
} | |||||
function setEngine(modelVersion) { | function setEngine(modelVersion) { | ||||
console.log("modelVersion=" + modelVersion); | console.log("modelVersion=" + modelVersion); | ||||
$('#choice_Engine').dropdown('clear') | $('#choice_Engine').dropdown('clear') | ||||
$("#job-Engine").empty() | $("#job-Engine").empty() | ||||
if (modelVersion.EngineName != null && modelVersion.EngineName != "") { | if (modelVersion.EngineName != null && modelVersion.EngineName != "") { | ||||
srcEngine = modelVersion.EngineName.split('-')[0] | srcEngine = modelVersion.EngineName.split('-')[0] | ||||
srcEngine = srcEngine.trim(); | |||||
let selectedText = "Pytorch"; | |||||
srcEngine = srcEngine.trim().toLowerCase(); | |||||
let selectedText = "PyTorch"; | |||||
let selectedValue = 0; | let selectedValue = 0; | ||||
let itemHtml = "<option class=\"item\" data-value=\"0\">Pytorch</option>"; | |||||
if (srcEngine == 'TensorFlow') { | |||||
let itemHtml = "<option class=\"item\" data-value=\"0\">PyTorch</option>"; | |||||
if (srcEngine == 'tensorflow') { | |||||
selectedText = "TensorFlow"; | selectedText = "TensorFlow"; | ||||
selectedValue = 1; | selectedValue = 1; | ||||
itemHtml += "<option class=\"active item\" data-value=\"1\">TensorFlow</option>"; | itemHtml += "<option class=\"active item\" data-value=\"1\">TensorFlow</option>"; | ||||
} else { | } else { | ||||
itemHtml += "<option class=\"item\" data-value=\"1\">TensorFlow</option>"; | itemHtml += "<option class=\"item\" data-value=\"1\">TensorFlow</option>"; | ||||
} | } | ||||
if (srcEngine == 'MindSpore') { | |||||
if (srcEngine == 'mindspore') { | |||||
selectedText = "MindSpore"; | selectedText = "MindSpore"; | ||||
selectedValue = 2; | selectedValue = 2; | ||||
itemHtml += "<option class=\"active item\" data-value=\"2\">MindSpore</option>"; | itemHtml += "<option class=\"active item\" data-value=\"2\">MindSpore</option>"; | ||||
} else { | } else { | ||||
itemHtml += "<option class=\"item\" data-value=\"2\">MindSpore</option>"; | itemHtml += "<option class=\"item\" data-value=\"2\">MindSpore</option>"; | ||||
} | } | ||||
itemHtml += "<option class=\"item\" data-value=\"4\">PaddlePaddle</option>" | |||||
itemHtml += "<option class=\"item\" data-value=\"5\">OneFlow</option>" | |||||
itemHtml += "<option class=\"item\" data-value=\"6\">MXNet</option>" | |||||
itemHtml += "<option class=\"item\" data-value=\"3\">Other</option>" | itemHtml += "<option class=\"item\" data-value=\"3\">Other</option>" | ||||
$('#choice_Engine .default.text').text(selectedText) | $('#choice_Engine .default.text').text(selectedText) | ||||
$('#choice_Engine input[name="Engine"]').val(selectedValue) | $('#choice_Engine input[name="Engine"]').val(selectedValue) | ||||
$("#job-Engine").append(itemHtml); | $("#job-Engine").append(itemHtml); | ||||
$("#choice_Engine").addClass('disabled') | |||||
$("#choice_Engine").removeClass('disabled'); | |||||
} else { | } else { | ||||
let itemHtml = "<option class=\"active item\" data-value=\"0\">Pytorch</option>"; | |||||
let itemHtml = "<option class=\"active item\" data-value=\"0\">PyTorch</option>"; | |||||
itemHtml += "<option class=\"item\" data-value=\"1\">TensorFlow</option>" | itemHtml += "<option class=\"item\" data-value=\"1\">TensorFlow</option>" | ||||
itemHtml += "<option class=\"item\" data-value=\"2\">MindSpore</option>" | itemHtml += "<option class=\"item\" data-value=\"2\">MindSpore</option>" | ||||
itemHtml += "<option class=\"item\" data-value=\"4\">PaddlePaddle</option>" | |||||
itemHtml += "<option class=\"item\" data-value=\"5\">OneFlow</option>" | |||||
itemHtml += "<option class=\"item\" data-value=\"6\">MXNet</option>" | |||||
itemHtml += "<option class=\"item\" data-value=\"3\">Other</option>" | itemHtml += "<option class=\"item\" data-value=\"3\">Other</option>" | ||||
$('#choice_Engine .default.text').text("Pytorch"); | |||||
$('#choice_Engine .default.text').text("PyTorch"); | |||||
$('#choice_Engine input[name="Engine"]').val(0) | $('#choice_Engine input[name="Engine"]').val(0) | ||||
$("#job-Engine").append(itemHtml); | $("#job-Engine").append(itemHtml); | ||||
$("#choice_Engine").removeClass('disabled'); | $("#choice_Engine").removeClass('disabled'); | ||||
@@ -234,12 +234,21 @@ function loadInfo(){ | |||||
} | } | ||||
function getEngineName(model){ | function getEngineName(model){ | ||||
if(model.Engine == 0){ | if(model.Engine == 0){ | ||||
return "Pytorch"; | |||||
return "PyTorch"; | |||||
}else if(model.Engine == 1 || model.Engine == 121){ | }else if(model.Engine == 1 || model.Engine == 121){ | ||||
return "TensorFlow"; | return "TensorFlow"; | ||||
}else if(model.Engine == 2 || model.Engine == 122){ | |||||
}else if(model.Engine == 2 || model.Engine == 122 || model.Engine == 35){ | |||||
return "MindSpore"; | return "MindSpore"; | ||||
}else{ | |||||
}else if(model.Engine == 3){ | |||||
return "Other"; | |||||
}else if(model.Engine == 4){ | |||||
return "PaddlePaddle"; | |||||
}else if(model.Engine == 5){ | |||||
return "OneFlow"; | |||||
}else if(model.Engine == 6){ | |||||
return "MXNet"; | |||||
} | |||||
else{ | |||||
return "Other" | return "Other" | ||||
} | } | ||||
} | } | ||||
@@ -65,7 +65,7 @@ | |||||
min-width="8.5%" | min-width="8.5%" | ||||
> | > | ||||
<template slot-scope="scope"> | <template slot-scope="scope"> | ||||
<span class="text-over">{{ scope.row.EngineName}}</span> | |||||
<span class="text-over" :title="scope.row.EngineName">{{ scope.row.EngineName}}</span> | |||||
</template> | </template> | ||||
</el-table-column> | </el-table-column> | ||||
<el-table-column | <el-table-column | ||||
@@ -203,6 +203,7 @@ export default { | |||||
$('#model_header').text("创建模型新版本") | $('#model_header').text("创建模型新版本") | ||||
$('input[name="Name"]').addClass('model_disabled') | $('input[name="Name"]').addClass('model_disabled') | ||||
$('input[name="Name"]').attr('readonly','readonly') | $('input[name="Name"]').attr('readonly','readonly') | ||||
$('input[name="modelSelectedFile"]').attr('readonly','readonly') | |||||
$('input[name="Version"]').addClass('model_disabled') | $('input[name="Version"]').addClass('model_disabled') | ||||
$('.ui.dimmer').css({"background-color":"rgb(136, 136, 136,0.7)"}) | $('.ui.dimmer').css({"background-color":"rgb(136, 136, 136,0.7)"}) | ||||
$("#job-name").empty() | $("#job-name").empty() | ||||
@@ -216,6 +217,9 @@ export default { | |||||
document.getElementById("formId").reset(); | document.getElementById("formId").reset(); | ||||
$('input[name="Name"]').removeClass('model_disabled') | $('input[name="Name"]').removeClass('model_disabled') | ||||
$('input[name="Name"]').removeAttr('readonly') | $('input[name="Name"]').removeAttr('readonly') | ||||
$('input[name="modelSelectedFile"]').removeAttr('readonly') | |||||
var cityObj = $("#modelSelectedFile"); | |||||
cityObj.attr("value", ""); | |||||
$('#choice_model').dropdown('clear') | $('#choice_model').dropdown('clear') | ||||
$('#choice_version').dropdown('clear') | $('#choice_version').dropdown('clear') | ||||
$('#choice_Engine').dropdown('clear') | $('#choice_Engine').dropdown('clear') | ||||
@@ -231,18 +235,26 @@ export default { | |||||
let versionname = document.getElementById("VersionName").value | let versionname = document.getElementById("VersionName").value | ||||
let name= document.getElementById("name").value | let name= document.getElementById("name").value | ||||
let version= document.getElementById("version").value | let version= document.getElementById("version").value | ||||
let modelSelectedFile = document.getElementById("modelSelectedFile").value | |||||
if(jobid==""){ | if(jobid==""){ | ||||
$(".required.ten.wide.field").addClass("error") | $(".required.ten.wide.field").addClass("error") | ||||
return false | return false | ||||
}else{ | }else{ | ||||
$(".required.ten.wide.field").removeClass("error") | $(".required.ten.wide.field").removeClass("error") | ||||
} | } | ||||
if(modelSelectedFile==""){ | |||||
$("#modelSelectedFile").addClass("error") | |||||
return false | |||||
}else{ | |||||
$("#modelSelectedFile").removeClass("error") | |||||
} | |||||
if(versionname==""){ | if(versionname==""){ | ||||
$(".required.six.widde.field").addClass("error") | $(".required.six.widde.field").addClass("error") | ||||
return false | return false | ||||
}else{ | }else{ | ||||
$(".required.six.widde.field").removeClass("error") | $(".required.six.widde.field").removeClass("error") | ||||
} | } | ||||
if(name==""){ | if(name==""){ | ||||
$("#modelname").addClass("error") | $("#modelname").addClass("error") | ||||
return false | return false | ||||
@@ -273,8 +285,8 @@ export default { | |||||
type:'POST', | type:'POST', | ||||
data:data, | data:data, | ||||
success:function(res){ | success:function(res){ | ||||
// context.loadrefresh1(row) | |||||
context.getModelList() | context.getModelList() | ||||
$("input[name='modelSelectedFile']").val("") | |||||
$('.ui.modal.second').modal('hide') | $('.ui.modal.second').modal('hide') | ||||
if(initModel==='0'){ | if(initModel==='0'){ | ||||
location.reload() | location.reload() | ||||
@@ -350,15 +362,21 @@ export default { | |||||
}, | }, | ||||
getEngineName(model){ | getEngineName(model){ | ||||
if(model.Engine == 0){ | if(model.Engine == 0){ | ||||
return "Pytorch"; | |||||
return "PyTorch"; | |||||
}else if(model.Engine == 1 || model.Engine == 121){ | }else if(model.Engine == 1 || model.Engine == 121){ | ||||
return "TensorFlow"; | return "TensorFlow"; | ||||
}else if(model.Engine == 2 || model.Engine == 122 || model.Engine == 35){ | }else if(model.Engine == 2 || model.Engine == 122 || model.Engine == 35){ | ||||
return "MindSpore"; | return "MindSpore"; | ||||
}else{ | |||||
}else if(model.Engine == 4){ | |||||
return "PaddlePaddle"; | |||||
}else if(model.Engine == 5){ | |||||
return "OneFlow"; | |||||
}else if(model.Engine == 6){ | |||||
return "MXNet"; | |||||
} | |||||
else{ | |||||
return "Other" | return "Other" | ||||
} | } | ||||
}, | }, | ||||
getModelList(){ | getModelList(){ | ||||
try { | try { | ||||
@@ -226,11 +226,8 @@ | |||||
width="120px" | width="120px" | ||||
align="center"> | align="center"> | ||||
</el-table-column> | </el-table-column> | ||||
<el-table-column | |||||
prop="Phone" | |||||
label="手机" | |||||
width="120px" | |||||
align="center"> | |||||
<el-table-column prop="Phone" label="是否手机验证" width="120px" align="center"> | |||||
<template slot-scope="scope"> {{scope.row.Phone ? '是' : '否'}} </template> | |||||
</el-table-column> | </el-table-column> | ||||
<el-table-column | <el-table-column | ||||
prop="RegistDate" | prop="RegistDate" | ||||