diff --git a/custom/public/rotation3D/rotation3D.css b/custom/public/rotation3D/rotation3D.css index 032096b48..4fd12283c 100755 --- a/custom/public/rotation3D/rotation3D.css +++ b/custom/public/rotation3D/rotation3D.css @@ -29,51 +29,22 @@ } .rotation3D__item .scale{ position: absolute; top: 0; width: 100%; height: 100%; } .rotation3D__item .cont{ position: relative; z-index: 2; } -.rotation3D__item .cont .iconfont { font-size: 28px; margin-top: 30px; margin-bottom: 96px; display: block; } +.rotation3D__item .cont .iconfont { font-size: 28px; margin-top: 30px; margin-bottom: 96px; display: block; height: 35px;} .rotation3D__item .cont p{ color: #101010; } -.itemList .rotation3D__item .cont p::after{ - font-size: 12px; - content: ''; - position: absolute; - left: 0; - right: 0; - margin-top: 60px; - color: #101010; -} -.itemList .rotation3D__item:nth-child(1) .cont p::after{ - content: "鹏城云脑一号"; -} -.itemList .rotation3D__item:nth-child(2) .cont p::after{ - content: "鹏城云脑二号"; -} -.itemList .rotation3D__item:nth-child(3) .cont p::after{ - content: "北大人工智能集群系统"; -} -.itemList .rotation3D__item:nth-child(4) .cont p::after{ - content: "合肥类脑智能开放平台"; +.lineList .rotation3D__line:nth-child(5n+0) .dot{ } -.itemList .rotation3D__item:nth-child(5) .cont p::after{ - content: "武汉人工智能计算中心"; +.lineList .rotation3D__line:nth-child(5n+1) .dot{ + animation-delay: 1s; } -.itemList .rotation3D__item:nth-child(6) .cont p::after{ - content: "西安未来人工智能计算中心"; +.lineList .rotation3D__line:nth-child(5n+2) .dot{ + animation-delay: 3s; } -.itemList .rotation3D__item:nth-child(7) .cont p::after{ - content: "更多接入中…"; +.lineList .rotation3D__line:nth-child(5n+3) .dot{ + animation-delay: 2s; } -.itemList .rotation3D__item:nth-child(8) .cont p::after{ - content: "中原人工智能计算中心"; +.lineList .rotation3D__line:nth-child(5n+3) .dot{ + animation-delay: 4s; } -.itemList .rotation3D__item:nth-child(9) .cont p::after{ - content: "成都人工智能计算中心"; -} -.itemList .rotation3D__item:nth-child(10) .cont p::after{ - content: "横琴先进智能计算中心"; -} -.itemList .rotation3D__item:nth-child(11) .cont p::after{ - content: "国家超级计算济南中心"; -} - .rotation3D__item.blue{ color: #01e9fc; } .rotation3D__item.green{ color: #b4b3ca; } .rotation3D__item.yellow{ color: #ffd200; } @@ -90,14 +61,17 @@ ---------------------------*/ .rotation3D__line{ position: absolute; left: 50%; top: 50%; - display: block; width: 1px; height: 50%; + display: block; + width: 30px; + height: 50%; padding-top: 60px; color: #fff; font-size: 50px; /*background: #fff;*/ /*原点设置在中间*/ transform-origin: 50% 0; transform-style: preserve-3d; -} -.rotation3D__line .pos{ position: absolute; top: 0; } + overflow: hidden; + } +.rotation3D__line .pos{ position: absolute; top: 0; left: 15px;} .rotation3D__line svg { position: absolute; top: 0; } .rotation3D__line svg path { stroke: #fff; fill: none; @@ -139,8 +113,10 @@ position: absolute; font-size: 12px; color: #888; - transform: rotate(180deg)scale(0.80); -} + transform:scale(0.80); + transform-origin:left; + white-space: nowrap; + } /*颜色*/ .rotation3D__line.blue { color: #07b2f9; } diff --git a/go.mod b/go.mod index c1e959f8e..387a34520 100755 --- a/go.mod +++ b/go.mod @@ -22,14 +22,21 @@ require ( github.com/PuerkitoBio/goquery v1.5.0 github.com/RichardKnop/machinery v1.6.9 github.com/RoaringBitmap/roaring v0.4.23 // indirect + github.com/alibabacloud-go/darabonba-openapi v0.1.18 + github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.9 + github.com/alibabacloud-go/tea v1.1.17 + github.com/alibabacloud-go/tea-utils v1.4.3 + github.com/alibabacloud-go/tea-xml v1.1.2 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect github.com/blevesearch/bleve v1.0.7 + github.com/clbanning/mxj/v2 v2.5.5 // indirect github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2 // indirect github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc github.com/dgrijalva/jwt-go v3.2.0+incompatible + github.com/disintegration/imaging v1.6.2 github.com/dustin/go-humanize v1.0.0 github.com/editorconfig/editorconfig-core-go/v2 v2.1.1 github.com/elliotchance/orderedmap v1.4.0 @@ -56,6 +63,7 @@ require ( github.com/golang/protobuf v1.4.1 // indirect github.com/gomodule/redigo v2.0.0+incompatible github.com/google/go-github/v24 v24.0.1 + github.com/google/uuid v1.1.1 github.com/gorilla/context v1.1.1 github.com/gorilla/websocket v1.4.0 github.com/hashicorp/go-retryablehttp v0.6.6 // indirect @@ -112,9 +120,9 @@ require ( github.com/urfave/cli v1.22.1 github.com/xanzy/go-gitlab v0.31.0 github.com/yohcop/openid-go v1.0.0 - github.com/yuin/goldmark v1.1.27 + github.com/yuin/goldmark v1.1.30 github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 - golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 + golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 golang.org/x/mod v0.3.0 // indirect golang.org/x/net v0.0.0-20200513185701-a91f0712d120 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d @@ -126,7 +134,7 @@ require ( gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df - gopkg.in/ini.v1 v1.52.0 + gopkg.in/ini.v1 v1.56.0 gopkg.in/ldap.v3 v3.0.2 gopkg.in/macaron.v1 v1.3.9 // indirect gopkg.in/testfixtures.v2 v2.5.0 diff --git a/go.sum b/go.sum index d9dc14b64..d55d7af48 100755 --- a/go.sum +++ b/go.sum @@ -78,6 +78,35 @@ github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBb github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.2/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= +github.com/alibabacloud-go/darabonba-openapi v0.1.14/go.mod h1:w4CosR7O/kapCtEEMBm3JsQqWBU/CnZ2o0pHorsTWDI= +github.com/alibabacloud-go/darabonba-openapi v0.1.18 h1:3eUVmAr7WCJp7fgIvmCd9ZUyuwtJYbtUqJIed5eXCmk= +github.com/alibabacloud-go/darabonba-openapi v0.1.18/go.mod h1:PB4HffMhJVmAgNKNq3wYbTUlFvPgxJpTzd1F5pTuUsc= +github.com/alibabacloud-go/darabonba-string v1.0.0/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA= +github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 h1:NqugFkGxx1TXSh/pBcU00Y6bljgDPaFdh5MUSeJ7e50= +github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY= +github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.9 h1:z+OU7LbWtQitWJ8SAn55hEQkJPCsEPJc97TvGCZV+4s= +github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.9/go.mod h1:AT91gCNJPsemf4lHLNgWTf/RsgmpdOprWvQ3FYvtwGk= +github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q= +github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= +github.com/alibabacloud-go/openapi-util v0.0.10/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/openapi-util v0.0.11 h1:iYnqOPR5hyEEnNZmebGyRMkkEJRWUEjDiiaOHZ5aNhA= +github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg= +github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.17 h1:05R5DnaJXe9sCNIe8KUgWHC/z6w/VZIwczgUwzRnul8= +github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= +github.com/alibabacloud-go/tea-utils v1.4.3 h1:8SzwmmRrOnQ09Hf5a9GyfJc0d7Sjv6fmsZoF4UDbFjo= +github.com/alibabacloud-go/tea-utils v1.4.3/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw= +github.com/alibabacloud-go/tea-xml v1.1.2 h1:oLxa7JUXm2EDFzMg+7oRsYc+kutgCVwm+bZlhhmvW5M= +github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= +github.com/aliyun/credentials-go v1.1.2 h1:qU1vwGIBb3UJ8BwunHDRFtAhS6jnQLnde/yk0+Ih2GY= +github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o= github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= @@ -125,6 +154,8 @@ github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU= github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE= +github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= +github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/corbym/gocrest v1.0.3 h1:gwEdq6RkTmq+09CTuM29DfKOCtZ7G7bcyxs3IZ6EVdU= github.com/corbym/gocrest v1.0.3/go.mod h1:maVFL5lbdS2PgfOQgGRWDYTeunSWQeiEgoNdTABShCs= @@ -170,6 +201,8 @@ github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xb github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= +github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= @@ -369,6 +402,7 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORR github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw= github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= @@ -432,6 +466,8 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= @@ -673,11 +709,13 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= @@ -707,6 +745,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM= @@ -722,6 +761,8 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ= github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM= +github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/toqueteos/trie v1.0.0 h1:8i6pXxNUXNRAqP246iibb7w/pSFquNTQ+uNfriG7vlk= github.com/toqueteos/trie v1.0.0/go.mod h1:Ywk48QhEqhU1+DwhMkJ2x7eeGxDHiGkAdc9+0DYcbsM= @@ -761,6 +802,8 @@ github.com/yuin/goldmark v1.1.7/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27 h1:nqDD4MMMQA0lmWq03Z2/myGPYLQoXtmi0rGVs95ntbo= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.30 h1:j4d4Lw3zqZelDhBksEo3BnWg9xhXRQGJPPSL6OApZjI= +github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 h1:gZucqLjL1eDzVWrXj4uiWeMbAopJlBR2mKQAsTGdPwo= github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60/go.mod h1:i9VhcIHN2PxXMbQrKqXNueok6QNONoPjNMoj9MygVL0= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= @@ -800,14 +843,19 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190907121410-71b5226ff739/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88= golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a h1:gHevYm0pO4QUbwy8Dmdr01R5r1BuKtfYqRqF0h/Cbh0= golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -848,6 +896,7 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -868,6 +917,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -933,6 +984,7 @@ golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200225230052-807dcd883420/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 h1:vmsb6v0zUdmUlXfwKaYrHPPRCV0lHq/IwNIf0ASGjyQ= golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1012,6 +1064,8 @@ gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg= gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4= gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.56.0 h1:DPMeDvGTM54DXbPkVIZsp19fp/I2K7zwA/itHYHKo8Y= +gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ldap.v3 v3.0.2 h1:R6RBtabK6e1GO0eQKtkyOFbAHO73QesLzI2w2DZ6b9w= gopkg.in/ldap.v3 v3.0.2/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= gopkg.in/macaron.v1 v1.3.9 h1:Dw+DDRYdXgQyEsPlfAfKz+UA5qVUrH3KPD7JhmZ9MFc= diff --git a/index.html b/index.html new file mode 100644 index 000000000..643c31b06 --- /dev/null +++ b/index.html @@ -0,0 +1,688 @@ + + + + + + + OpenI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+ + +
+ + + + + + +
+
+
+

+ Explore Better AI +
+ OpenI AI Development Cooperation Platform +
+

+

The one-stop collaborative development environment for AI field provides AI development pipeline integrating code development, data management, model debugging, reasoning and evaluation

+ + + Use Now + +
+
+
+

* Only show the dynamics of open source projects

+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+
+
+

Recommended Organizations

+

These excellent organizations are using the OpenI AI Collaboration Platform for collaborative development of projects. To show your organization here, Click here to submit.

+ More Organizations +
+
+
+
+ +
+
+ +
+
+ +
+

Community Activities

+

The community has prepared a wealth of activities, waiting for you to participate!

+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+
+
+
+

Recommended Projects

+

Excellent AI projects recommendation. To show your project here, Click here to submit.Click here to explore more projects.

+
+ +
+
+ +
+
+
+ +
+ +
+
+
+

智算网络

+

人工智能算力网络推进联盟已接入10家智算中心,算力总规模1542P

+
+ +
+ + +
+ +
+ + +
+
+
+
+
+ +

+
+
+
+
+
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+
+
+
+
+
+
+ + +
+ +
+

Collaborative Development Environment

+

Provide a collaborative development environment for AI development, which is the biggest highlight that distinguishes the OpenI AI Collaboration Platform from other traditional Git platforms.

+
+
+
+
+ +
+
+

Unified Management of Development Elements

+
+ The platform provides four elements of AI development: unified management of model code, data set, model and execution environment. +
+
+
+
+
+ +
+
+

Data Collaboration and Sharing

+
+ By uploading data sets in the project, many project members cooperate to complete data preprocessing. You can also establish a better model with community developers by setting the data as a public dataset. +
+
+
+
+
+ +
+
+

Model Management and Sharing

+
+ Associate the model with the code version, you can adjust the model in different ways based on the historical version of the code and save the results. The trained model can be open and shared, so that more people can use the model to test and give feedback. +
+
+
+
+
+ +
+
+

Once Configuration, Multiple Reuse

+
+ Provide execution environment sharing, Once Configuration, Multiple Reuse. Lower the threshold of model development, and avoid spending repetitive time configuring complex environments. +
+
+
+
+
+ + +
+
+
+
+ +
+
+

PengCheng Cloudbrain Open Source Collaboration

+

+ The platform has been connected with Pengcheng Cloudbrain and can use the rich computing resources of Pengcheng Cloudbrain to complete AI development tasks.
+ Pengcheng Cloudbrain's existing AI computing power is 100p FLOPS@FP16 (billions of half precision floating-point calculations per second), the main hardware infrastructure is composed of GPU server equipped with NVIDIA Tesla V100 and Atlas 900 AI cluster equipped with Kunpeng and Ascend processors.
+ Developers can freely choose the corresponding computing resources according to their needs, and can test the adaptability, performance, stability of the model in different hardware environments.
+ If your model requires more computing resources, you can also apply for it separately.
+

+ + + Use Now + + + Apply Separately +
+
+
+
+
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/models/ai_model_manage.go b/models/ai_model_manage.go index ed696fcf0..0ea01d6e5 100644 --- a/models/ai_model_manage.go +++ b/models/ai_model_manage.go @@ -2,6 +2,7 @@ package models import ( "fmt" + "time" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -39,6 +40,40 @@ type AiModelManage struct { 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 { ListOptions RepoID int64 // include all repos if empty @@ -47,7 +82,124 @@ type AiModelQueryOptions struct { SortType string New int // 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 { @@ -63,6 +215,20 @@ func SaveModelToDb(model *AiModelManage) error { 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) { sess := x.NewSession() defer sess.Close() @@ -74,14 +240,28 @@ func QueryModelById(id string) (*AiModelManage, error) { if len(aiModelManageList) == 1 { return aiModelManageList[0], nil } + } else { + log.Info("error=" + err.Error()) } return nil, err } -func DeleteModelById(id string) error { +func DeleteModelConvertById(id string) error { sess := x.NewSession() 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{ ID: id, }) @@ -90,7 +270,6 @@ func DeleteModelById(id string) error { } log.Info("success to delete from db.re=" + fmt.Sprint((re))) return nil - } func ModifyModelDescription(id string, description string) error { @@ -201,3 +380,73 @@ func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) { 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 +} diff --git a/models/cloudbrain.go b/models/cloudbrain.go index 85338d2bc..af53bad32 100755 --- a/models/cloudbrain.go +++ b/models/cloudbrain.go @@ -134,7 +134,7 @@ type Cloudbrain struct { CanDebug bool `xorm:"-"` CanDel bool `xorm:"-"` CanModify bool `xorm:"-"` - Type int + Type int `xorm:"INDEX"` BenchmarkTypeID int BenchmarkChildTypeID int @@ -164,12 +164,11 @@ type Cloudbrain struct { FlavorName string //规格名称 EngineName string //引擎名称 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:"-"` Repo *Repository `xorm:"-"` @@ -306,6 +305,22 @@ type CreateJobResult struct { Payload map[string]interface{} `json:"payload"` } +type QueueDetailResult struct { + Code string `json:"code"` + Msg string `json:"msg"` + Payload map[string]QueueDetail `json:"payload"` +} + +type QueueDetail struct { + JobScheduleInfo JobScheduleInfo `json:"JobScheduleInfo"` +} + +type JobScheduleInfo struct { + Pending int `json:"Pending"` + Running int `json:"Running"` + MedianPendingJobDurationSec int `json:"MedianPendingJobDurationSec"` +} + type GetJobResult struct { Code string `json:"code"` Msg string `json:"msg"` @@ -570,11 +585,12 @@ type SpecialPools struct { Pools []*SpecialPool `json:"pools"` } type SpecialPool struct { - Org string `json:"org"` - Type string `json:"type"` - IsExclusive bool `json:"isExclusive"` - Pool []*GpuInfo `json:"pool"` - JobType []string `json:"jobType"` + Org string `json:"org"` + Type string `json:"type"` + IsExclusive bool `json:"isExclusive"` + Pool []*GpuInfo `json:"pool"` + JobType []string `json:"jobType"` + ResourceSpec []*ResourceSpec `json:"resourceSpecs"` } type ImageInfosModelArts struct { @@ -916,6 +932,28 @@ type NotebookDelResult struct { 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 { JobName string `json:"job_name"` Description string `json:"job_desc"` @@ -963,6 +1001,11 @@ type CreateTrainJobVersionParams struct { Config TrainJobVersionConfig `json:"config"` } +type CreateTrainJobVersionUserImageParams struct { + Description string `json:"job_desc"` + Config TrainJobVersionUserImageConfig `json:"config"` +} + type TrainJobVersionConfig struct { WorkServerNum int `json:"worker_server_num"` AppUrl string `json:"app_url"` //训练作业的代码目录 @@ -977,6 +1020,21 @@ type TrainJobVersionConfig struct { 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 { ConfigName string `json:"config_name"` Description string `json:"config_desc"` @@ -1208,13 +1266,17 @@ type GrampusJobInfo struct { UserID string `json:"userId"` Tasks []GrampusTasks `json:"tasks"` } - +type Center struct { + ID string `json:"id"` + Name string `json:"name"` +} type GrampusSpec struct { - CreatedAt int64 `json:"createdAt"` - UpdatedAt int64 `json:"updatedAt"` - ID string `json:"id"` - Name string `json:"name"` - ProcessorType string `json:"processorType"` + CreatedAt int64 `json:"createdAt"` + UpdatedAt int64 `json:"updatedAt"` + ID string `json:"id"` + Name string `json:"name"` + ProcessorType string `json:"processorType"` + Centers []Center `json:"centers"` } type GetGrampusResourceSpecsResult struct { @@ -1409,7 +1471,7 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { return cloudbrains, count, nil } -func QueryModelTrainJobVersionList(jobId string) ([]*CloudbrainInfo, int, error) { +func QueryModelTrainJobVersionList(jobId string) ([]*Cloudbrain, int, error) { sess := x.NewSession() defer sess.Close() @@ -1424,7 +1486,7 @@ func QueryModelTrainJobVersionList(jobId string) ([]*CloudbrainInfo, int, error) ) sess.OrderBy("cloudbrain.created_unix DESC") - cloudbrains := make([]*CloudbrainInfo, 0) + cloudbrains := make([]*Cloudbrain, 0) if err := sess.Table(&Cloudbrain{}).Where(cond). Find(&cloudbrains); err != nil { return nil, 0, fmt.Errorf("Find: %v", err) @@ -1446,9 +1508,9 @@ func QueryModelTrainJobList(repoId int64) ([]*CloudbrainInfo, int, error) { cond = cond.And( 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) if err := sess.Select("job_id,display_job_name").Table(&Cloudbrain{}).Where(cond).OrderBy("created_unix DESC"). @@ -1738,6 +1800,17 @@ func GetBenchmarkCountByUserID(userID int64) (int, error) { return int(count), err } +func GetWaitingCloudbrainCount(cloudbrainType int, computeResource string, jobTypes ...JobType) (int64, error) { + sess := x.Where("status=? and type=?", JobWaiting, cloudbrainType) + if len(jobTypes) > 0 { + sess.In("job_type", jobTypes) + } + if computeResource != "" { + sess.And("compute_resource=?", computeResource) + } + return sess.Count(new(Cloudbrain)) +} + func GetCloudbrainNotebookCountByUserID(userID int64) (int, error) { count, err := x.In("status", ModelArtsCreateQueue, ModelArtsCreating, ModelArtsStarting, ModelArtsReadyToStart, ModelArtsResizing, ModelArtsStartQueuing, ModelArtsRunning, ModelArtsRestarting). And("job_type = ? and user_id = ? and type = ?", JobTypeDebug, userID, TypeCloudBrainTwo).Count(new(Cloudbrain)) @@ -2014,3 +2087,30 @@ func GetDatasetInfo(uuidStr string) (map[string]DatasetInfo, string, error) { return datasetInfos, datasetNames, nil } + +func GetNewestJobsByAiCenter() ([]int64, error) { + ids := make([]int64, 0) + return ids, x. + Select("max(id) as id"). + Where("type=? and ai_center!='' and ai_center is not null", TypeC2Net). + GroupBy("ai_center"). + Table(Cloudbrain{}). + Find(&ids) +} + +func GetNewestJobsByType() ([]int64, error) { + ids := make([]int64, 0) + return ids, x. + Select("max(id) as id"). + In("type", TypeCloudBrainOne, TypeCloudBrainTwo). + GroupBy("type"). + Table(Cloudbrain{}). + Find(&ids) +} + +func GetCloudbrainByIDs(ids []int64) ([]*Cloudbrain, error) { + cloudbrains := make([]*Cloudbrain, 0) + return cloudbrains, x. + In("id", ids). + Find(&cloudbrains) +} diff --git a/models/custom_migrations.go b/models/custom_migrations.go index 65b53f0f4..041c4fb93 100755 --- a/models/custom_migrations.go +++ b/models/custom_migrations.go @@ -15,10 +15,15 @@ type CustomMigrationStatic struct { Migrate func(*xorm.Engine, *xorm.Engine) error } -var customMigrations []CustomMigration +var customMigrations = []CustomMigration{ + //手机号功能可以不启用,不启用时手机号为空串,为了避免启用时唯一性约束报错,定制唯一性约束(对null和空字符串不做唯一性检查) + {"set phone number unique index", setPhoneNumberUniqueIndex}, +} var customMigrationsStatic []CustomMigrationStatic + + func MigrateCustom(x *xorm.Engine) { for _, m := range customMigrations { @@ -35,13 +40,20 @@ func MigrateCustomStatic(x *xorm.Engine, static *xorm.Engine) { for _, m := range customMigrationsStatic { log.Info("Migration: %s", m.Description) if err := m.Migrate(x, static); err != nil { - log.Error("Migration: %v", err) - } } } +func setPhoneNumberUniqueIndex(x *xorm.Engine) error { + + query := "CREATE UNIQUE INDEX IF NOT EXISTS \"UQE_user_phone_number\" ON \"user\" (phone_number) WHERE phone_number IS NOT NULL and phone_number !='';" + + _, err := x.Exec(query) + return err +} + + func syncTopicStruct(x *xorm.Engine) error { query := "ALTER TABLE topic ALTER COLUMN name TYPE varchar(105);" diff --git a/models/login_source.go b/models/login_source.go index ca2aa5a4d..5641e5c59 100755 --- a/models/login_source.go +++ b/models/login_source.go @@ -766,6 +766,14 @@ func UserSignIn(username, password string) (*User, error) { if err != nil { return nil, err } + //email和用户名方式没找到,用手机号查找 + if !hasUser { + user = &User{PhoneNumber: strings.TrimSpace(username)} + hasUser, err = x.Get(user) + if err != nil { + return nil, err + } + } if hasUser { switch user.LoginType { diff --git a/models/models.go b/models/models.go index 9d255c5e6..b714f4650 100755 --- a/models/models.go +++ b/models/models.go @@ -144,6 +144,7 @@ func init() { new(WechatBindLog), new(OrgStatistic), new(SearchRecord), + new(AiModelConvert), ) tablesStatistic = append(tablesStatistic, diff --git a/models/repo_activity_custom.go b/models/repo_activity_custom.go index cbe00b9d9..6e7921d75 100644 --- a/models/repo_activity_custom.go +++ b/models/repo_activity_custom.go @@ -211,6 +211,42 @@ func setKeyContributerDict(contributorDistinctDict map[string]int, email string, } } +func GetAllUserPublicRepoKPIStats(startTime time.Time, endTime time.Time) (map[string]*git.UserKPIStats, error) { + authors := make(map[string]*git.UserKPIStats) + repositorys, err := GetAllRepositoriesByFilterCols("owner_name", "name", "is_private") + if err != nil { + return nil, err + } + + for _, repository := range repositorys { + if repository.IsPrivate { + continue + } + authorsOneRepo, err1 := git.GetUserKPIStats(repository.RepoPath(), startTime, endTime) + if err1 != nil { + log.Warn("get user kpi status err:"+repository.RepoPath(), err1.Error()) + continue + } + + for key, value := range authorsOneRepo { + if _, ok := authors[key]; !ok { + authors[key] = &git.UserKPIStats{ + + Name: value.Name, + Email: value.Email, + Commits: 0, + CommitLines: 0, + } + } + authors[key].Commits += value.Commits + authors[key].CommitLines += value.CommitLines + + } + + } + return authors, nil +} + func GetAllUserKPIStats(startTime time.Time, endTime time.Time) (map[string]*git.UserKPIStats, error) { authors := make(map[string]*git.UserKPIStats) repositorys, err := GetAllRepositoriesByFilterCols("owner_name", "name") diff --git a/models/user.go b/models/user.go index dd5a6f1d2..a423a843b 100755 --- a/models/user.go +++ b/models/user.go @@ -184,6 +184,8 @@ type User struct { //Wechat WechatOpenId string `xorm:"INDEX"` WechatBindUnix timeutil.TimeStamp + //Mobile phone + PhoneNumber string `xorm:"VARCHAR(255)"` } // SearchOrganizationsOptions options to filter organizations @@ -1442,6 +1444,31 @@ func getUserByName(e Engine, name string) (*User, error) { return u, nil } +func GetUserByPhoneNumber(phoneNumber string) (*User, error) { + return getUserByPhoneNumber(x, phoneNumber) +} + +func getUserByPhoneNumber(e Engine, phoneNumber string) (*User, error) { + u := &User{PhoneNumber: phoneNumber} + has, err := e.Get(u) + if err != nil { + return nil, err + } else if !has { + return nil, ErrUserNotExist{0, "", 0} + } + return u, nil +} + +func IsUserByPhoneNumberExist(phoneNumber string) (bool, error) { + return isUserByPhoneNumberExist(x, phoneNumber) + +} + +func isUserByPhoneNumberExist(e Engine, phoneNumber string) (bool, error) { + return e.Where("phone_number = ?", phoneNumber).Exist(&User{}) + +} + // GetUserEmailsByNames returns a list of e-mails corresponds to names of users // that have their email notifications set to enabled or onmention. func GetUserEmailsByNames(names []string) []string { @@ -1610,6 +1637,26 @@ func GetUserByEmail(email string) (*User, error) { return GetUserByEmailContext(DefaultDBContext(), email) } +func GetUserByMainEmail(email string) (*User, error) { + if len(email) == 0 { + return nil, ErrUserNotExist{0, email, 0} + } + + email = strings.ToLower(email) + // First try to find the user by primary email + user := &User{Email: email} + has, err := DefaultDBContext().e.Get(user) + if err != nil { + return nil, err + } + if has { + return user, nil + } else { + return nil, ErrUserNotExist{0, email, 0} + } + +} + // GetUserByEmailContext returns the user object by given e-mail if exists with db context func GetUserByEmailContext(ctx DBContext, email string) (*User, error) { if len(email) == 0 { diff --git a/models/user_analysis_for_activity.go b/models/user_analysis_for_activity.go new file mode 100644 index 000000000..e69eecae0 --- /dev/null +++ b/models/user_analysis_for_activity.go @@ -0,0 +1,437 @@ +package models + +import ( + "fmt" + "time" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/timeutil" +) + +type UserBusinessAnalysisForActivity struct { + ID int64 `xorm:"pk"` + CountDate int64 `xorm:"pk"` + //action :ActionMergePullRequest // 11 + CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"` + //action :ActionCommitRepo + CommitCount int `xorm:"NOT NULL DEFAULT 0"` + //issue // 10 + IssueCount int `xorm:"NOT NULL DEFAULT 0"` + //comment table current date + CommentCount int `xorm:"NOT NULL DEFAULT 0"` + + //follow table + WatchedCount int `xorm:"NOT NULL DEFAULT 0"` + + CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"` + //issue, issueassigees + SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"` + //use + RegistDate timeutil.TimeStamp `xorm:"NOT NULL"` + + //user + Email string `xorm:"NOT NULL"` + + Phone string `xorm:"NULL"` + //user + Name string `xorm:"NOT NULL"` + DataDate string `xorm:"NULL"` + + CloudBrainTaskNum int `xorm:"NOT NULL DEFAULT 0"` + CommitDatasetNum int `xorm:"NOT NULL DEFAULT 0"` + //0 + CommitModelCount int `xorm:"NOT NULL DEFAULT 0"` +} + +func QueryDataForActivity(startTime time.Time, endTime time.Time) []*UserBusinessAnalysisForActivity { + sess := x.NewSession() + defer sess.Close() + + result := make([]*UserBusinessAnalysisForActivity, 0) + publicRepo := queryPublicRepo() + start_unix := startTime.Unix() + end_unix := endTime.Unix() + + CodeMergeCountMap := queryPullRequestPublic(start_unix, end_unix, publicRepo) + CommitCodeSizeMap, err := GetAllUserPublicRepoKPIStats(startTime, endTime) + if err != nil { + log.Info("error,info=" + err.Error()) + } + CommitCountMap := queryCommitActionPublic(start_unix, end_unix, 5, publicRepo) + IssueCountMap, publicRepoIssueIdMap := queryCreateIssuePublic(start_unix, end_unix, publicRepo) + SolveIssueCountMap := querySolveIssuePublic(start_unix, end_unix, publicRepoIssueIdMap) + WatchedCountMap, _ := queryFollow(start_unix, end_unix) + CommentCountMap := queryCommentPublic(start_unix, end_unix, publicRepoIssueIdMap) + PublicDataSet := queryAllPublicDataSet(publicRepo) + DatasetFileNums := queryPublicDatasetFileNums(start_unix, end_unix, PublicDataSet) + AiModelManageMap := queryUserModelPublic(start_unix, end_unix, publicRepo) + + cond := "type != 1 and is_active=true" + count, err := sess.Where(cond).Count(new(User)) + + var indexTotal int64 + indexTotal = 0 + for { + sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) + userList := make([]*User, 0) + sess.Find(&userList) + + for i, userRecord := range userList { + var dateRecord UserBusinessAnalysisForActivity + dateRecord.ID = userRecord.ID + log.Info("i=" + fmt.Sprint(i) + " userName=" + userRecord.Name) + dateRecord.Email = userRecord.Email + dateRecord.Phone = userRecord.PhoneNumber + dateRecord.RegistDate = userRecord.CreatedUnix + dateRecord.Name = userRecord.Name + + dateRecord.CodeMergeCount = getMapValue(dateRecord.ID, CodeMergeCountMap) + dateRecord.CommitCount = getMapValue(dateRecord.ID, CommitCountMap) + dateRecord.WatchedCount = getMapValue(dateRecord.ID, WatchedCountMap) + dateRecord.CommitDatasetNum = getMapValue(dateRecord.ID, DatasetFileNums) + dateRecord.IssueCount = getMapValue(dateRecord.ID, IssueCountMap) + dateRecord.CommentCount = getMapValue(dateRecord.ID, CommentCountMap) + if _, ok := CommitCodeSizeMap[dateRecord.Email]; !ok { + dateRecord.CommitCodeSize = 0 + } else { + dateRecord.CommitCodeSize = int(CommitCodeSizeMap[dateRecord.Email].CommitLines) + } + dateRecord.SolveIssueCount = getMapValue(dateRecord.ID, SolveIssueCountMap) + + dateRecord.CommitModelCount = getMapValue(dateRecord.ID, AiModelManageMap) + + result = append(result, &dateRecord) + } + indexTotal += PAGE_SIZE + if indexTotal >= count { + break + } + } + + return result +} +func querySolveIssuePublic(start_unix int64, end_unix int64, publicRepoIssueIdMap map[int64]int) map[int64]int { + sess := x.NewSession() + defer sess.Close() + resultMap := make(map[int64]int) + cond := "issue.is_closed=true and issue.closed_unix>=" + fmt.Sprint(start_unix) + " and issue.closed_unix<=" + fmt.Sprint(end_unix) + + count, err := sess.Table("issue_assignees").Join("inner", "issue", "issue.id=issue_assignees.issue_id").Where(cond).Count(new(IssueAssignees)) + if err != nil { + log.Info("query issue error. return.") + return resultMap + } + var indexTotal int64 + indexTotal = 0 + for { + issueAssigneesList := make([]*IssueAssignees, 0) + sess.Select("issue_assignees.*").Table("issue_assignees"). + Join("inner", "issue", "issue.id=issue_assignees.issue_id"). + Where(cond).OrderBy("issue_assignees.id asc").Limit(PAGE_SIZE, int(indexTotal)) + + sess.Find(&issueAssigneesList) + + log.Info("query IssueAssignees size=" + fmt.Sprint(len(issueAssigneesList))) + for _, issueAssigneesRecord := range issueAssigneesList { + if isPublicRepo(issueAssigneesRecord.IssueID, publicRepoIssueIdMap) { + if _, ok := resultMap[issueAssigneesRecord.AssigneeID]; !ok { + resultMap[issueAssigneesRecord.AssigneeID] = 1 + } else { + resultMap[issueAssigneesRecord.AssigneeID] += 1 + } + } + } + indexTotal += PAGE_SIZE + if indexTotal >= count { + break + } + } + + return resultMap +} + +func queryPublicRepo() map[int64]int { + sess := x.NewSession() + defer sess.Close() + resultMap := make(map[int64]int) + + count, err := sess.Table("repository").Count(new(Repository)) + if err != nil { + log.Info("query Repository error. return.") + return resultMap + } + var indexTotal int64 + indexTotal = 0 + for { + repositoryList := make([]*Repository, 0) + sess.Select("*").Table("repository").OrderBy("id desc").Limit(PAGE_SIZE, int(indexTotal)) + sess.Find(&repositoryList) + log.Info("query repo size=" + fmt.Sprint(len(repositoryList))) + for _, repositoryRecord := range repositoryList { + if repositoryRecord.IsPrivate { + continue + } + if _, ok := resultMap[repositoryRecord.ID]; !ok { + resultMap[repositoryRecord.ID] = 1 + } + } + indexTotal += PAGE_SIZE + if indexTotal >= count { + break + } + } + + return resultMap +} + +func isPublicRepo(repoId int64, publicAllRepo map[int64]int) bool { + if _, ok := publicAllRepo[repoId]; !ok { + return false + } + return true +} + +func queryPullRequestPublic(start_unix int64, end_unix int64, publicAllRepo map[int64]int) map[int64]int { + sess := x.NewSession() + defer sess.Close() + resultMap := make(map[int64]int) + cond := "pull_request.merged_unix>=" + fmt.Sprint(start_unix) + " and pull_request.merged_unix<=" + fmt.Sprint(end_unix) + count, err := sess.Table("issue").Join("inner", "pull_request", "issue.id=pull_request.issue_id").Where(cond).Count(new(Issue)) + if err != nil { + log.Info("query issue error. return.") + return resultMap + } + var indexTotal int64 + indexTotal = 0 + for { + issueList := make([]*Issue, 0) + sess.Select("issue.*").Table("issue").Join("inner", "pull_request", "issue.id=pull_request.issue_id").Where(cond).OrderBy("issue.id asc").Limit(PAGE_SIZE, int(indexTotal)) + sess.Find(&issueList) + log.Info("query issue(PR) size=" + fmt.Sprint(len(issueList))) + for _, issueRecord := range issueList { + if isPublicRepo(issueRecord.RepoID, publicAllRepo) { + if _, ok := resultMap[issueRecord.PosterID]; !ok { + resultMap[issueRecord.PosterID] = 1 + } else { + resultMap[issueRecord.PosterID] += 1 + } + } + } + indexTotal += PAGE_SIZE + if indexTotal >= count { + break + } + } + return resultMap +} + +func queryCommitActionPublic(start_unix int64, end_unix int64, actionType int64, publicAllRepo map[int64]int) map[int64]int { + sess := x.NewSession() + defer sess.Close() + resultMap := make(map[int64]int) + + cond := "user_id=act_user_id and op_type=" + fmt.Sprint(actionType) + " and created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) + + count, err := sess.Where(cond).Count(new(Action)) + if err != nil { + log.Info("query action error. return.") + return resultMap + } + var indexTotal int64 + indexTotal = 0 + for { + sess.Select("id,user_id,op_type,act_user_id,repo_id").Table("action").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) + actionList := make([]*Action, 0) + sess.Find(&actionList) + + log.Info("query action size=" + fmt.Sprint(len(actionList))) + for _, actionRecord := range actionList { + if isPublicRepo(actionRecord.RepoID, publicAllRepo) { + if _, ok := resultMap[actionRecord.UserID]; !ok { + resultMap[actionRecord.UserID] = 1 + } else { + resultMap[actionRecord.UserID] += 1 + } + } + } + indexTotal += PAGE_SIZE + if indexTotal >= count { + break + } + } + + return resultMap +} + +func queryCreateIssuePublic(start_unix int64, end_unix int64, publicAllRepo map[int64]int) (map[int64]int, map[int64]int) { + + sess := x.NewSession() + defer sess.Close() + resultMap := make(map[int64]int) + publicRepoIssueIdMap := make(map[int64]int) + cond := "is_pull=false and created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) + + count, err := sess.Where(cond).Count(new(Issue)) + if err != nil { + log.Info("query Issue error. return.") + return resultMap, publicRepoIssueIdMap + } + var indexTotal int64 + indexTotal = 0 + for { + sess.Select("id,poster_id,repo_id").Table("issue").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) + issueList := make([]*Issue, 0) + sess.Find(&issueList) + log.Info("query issue size=" + fmt.Sprint(len(issueList))) + for _, issueRecord := range issueList { + if isPublicRepo(issueRecord.RepoID, publicAllRepo) { + if _, ok := resultMap[issueRecord.PosterID]; !ok { + resultMap[issueRecord.PosterID] = 1 + } else { + resultMap[issueRecord.PosterID] += 1 + } + publicRepoIssueIdMap[issueRecord.ID] = 1 + } + } + indexTotal += PAGE_SIZE + if indexTotal >= count { + break + } + } + return resultMap, publicRepoIssueIdMap + +} + +func queryCommentPublic(start_unix int64, end_unix int64, publicRepoIssueIdMap map[int64]int) map[int64]int { + + sess := x.NewSession() + defer sess.Close() + cond := "created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) + resultMap := make(map[int64]int) + count, err := sess.Where(cond).Count(new(Comment)) + if err != nil { + log.Info("query Comment error. return.") + return resultMap + } + var indexTotal int64 + indexTotal = 0 + for { + sess.Select("id,type,poster_id,issue_id").Table("comment").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) + commentList := make([]*Comment, 0) + sess.Find(&commentList) + log.Info("query Comment size=" + fmt.Sprint(len(commentList))) + for _, commentRecord := range commentList { + if isPublicRepo(commentRecord.IssueID, publicRepoIssueIdMap) { + if _, ok := resultMap[commentRecord.PosterID]; !ok { + resultMap[commentRecord.PosterID] = 1 + } else { + resultMap[commentRecord.PosterID] += 1 + } + } + } + indexTotal += PAGE_SIZE + if indexTotal >= count { + break + } + } + return resultMap +} + +func queryAllPublicDataSet(publicAllRepo map[int64]int) map[int64]int { + sess := x.NewSession() + defer sess.Close() + publicDataSetIdMap := make(map[int64]int) + count, err := sess.Count(new(Dataset)) + if err != nil { + log.Info("query dataset error. return.") + return publicDataSetIdMap + } + var indexTotal int64 + indexTotal = 0 + for { + sess.Select("id,user_id,repo_id").Table(new(Dataset)).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) + datasetList := make([]*Dataset, 0) + sess.Find(&datasetList) + log.Info("query datasetList size=" + fmt.Sprint(len(datasetList))) + for _, datasetRecord := range datasetList { + if isPublicRepo(datasetRecord.RepoID, publicAllRepo) { + publicDataSetIdMap[datasetRecord.ID] = 1 + } + } + indexTotal += PAGE_SIZE + if indexTotal >= count { + break + } + } + return publicDataSetIdMap +} + +func queryPublicDatasetFileNums(start_unix int64, end_unix int64, publicDataSetIdMap map[int64]int) map[int64]int { + sess := x.NewSession() + defer sess.Close() + resultNumMap := make(map[int64]int) + cond := " created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) + + count, err := sess.Where(cond).Count(new(Attachment)) + if err != nil { + log.Info("query attachment error. return.") + return resultNumMap + } + var indexTotal int64 + indexTotal = 0 + for { + sess.Select("id,uploader_id,size,dataset_id").Table("attachment").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) + attachmentList := make([]*Attachment, 0) + sess.Find(&attachmentList) + + log.Info("query Attachment size=" + fmt.Sprint(len(attachmentList))) + for _, attachRecord := range attachmentList { + if isPublicRepo(attachRecord.DatasetID, publicDataSetIdMap) { + if _, ok := resultNumMap[attachRecord.UploaderID]; !ok { + resultNumMap[attachRecord.UploaderID] = 1 + } else { + resultNumMap[attachRecord.UploaderID] += 1 + } + } + } + indexTotal += PAGE_SIZE + if indexTotal >= count { + break + } + } + return resultNumMap +} + +func queryUserModelPublic(start_unix int64, end_unix int64, publicAllRepo map[int64]int) map[int64]int { + sess := x.NewSession() + defer sess.Close() + resultMap := make(map[int64]int) + cond := " created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) + count, err := sess.Where(cond).Count(new(AiModelManage)) + if err != nil { + log.Info("query AiModelManage error. return.") + return resultMap + } + var indexTotal int64 + indexTotal = 0 + for { + sess.Select("id,user_id,repo_id").Table("ai_model_manage").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) + aiModelList := make([]*AiModelManage, 0) + sess.Find(&aiModelList) + log.Info("query AiModelManage size=" + fmt.Sprint(len(aiModelList))) + for _, aiModelRecord := range aiModelList { + if isPublicRepo(aiModelRecord.RepoId, publicAllRepo) { + if _, ok := resultMap[aiModelRecord.UserId]; !ok { + resultMap[aiModelRecord.UserId] = 1 + } else { + resultMap[aiModelRecord.UserId] += 1 + } + } + } + indexTotal += PAGE_SIZE + if indexTotal >= count { + break + } + } + return resultMap +} diff --git a/models/user_business_analysis.go b/models/user_business_analysis.go index e058c0df8..cb503d669 100644 --- a/models/user_business_analysis.go +++ b/models/user_business_analysis.go @@ -105,6 +105,8 @@ type UserBusinessAnalysisAll struct { CollectImage int `xorm:"NOT NULL DEFAULT 0"` CollectedImage int `xorm:"NOT NULL DEFAULT 0"` RecommendImage int `xorm:"NOT NULL DEFAULT 0"` + + Phone string `xorm:"NULL"` } type UserBusinessAnalysis struct { @@ -192,6 +194,8 @@ type UserBusinessAnalysis struct { CollectImage int `xorm:"NOT NULL DEFAULT 0"` CollectedImage int `xorm:"NOT NULL DEFAULT 0"` RecommendImage int `xorm:"NOT NULL DEFAULT 0"` + + Phone string `xorm:"NULL"` } type UserBusinessAnalysisQueryOptions struct { @@ -358,7 +362,7 @@ func QueryUserStaticDataByTableName(start int, pageSize int, tableName string, q var cond = builder.NewCond() if len(userName) > 0 { cond = cond.And( - builder.Like{"name", userName}, + builder.Like{"lower(name)", strings.ToLower(userName)}, ) } allCount, err := statictisSess.Where(cond).Count(queryObj) @@ -475,6 +479,7 @@ func QueryUserStaticDataForUserDefine(opts *UserBusinessAnalysisQueryOptions, wi dateRecord.CountDate = CountDate.Unix() dateRecord.DataDate = DataDate dateRecord.Email = userRecord.Email + dateRecord.Phone = userRecord.PhoneNumber dateRecord.RegistDate = userRecord.CreatedUnix dateRecord.Name = userRecord.Name dateRecord.UserLocation = userRecord.Location @@ -728,6 +733,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS var dateRecordAll UserBusinessAnalysisAll dateRecordAll.ID = userRecord.ID dateRecordAll.Email = userRecord.Email + dateRecordAll.Phone = userRecord.PhoneNumber dateRecordAll.RegistDate = userRecord.CreatedUnix dateRecordAll.Name = userRecord.Name dateRecordAll.GiteaAgeMonth = subMonth(currentTimeNow, userRecord.CreatedUnix.AsTime()) @@ -839,7 +845,7 @@ func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, static insertBatchSql := "INSERT INTO public." + tableName + "(id, count_date, code_merge_count, commit_count, issue_count, comment_count, focus_repo_count, star_repo_count, watched_count, gitea_age_month, commit_code_size, commit_dataset_size, " + - "commit_model_count, solve_issue_count, encyclopedias_count, regist_date, create_repo_count, login_count, open_i_index, email, name, data_date,cloud_brain_task_num,gpu_debug_job,npu_debug_job,gpu_train_job,npu_train_job,npu_inference_job,gpu_bench_mark_job,cloud_brain_run_time,commit_dataset_num,user_index,user_location,focus_other_user,collect_dataset,collected_dataset,recommend_dataset,collect_image,collected_image,recommend_image,user_index_primitive) " + + "commit_model_count, solve_issue_count, encyclopedias_count, regist_date, create_repo_count, login_count, open_i_index, email, name, data_date,cloud_brain_task_num,gpu_debug_job,npu_debug_job,gpu_train_job,npu_train_job,npu_inference_job,gpu_bench_mark_job,cloud_brain_run_time,commit_dataset_num,user_index,user_location,focus_other_user,collect_dataset,collected_dataset,recommend_dataset,collect_image,collected_image,recommend_image,user_index_primitive,phone) " + "VALUES" for i, record := range dateRecords { @@ -848,7 +854,7 @@ func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, static ", " + fmt.Sprint(record.WatchedCount) + ", " + fmt.Sprint(record.GiteaAgeMonth) + ", " + fmt.Sprint(record.CommitCodeSize) + ", " + fmt.Sprint(record.CommitDatasetSize) + ", " + fmt.Sprint(record.CommitModelCount) + ", " + fmt.Sprint(record.SolveIssueCount) + ", " + fmt.Sprint(record.EncyclopediasCount) + ", " + fmt.Sprint(record.RegistDate) + ", " + fmt.Sprint(record.CreateRepoCount) + ", " + fmt.Sprint(record.LoginCount) + ", " + fmt.Sprint(record.OpenIIndex) + ", '" + record.Email + "', '" + record.Name + "', '" + record.DataDate + "'," + fmt.Sprint(record.CloudBrainTaskNum) + "," + fmt.Sprint(record.GpuDebugJob) + "," + fmt.Sprint(record.NpuDebugJob) + "," + fmt.Sprint(record.GpuTrainJob) + "," + fmt.Sprint(record.NpuTrainJob) + "," + fmt.Sprint(record.NpuInferenceJob) + "," + fmt.Sprint(record.GpuBenchMarkJob) + "," + fmt.Sprint(record.CloudBrainRunTime) + "," + fmt.Sprint(record.CommitDatasetNum) + "," + fmt.Sprint(record.UserIndex) + ",'" + record.UserLocation + "'," + - fmt.Sprint(record.FocusOtherUser) + "," + fmt.Sprint(record.CollectDataset) + "," + fmt.Sprint(record.CollectedDataset) + "," + fmt.Sprint(record.RecommendDataset) + "," + fmt.Sprint(record.CollectImage) + "," + fmt.Sprint(record.CollectedImage) + "," + fmt.Sprint(record.RecommendImage) + "," + fmt.Sprint(record.UserIndexPrimitive) + ")" + fmt.Sprint(record.FocusOtherUser) + "," + fmt.Sprint(record.CollectDataset) + "," + fmt.Sprint(record.CollectedDataset) + "," + fmt.Sprint(record.RecommendDataset) + "," + fmt.Sprint(record.CollectImage) + "," + fmt.Sprint(record.CollectedImage) + "," + fmt.Sprint(record.RecommendImage) + "," + fmt.Sprint(record.UserIndexPrimitive) + ",'" + record.Phone + "')" if i < (len(dateRecords) - 1) { insertBatchSql += "," } @@ -973,6 +979,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, dateRecord.CountDate = CountDate.Unix() dateRecord.Email = userRecord.Email + dateRecord.Phone = userRecord.PhoneNumber dateRecord.RegistDate = userRecord.CreatedUnix dateRecord.Name = userRecord.Name dateRecord.GiteaAgeMonth = subMonth(currentTimeNow, userRecord.CreatedUnix.AsTime()) @@ -1028,12 +1035,12 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, setUserMetrics(userMetrics, userRecord, start_unix, end_unix, dateRecord) if getUserActivate(dateRecord) > 0 { log.Info("has activity." + userRecord.Name) - addUserToMap(userNewAddActivity, userRecord.CreatedUnix, dateRecord.ID) + addUserToMap(userNewAddActivity, userRecord.CreatedUnix, dateRecord.ID, currentTimeNow) } if userRecord.IsActive { - addUserToMap(userAcitvateJsonMap, userRecord.CreatedUnix, dateRecord.ID) + addUserToMap(userAcitvateJsonMap, userRecord.CreatedUnix, dateRecord.ID, currentTimeNow) } - addUserToMap(userCurrentDayRegistMap, userRecord.CreatedUnix, dateRecord.ID) + addUserToMap(userCurrentDayRegistMap, userRecord.CreatedUnix, dateRecord.ID, currentTimeNow) } indexTotal += PAGE_SIZE @@ -1056,7 +1063,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, useMetrics.NotActivateRegistUser = getMapKeyStringValue("NotActivateRegistUser", userMetrics) useMetrics.TotalActivateRegistUser = getMapKeyStringValue("TotalActivateRegistUser", userMetrics) useMetrics.TotalHasActivityUser = getMapKeyStringValue("TotalHasActivityUser", userMetrics) - + useMetrics.CurrentDayRegistUser = getMapKeyStringValue("CurrentDayRegistUser", userMetrics) count, err = sess.Where("type=0").Count(new(User)) if err != nil { log.Info("query user error. return.") @@ -1124,8 +1131,9 @@ func setUniqueUserId(jsonString string, value map[int64]int64) (string, int) { return userIdArray, len(value) } -func addUserToMap(currentUserActivity map[int64]map[int64]int64, registDate timeutil.TimeStamp, userId int64) { - CountDateTime := time.Date(registDate.Year(), registDate.AsTime().Month(), registDate.AsTime().Day(), 0, 1, 0, 0, registDate.AsTime().Location()) +func addUserToMap(currentUserActivity map[int64]map[int64]int64, registDate timeutil.TimeStamp, userId int64, currentTimeNow time.Time) { + registTime := registDate.AsTimeInLocation(currentTimeNow.Location()) + CountDateTime := time.Date(registTime.Year(), registTime.Month(), registTime.Day(), 0, 1, 0, 0, currentTimeNow.Location()) CountDate := CountDateTime.Unix() if _, ok := currentUserActivity[CountDate]; !ok { userIdMap := make(map[int64]int64, 0) @@ -1149,6 +1157,7 @@ func setUserMetrics(userMetrics map[string]int, user *User, start_time int64, en } else { userMetrics["NotActivateRegistUser"] = getMapKeyStringValue("NotActivateRegistUser", userMetrics) + 1 } + userMetrics["CurrentDayRegistUser"] = getMapKeyStringValue("CurrentDayRegistUser", userMetrics) + 1 } if user.IsActive { userMetrics["TotalActivateRegistUser"] = getMapKeyStringValue("TotalActivateRegistUser", userMetrics) + 1 diff --git a/models/user_business_struct.go b/models/user_business_struct.go index 870a64bc7..36ef077e2 100644 --- a/models/user_business_struct.go +++ b/models/user_business_struct.go @@ -65,6 +65,8 @@ type UserBusinessAnalysisCurrentYear struct { CollectImage int `xorm:"NOT NULL DEFAULT 0"` CollectedImage int `xorm:"NOT NULL DEFAULT 0"` RecommendImage int `xorm:"NOT NULL DEFAULT 0"` + + Phone string `xorm:"NULL"` } type UserBusinessAnalysisLast30Day struct { @@ -130,6 +132,8 @@ type UserBusinessAnalysisLast30Day struct { CollectImage int `xorm:"NOT NULL DEFAULT 0"` CollectedImage int `xorm:"NOT NULL DEFAULT 0"` RecommendImage int `xorm:"NOT NULL DEFAULT 0"` + + Phone string `xorm:"NULL"` } type UserBusinessAnalysisLastMonth struct { @@ -195,6 +199,8 @@ type UserBusinessAnalysisLastMonth struct { CollectImage int `xorm:"NOT NULL DEFAULT 0"` CollectedImage int `xorm:"NOT NULL DEFAULT 0"` RecommendImage int `xorm:"NOT NULL DEFAULT 0"` + + Phone string `xorm:"NULL"` } type UserBusinessAnalysisCurrentMonth struct { @@ -260,6 +266,8 @@ type UserBusinessAnalysisCurrentMonth struct { CollectImage int `xorm:"NOT NULL DEFAULT 0"` CollectedImage int `xorm:"NOT NULL DEFAULT 0"` RecommendImage int `xorm:"NOT NULL DEFAULT 0"` + + Phone string `xorm:"NULL"` } type UserBusinessAnalysisCurrentWeek struct { @@ -326,6 +334,8 @@ type UserBusinessAnalysisCurrentWeek struct { CollectImage int `xorm:"NOT NULL DEFAULT 0"` CollectedImage int `xorm:"NOT NULL DEFAULT 0"` RecommendImage int `xorm:"NOT NULL DEFAULT 0"` + + Phone string `xorm:"NULL"` } type UserBusinessAnalysisYesterday struct { @@ -392,6 +402,8 @@ type UserBusinessAnalysisYesterday struct { CollectImage int `xorm:"NOT NULL DEFAULT 0"` CollectedImage int `xorm:"NOT NULL DEFAULT 0"` RecommendImage int `xorm:"NOT NULL DEFAULT 0"` + + Phone string `xorm:"NULL"` } type UserBusinessAnalysisLastWeek struct { @@ -458,6 +470,8 @@ type UserBusinessAnalysisLastWeek struct { CollectImage int `xorm:"NOT NULL DEFAULT 0"` CollectedImage int `xorm:"NOT NULL DEFAULT 0"` RecommendImage int `xorm:"NOT NULL DEFAULT 0"` + + Phone string `xorm:"NULL"` } type UserAnalysisPara struct { diff --git a/modules/auth/cloudbrain.go b/modules/auth/cloudbrain.go index e5be38084..160328b5b 100755 --- a/modules/auth/cloudbrain.go +++ b/modules/auth/cloudbrain.go @@ -50,6 +50,28 @@ type EditImageCloudBrainForm struct { Topics string `form:"topics"` } +type CreateCloudBrainInferencForm struct { + JobName string `form:"job_name" binding:"Required"` + DisplayJobName string `form:"display_job_name" binding:"Required"` + Image string `form:"image" binding:"Required"` + Command string `form:"command" binding:"Required"` + Attachment string `form:"attachment" binding:"Required"` + JobType string `form:"job_type" binding:"Required"` + BenchmarkCategory string `form:"get_benchmark_category"` + GpuType string `form:"gpu_type"` + TrainUrl string `form:"train_url"` + TestUrl string `form:"test_url"` + Description string `form:"description"` + ResourceSpecId int `form:"resource_spec_id" binding:"Required"` + BootFile string `form:"boot_file"` + Params string `form:"run_para_list"` + BranchName string `form:"branch_name"` + ModelName string `form:"model_name" binding:"Required"` + ModelVersion string `form:"model_version" binding:"Required"` + CkptName string `form:"ckpt_name" binding:"Required"` + LabelName string `form:"label_names" binding:"Required"` +} + func (f *CreateCloudBrainForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { return validate(errs, ctx.Data, f, ctx.Locale) } @@ -61,3 +83,7 @@ func (f *CommitImageCloudBrainForm) Validate(ctx *macaron.Context, errs binding. func (f *EditImageCloudBrainForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { return validate(errs, ctx.Data, f, ctx.Locale) } + +func (f *CreateCloudBrainInferencForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { + return validate(errs, ctx.Data, f, ctx.Locale) +} diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go index 86771b9f8..130586a5a 100755 --- a/modules/auth/user_form.go +++ b/modules/auth/user_form.go @@ -81,8 +81,11 @@ type RegisterForm struct { UserName string `binding:"Required;AlphaDashDot;MaxSize(40)"` Email string `binding:"Required;Email;MaxSize(254)"` Password string `binding:"MaxSize(255)"` + PhoneNumber string `binding:"MaxSize(20)"` + VerifyCode string `binding:"MaxSize(10)"` Retype string GRecaptchaResponse string `form:"g-recaptcha-response"` + Agree bool } // Validate valideates the fields @@ -105,7 +108,7 @@ func (f RegisterForm) IsEmailDomainWhitelisted() bool { } domain := strings.ToLower(f.Email[n+1:]) - + //support edu.cn if strings.HasSuffix(domain, "edu.cn") { return true @@ -209,6 +212,8 @@ type UpdateProfileForm struct { Location string `binding:"MaxSize(50)"` Language string `binding:"Size(5)"` Description string `binding:"MaxSize(255)"` + PhoneNumber string `binding:"MaxSize(20)"` + VerifyCode string `binding:"MaxSize(10)"` } // Validate validates the fields @@ -364,3 +369,43 @@ type U2FDeleteForm struct { func (f *U2FDeleteForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { return validate(errs, ctx.Data, f, ctx.Locale) } + +type PhoneNumberForm struct { + PhoneNumber string `binding:"Required;MaxSize(20)"` + Mode int `binding:"Required"` + SlideID string `binding:"Required;MaxSize(100)"` +} + +func (f *PhoneNumberForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { + return validate(errs, ctx.Data, f, ctx.Locale) +} + +type PhoneNumberCodeForm struct { + PhoneNumber string `binding:"Required;MaxSize(20)"` + VerifyCode string `binding:"Required;MaxSize(10)"` + Remember bool +} + +func (f *PhoneNumberCodeForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { + return validate(errs, ctx.Data, f, ctx.Locale) +} + +type ResetPassWordByPhoneForm struct { + PhoneNumber string `binding:"Required;MaxSize(20)"` + VerifyCode string `binding:"Required;MaxSize(10)"` + Password string `binding:"MaxSize(255)"` + Remember bool +} + +func (f *ResetPassWordByPhoneForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { + return validate(errs, ctx.Data, f, ctx.Locale) +} + +type SlideImageForm struct { + SlideID string `binding:"Required"` + X int `binding:"Required"` +} + +func (f *SlideImageForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { + return validate(errs, ctx.Data, f, ctx.Locale) +} diff --git a/modules/cloudbrain/cloudbrain.go b/modules/cloudbrain/cloudbrain.go index 430304dd5..6cbb97999 100755 --- a/modules/cloudbrain/cloudbrain.go +++ b/modules/cloudbrain/cloudbrain.go @@ -3,6 +3,7 @@ package cloudbrain import ( "encoding/json" "errors" + "os" "strconv" "code.gitea.io/gitea/modules/timeutil" @@ -17,7 +18,7 @@ import ( ) const ( - Command = `pip3 install jupyterlab==2.2.5 -i https://pypi.tuna.tsinghua.edu.cn/simple;service ssh stop;jupyter lab --no-browser --ip=0.0.0.0 --allow-root --notebook-dir="/code" --port=80 --LabApp.token="" --LabApp.allow_origin="self https://cloudbrain.pcl.ac.cn"` + //Command = `pip3 install jupyterlab==2.2.5 -i https://pypi.tuna.tsinghua.edu.cn/simple;service ssh stop;jupyter lab --no-browser --ip=0.0.0.0 --allow-root --notebook-dir="/code" --port=80 --LabApp.token="" --LabApp.allow_origin="self https://cloudbrain.pcl.ac.cn"` //CommandBenchmark = `echo "start benchmark";python /code/test.py;echo "end benchmark"` CommandBenchmark = `echo "start benchmark";cd /benchmark && bash run_bk.sh;echo "end benchmark"` CodeMountPath = "/code" @@ -37,11 +38,15 @@ const ( Success = "S000" DefaultBranchName = "master" + + ResultPath = "/result" ) var ( - ResourceSpecs *models.ResourceSpecs - TrainResourceSpecs *models.ResourceSpecs + ResourceSpecs *models.ResourceSpecs + TrainResourceSpecs *models.ResourceSpecs + InferenceResourceSpecs *models.ResourceSpecs + SpecialPools *models.SpecialPools ) type GenerateCloudBrainTaskReq struct { @@ -68,6 +73,17 @@ type GenerateCloudBrainTaskReq struct { BenchmarkTypeID int BenchmarkChildTypeID int ResourceSpecId int + ResultPath string + TrainUrl string + ModelName string + ModelVersion string + CkptName string + LabelName string +} + +func GetCloudbrainDebugCommand() string { + var command = `pip3 install jupyterlab==3 -i https://pypi.tuna.tsinghua.edu.cn/simple;service ssh stop;jupyter lab --ServerApp.shutdown_no_activity_timeout=` + setting.CullIdleTimeout + ` --TerminalManager.cull_inactive_timeout=` + setting.CullIdleTimeout + ` --TerminalManager.cull_interval=` + setting.CullInterval + ` --MappingKernelManager.cull_idle_timeout=` + setting.CullIdleTimeout + ` --MappingKernelManager.cull_interval=` + setting.CullInterval + ` --MappingKernelManager.cull_connected=True --MappingKernelManager.cull_busy=True --no-browser --ip=0.0.0.0 --allow-root --notebook-dir="/code" --port=80 --ServerApp.token="" --ServerApp.allow_origin="self https://cloudbrain.pcl.ac.cn" ` + return command } func isAdminOrOwnerOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool { @@ -213,7 +229,6 @@ func AdminOrImageCreaterRight(ctx *context.Context) { func GenerateTask(req GenerateCloudBrainTaskReq) error { var resourceSpec *models.ResourceSpec var versionCount int - if req.JobType == string(models.JobTypeTrain) { versionCount = 1 if TrainResourceSpecs == nil { @@ -222,8 +237,20 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { for _, spec := range TrainResourceSpecs.ResourceSpec { if req.ResourceSpecId == spec.Id { resourceSpec = spec + break + } + } + } else if req.JobType == string(models.JobTypeInference) { + if InferenceResourceSpecs == nil { + json.Unmarshal([]byte(setting.InferenceResourceSpecs), &InferenceResourceSpecs) + } + for _, spec := range InferenceResourceSpecs.ResourceSpec { + if req.ResourceSpecId == spec.Id { + resourceSpec = spec + break } } + } else { if ResourceSpecs == nil { json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs) @@ -231,10 +258,15 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { for _, spec := range ResourceSpecs.ResourceSpec { if req.ResourceSpecId == spec.Id { resourceSpec = spec + break } } } + //如果没有匹配到spec信息,尝试从专属资源池获取 + if resourceSpec == nil && SpecialPools != nil { + resourceSpec = geMatchResourceSpec(req.JobType, req.GpuQueue, req.ResourceSpecId) + } if resourceSpec == nil { log.Error("no such resourceSpecId(%d)", req.ResourceSpecId, req.Ctx.Data["MsgID"]) @@ -277,6 +309,13 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { ReadOnly: true, }, }, + { + HostPath: models.StHostPath{ + Path: req.ResultPath, + MountPath: ResultPath, + ReadOnly: false, + }, + }, } if len(req.DatasetInfos) == 1 { @@ -357,6 +396,12 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { BootFile: req.BootFile, DatasetName: req.DatasetNames, Parameters: req.Params, + TrainUrl: req.TrainUrl, + ModelName: req.ModelName, + ModelVersion: req.ModelVersion, + CkptName: req.CkptName, + ResultUrl: req.ResultPath, + LabelName: req.LabelName, CreatedUnix: createTime, UpdatedUnix: createTime, CommitID: req.CommitID, @@ -377,6 +422,8 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { notification.NotifyOtherTask(req.Ctx.User, req.Ctx.Repo.Repository, stringId, req.DisplayJobName, models.ActionCreateBenchMarkTask) } else if string(models.JobTypeTrain) == req.JobType { notification.NotifyOtherTask(req.Ctx.User, req.Ctx.Repo.Repository, jobID, req.DisplayJobName, models.ActionCreateGPUTrainTask) + } else if string(models.JobTypeInference) == req.JobType { + notification.NotifyOtherTask(req.Ctx.User, req.Ctx.Repo.Repository, jobID, req.DisplayJobName, models.ActionCreateInferenceTask) } else { notification.NotifyOtherTask(req.Ctx.User, req.Ctx.Repo.Repository, stringId, req.DisplayJobName, models.ActionCreateDebugGPUTask) } @@ -388,6 +435,15 @@ func IsBenchmarkJob(jobType string) bool { return string(models.JobTypeBenchmark) == jobType || string(models.JobTypeBrainScore) == jobType || string(models.JobTypeSnn4imagenet) == jobType } +func GetWaitingCloudbrainCount(cloudbrainType int, computeResource string, jobTypes ...models.JobType) int64 { + num, err := models.GetWaitingCloudbrainCount(cloudbrainType, computeResource, jobTypes...) + if err != nil { + log.Warn("Get waiting count err", err) + num = 0 + } + return num +} + func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) error { jobName := task.JobName @@ -401,6 +457,11 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e } } + //如果没有匹配到spec信息,尝试从专属资源池获取 + if resourceSpec == nil && SpecialPools != nil { + resourceSpec = geMatchResourceSpec(task.JobType, task.GpuQueue, task.ResourceSpecId) + } + if resourceSpec == nil { log.Error("no such resourceSpecId(%d)", task.ResourceSpecId, ctx.Data["MsgID"]) return errors.New("no such resourceSpec") @@ -486,7 +547,7 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e GPUNumber: resourceSpec.GpuNum, MemoryMB: resourceSpec.MemMiB, ShmMB: resourceSpec.ShareMemMiB, - Command: Command, + Command: GetCloudbrainDebugCommand(),//Command, NeedIBDevice: false, IsMainRole: false, UseNNI: false, @@ -538,3 +599,96 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e return nil } + +func geMatchResourceSpec(jobType string, gpuQueue string, resourceSpecId int) *models.ResourceSpec { + + for _, specialPool := range SpecialPools.Pools { + + if specialPool.ResourceSpec != nil { + if IsElementExist(specialPool.JobType, jobType) && IsQueueInSpecialtPool(specialPool.Pool, gpuQueue) { + for _, spec := range specialPool.ResourceSpec { + if resourceSpecId == spec.Id { + return spec + } + } + } + } + } + return nil +} + +func DelCloudBrainJob(jobId string) string { + task, err := models.GetCloudbrainByJobID(jobId) + if err != nil { + log.Error("get cloud brain err:", err) + return "cloudbrain.Delete_failed" + + } + if task.Status != string(models.JobStopped) && task.Status != string(models.JobFailed) && task.Status != string(models.JobSucceeded) { + log.Error("the job(%s) has not been stopped", task.JobName) + return "cloudbrain.Not_Stopped" + } + + err = models.DeleteJob(task) + if err != nil { + log.Error("DeleteJob failed:", err) + return "cloudbrain.Delete_failed" + } + + deleteJobStorage(task.JobName) + + return "" +} + +func deleteJobStorage(jobName string) error { + //delete local + localJobPath := setting.JobPath + jobName + err := os.RemoveAll(localJobPath) + if err != nil { + log.Error("RemoveAll(%s) failed:%v", localJobPath, err) + } + + dirPath := setting.CBCodePathPrefix + jobName + "/" + err = storage.Attachments.DeleteDir(dirPath) + if err != nil { + log.Error("DeleteDir(%s) failed:%v", localJobPath, err) + } + + return nil +} + +func InitSpecialPool() { + if SpecialPools == nil && setting.SpecialPools != "" { + json.Unmarshal([]byte(setting.SpecialPools), &SpecialPools) + } +} + +func IsResourceSpecInSpecialPool(resourceSpecs []*models.ResourceSpec, resourceSpecId int) bool { + if resourceSpecs == nil || len(resourceSpecs) == 0 { + return true + } + for _, v := range resourceSpecs { + if v.Id == resourceSpecId { + return true + } + } + return false +} + +func IsQueueInSpecialtPool(pool []*models.GpuInfo, queue string) bool { + for _, v := range pool { + if v.Queue == queue { + return true + } + } + return false +} + +func IsElementExist(s []string, str string) bool { + for _, v := range s { + if v == str { + return true + } + } + return false +} diff --git a/modules/cloudbrain/resty.go b/modules/cloudbrain/resty.go index e70dbdd2b..7b714c4b5 100755 --- a/modules/cloudbrain/resty.go +++ b/modules/cloudbrain/resty.go @@ -30,6 +30,7 @@ const ( LogPageSize = 500 LogPageTokenExpired = "5m" pageSize = 15 + QueuesDetailUrl = "/rest-server/api/v2/queuesdetail" ) func getRestyClient() *resty.Client { @@ -73,12 +74,44 @@ func loginCloudbrain() error { return nil } +func GetQueuesDetail() (*map[string]int, error) { + checkSetting() + client := getRestyClient() + var jobResult models.QueueDetailResult + + var result = make(map[string]int, 0) + + res, err := client.R(). + SetHeader("Content-Type", "application/json"). + SetAuthToken(TOKEN). + SetResult(&jobResult). + Get(HOST + QueuesDetailUrl) + + if err != nil { + return nil, fmt.Errorf("resty get queues detail failed: %s", err) + } + + if jobResult.Code != Success { + return nil, fmt.Errorf("jobResult err: %s", res.String()) + } + + for k, v := range jobResult.Payload { + + result[k] = v.JobScheduleInfo.Pending + + } + return &result, nil + +} + func CreateJob(jobName string, createJobParams models.CreateJobParams) (*models.CreateJobResult, error) { checkSetting() client := getRestyClient() var jobResult models.CreateJobResult retry := 0 + reqPara, _ := json.Marshal(createJobParams) + log.Warn("job req:", string(reqPara[:])) sendjob: res, err := client.R(). @@ -143,16 +176,6 @@ sendjob: return &getJobResult, nil } -func GetImages() (*models.GetImagesResult, error) { - - return GetImagesPageable(1, 100, Custom, "") - -} - -func GetPublicImages() (*models.GetImagesResult, error) { - return GetImagesPageable(1, 100, Public, "") -} - func GetImagesPageable(page int, size int, imageType string, name string) (*models.GetImagesResult, error) { checkSetting() client := getRestyClient() diff --git a/modules/context/auth.go b/modules/context/auth.go index 287823dea..efde3bc2e 100755 --- a/modules/context/auth.go +++ b/modules/context/auth.go @@ -53,6 +53,10 @@ func Toggle(options *ToggleOptions) macaron.Handler { ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") ctx.HTML(200, "user/auth/prohibit_login") return + } else if setting.PhoneService.Enabled && ctx.User.IsActive && ctx.User.PhoneNumber == "" && ctx.Req.URL.Path != "/bindPhone" { + ctx.Data["Title"] = ctx.Tr("phone.bind_phone") + ctx.HTML(200, "user/auth/bind_phone") + return } if ctx.User.MustChangePassword { diff --git a/modules/grampus/grampus.go b/modules/grampus/grampus.go index e83ccccc6..caaae4e8e 100755 --- a/modules/grampus/grampus.go +++ b/modules/grampus/grampus.go @@ -65,6 +65,7 @@ type GenerateTrainJobReq struct { EngineName string TotalVersionCount int ComputeResource string + ProcessType string DatasetName string Params string } @@ -72,25 +73,7 @@ type GenerateTrainJobReq struct { func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error) { createTime := timeutil.TimeStampNow() - var CenterID []string - var CenterName []string - - if SpecialPools != nil { - for _, pool := range SpecialPools.Pools { - if !pool.IsExclusive && strings.Contains(req.ComputeResource, pool.Type) { - org, _ := models.GetOrgByName(pool.Org) - if org != nil { - isOrgMember, _ := models.IsOrganizationMember(org.ID, ctx.User.ID) - if isOrgMember { - for _, info := range pool.Pool { - CenterID = append(CenterID, info.Queue) - CenterName = append(CenterName, info.Value) - } - } - } - } - } - } + centerID, centerName := getCentersParamter(ctx, req) jobResult, err := createJob(models.CreateGrampusJobRequest{ Name: req.JobName, @@ -101,8 +84,8 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error ResourceSpecId: req.ResourceSpecId, ImageId: req.ImageId, ImageUrl: req.ImageUrl, - CenterID: CenterID, - CenterName: CenterName, + CenterID: centerID, + CenterName: centerName, ReplicaNum: 1, }, }, @@ -160,6 +143,66 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error return nil } +func getCentersParamter(ctx *context.Context, req *GenerateTrainJobReq) ([]string, []string) { + var centerID []string + var centerName []string + + includeCenters := make(map[string]string) + excludeCenters := make(map[string]string) + + if SpecialPools != nil { + for _, pool := range SpecialPools.Pools { + if !pool.IsExclusive && strings.Contains(req.ComputeResource, pool.Type) { + org, _ := models.GetOrgByName(pool.Org) + if org != nil { + isOrgMember, _ := models.IsOrganizationMember(org.ID, ctx.User.ID) + if isOrgMember { + for _, info := range pool.Pool { + includeCenters[info.Queue] = info.Value + } + } else { + for _, info := range pool.Pool { + excludeCenters[info.Queue] = info.Value + } + } + } + } + } + + } + + if len(includeCenters) > 0 { + //如果有专属资源池,根据专属资源池指定智算中心 + for k, v := range includeCenters { + centerID = append(centerID, k) + centerName = append(centerName, v) + } + } else if len(excludeCenters) > 0 { + //否则,有要排除的中心,先获取所有中心,删除其中的排除中心,得到指定的智算中心 + allCenters := make(map[string]string) + specs, err := GetResourceSpecs(req.ProcessType) + if err == nil { + for _, info := range specs.Infos { + for _, center := range info.Centers { + allCenters[center.ID] = center.Name + } + + } + } + + for k, _ := range excludeCenters { + delete(allCenters, k) + } + + for k, v := range allCenters { + centerID = append(centerID, k) + centerName = append(centerName, v) + } + + } + return centerID, centerName +} + func TransTrainJobStatus(status string) string { if status == models.GrampusStatusPending { status = models.GrampusStatusWaiting diff --git a/modules/modelarts/modelarts.go b/modules/modelarts/modelarts.go index 79aeb4cb0..1f39d0fac 100755 --- a/modules/modelarts/modelarts.go +++ b/modules/modelarts/modelarts.go @@ -19,14 +19,14 @@ import ( const ( //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 // ResourcePools = "{\"resource_pool\":[{\"id\":\"pool1328035d\", \"value\":\"专属资源池\"}]}" @@ -98,6 +98,8 @@ type GenerateTrainJobReq struct { VersionCount int EngineName string TotalVersionCount int + UserImageUrl string + UserCommand string DatasetName string } @@ -136,6 +138,7 @@ type VersionInfo struct { Version []struct { ID int `json:"id"` Value string `json:"value"` + Url string `json:"url"` } `json:"version"` } @@ -314,15 +317,107 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error) { 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, Description: req.Description, - Config: models.Config{ + Config: models.UserImageConfig{ WorkServerNum: req.WorkServerNumber, AppUrl: req.CodeObsPath, BootFileUrl: req.BootFileUrl, DataUrl: req.DataUrl, - EngineID: req.EngineID, TrainUrl: req.TrainUrl, LogUrl: req.LogUrl, PoolID: req.PoolID, @@ -330,20 +425,83 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error Flavor: models.Flavor{ 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), UserID: ctx.User.ID, RepoID: ctx.Repo.Repository.ID, - JobID: jobId, + JobID: strconv.FormatInt(jobResult.JobID, 10), JobName: req.JobName, DisplayJobName: req.DisplayJobName, JobType: string(models.JobTypeTrain), @@ -354,6 +512,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error DatasetName: req.DatasetName, CommitID: req.CommitID, IsLatestVersion: req.IsLatestVersion, + PreVersionName: req.PreVersionName, ComputeResource: models.NPUResource, EngineID: req.EngineID, TrainUrl: req.TrainUrl, @@ -362,45 +521,54 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error BootFile: req.BootFile, DataUrl: req.DataUrl, LogUrl: req.LogUrl, + PreVersionId: req.PreVersionId, FlavorCode: req.FlavorCode, Description: req.Description, WorkServerNumber: req.WorkServerNumber, FlavorName: req.FlavorName, EngineName: req.EngineName, - VersionCount: req.VersionCount, - TotalVersionCount: req.TotalVersionCount, + TotalVersionCount: VersionTaskList[0].TotalVersionCount + 1, + VersionCount: VersionListCount + 1, CreatedUnix: 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() - jobResult, err := createTrainJobVersion(models.CreateTrainJobVersionParams{ + jobResult, err := createTrainJobUserImage(models.CreateUserImageTrainJobParams{ + JobName: req.JobName, Description: req.Description, - Config: models.TrainJobVersionConfig{ + Config: models.UserImageConfig{ 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, - PreVersionId: req.PreVersionId, + UserImageUrl: req.UserImageUrl, + UserCommand: req.UserCommand, }, - }, jobId) + }) if err != nil { log.Error("CreateJob failed: %v", err.Error()) return err @@ -438,7 +606,8 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job IsLatestVersion: req.IsLatestVersion, PreVersionName: req.PreVersionName, ComputeResource: models.NPUResource, - EngineID: req.EngineID, + EngineID: MORDELART_USER_IMAGE_ENGINE_ID, + Image: req.UserImageUrl, TrainUrl: req.TrainUrl, BranchName: req.BranchName, Parameters: req.Params, diff --git a/modules/modelarts/resty.go b/modules/modelarts/resty.go index 6a2803cb1..46c273a8b 100755 --- a/modules/modelarts/resty.go +++ b/modules/modelarts/resty.go @@ -472,6 +472,62 @@ sendjob: 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) { checkSetting() client := getRestyClient() @@ -583,6 +639,61 @@ sendjob: 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) { checkSetting() client := getRestyClient() diff --git a/modules/phone/phone.go b/modules/phone/phone.go new file mode 100644 index 000000000..9349a75ec --- /dev/null +++ b/modules/phone/phone.go @@ -0,0 +1,61 @@ +package phone + +import ( + "math" + "math/rand" + "regexp" + "strconv" + "time" + + "code.gitea.io/gitea/modules/setting" + + openapi "github.com/alibabacloud-go/darabonba-openapi/client" + dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20170525/v2/client" + util "github.com/alibabacloud-go/tea-utils/service" + "github.com/alibabacloud-go/tea/tea" +) + +func IsValidPhoneNumber(phoneNumber string) bool { + pattern := "^1[3-9]\\d{9}$" + match, _ := regexp.MatchString(pattern, phoneNumber) + return match +} + +func GenerateVerifyCode(n int) string { + min := int(math.Pow10(n - 1)) + max := int(math.Pow10(n)) + rand.Seed(time.Now().UnixNano()) + return strconv.Itoa(rand.Intn(max-min) + min) + +} + +func createClient(accessKeyId *string, accessKeySecret *string) (_result *dysmsapi20170525.Client, _err error) { + config := &openapi.Config{ + // 您的AccessKey ID + AccessKeyId: accessKeyId, + // 您的AccessKey Secret + AccessKeySecret: accessKeySecret, + } + // 访问的域名 + config.Endpoint = tea.String("dysmsapi.aliyuncs.com") + _result = &dysmsapi20170525.Client{} + _result, _err = dysmsapi20170525.NewClient(config) + return _result, _err +} + +func SendVerifyCode(phoneNumber string, verifyCode string) error { + client, _err := createClient(&setting.PhoneService.AccessKeyId, &setting.PhoneService.AccessKeySecret) + if _err != nil { + return _err + } + + sendSmsRequest := &dysmsapi20170525.SendSmsRequest{ + SignName: tea.String(setting.PhoneService.SignName), + TemplateCode: tea.String(setting.PhoneService.TemplateCode), + PhoneNumbers: tea.String(phoneNumber), + TemplateParam: tea.String("{\"code\":\"" + verifyCode + "\"}"), + } + runtime := &util.RuntimeOptions{} + _, _err = client.SendSmsWithOptions(sendSmsRequest, runtime) + return _err +} diff --git a/modules/public/dynamic.go b/modules/public/dynamic.go index 07f83e1f6..4f10895a1 100644 --- a/modules/public/dynamic.go +++ b/modules/public/dynamic.go @@ -7,10 +7,53 @@ package public import ( + "fmt" + "io/ioutil" + "os" + "path" + + "code.gitea.io/gitea/modules/setting" "gitea.com/macaron/macaron" + "github.com/unknwon/com" ) // Static implements the macaron static handler for serving assets. func Static(opts *Options) macaron.Handler { return opts.staticHandler(opts.Directory) } + +func Dir(name string) ([]string, error) { + + var ( + result []string + ) + + staticDir := path.Join(setting.StaticRootPath, "public", name) + + if com.IsDir(staticDir) { + files, err := com.StatDir(staticDir, true) + + if err != nil { + return []string{}, fmt.Errorf("Failed to read img directory. %v", err) + } + + result = append(result, files...) + } + + return result, nil +} + +func Asset(name string) ([]byte, error) { + + staticPath := path.Join(setting.StaticRootPath, "public", name) + + if com.IsFile(staticPath) { + f, err := os.Open(staticPath) + defer f.Close() + + if err == nil { + return ioutil.ReadAll(f) + } + } + return nil, fmt.Errorf("Asset file does not exist: %s", name) +} diff --git a/modules/public/static.go b/modules/public/static.go index 76050632c..6eac8a751 100644 --- a/modules/public/static.go +++ b/modules/public/static.go @@ -7,6 +7,7 @@ package public import ( + "fmt" "io/ioutil" "gitea.com/macaron/macaron" @@ -20,6 +21,16 @@ func Static(opts *Options) macaron.Handler { return opts.staticHandler("") } +func Dir(name string) ([]string, error) { + + files, err := AssetDir(name) + if err != nil { + return []string{}, fmt.Errorf("Failed to read embedded directory. %v", err) + } + + return files, nil +} + func Asset(name string) ([]byte, error) { f, err := Assets.Open("/" + name) if err != nil { @@ -29,6 +40,24 @@ func Asset(name string) ([]byte, error) { return ioutil.ReadAll(f) } +func AssetDir(dirName string) ([]string, error) { + d, err := Assets.Open(dirName) + if err != nil { + return nil, err + } + defer d.Close() + + files, err := d.Readdir(-1) + if err != nil { + return nil, err + } + var results = make([]string, 0, len(files)) + for _, file := range files { + results = append(results, file.Name()) + } + return results, nil +} + func AssetNames() []string { realFS := Assets.(vfsgen۰FS) var results = make([]string, 0, len(realFS)) diff --git a/modules/redis/redis_client/client.go b/modules/redis/redis_client/client.go index 437aecdae..ebcff4930 100644 --- a/modules/redis/redis_client/client.go +++ b/modules/redis/redis_client/client.go @@ -41,6 +41,66 @@ func Setnx(key, value string, timeout time.Duration) (bool, error) { } +func SETNX(conn redis.Conn, key, value string, seconds int) (bool, error) { + reply, err := conn.Do("SET", key, value, "NX", "EX", seconds) + return redis.Bool(reply, err) + +} + +func SET(conn redis.Conn, key, value string, seconds int) (bool, error) { + reply, err := conn.Do("SETEX", key, seconds, value) + return redis.Bool(reply, err) + +} + +func HSETNX(conn redis.Conn, key, subKey string, value interface{}) error { + _, err := conn.Do("HSETNX", key, subKey, value) + return err + +} + +func HGET(conn redis.Conn, key, subKey string) (interface{}, error) { + return conn.Do("HGET", key, subKey) +} +func EXISTS(conn redis.Conn, key string) (bool, error) { + + reply, err := conn.Do("EXISTS", key) + return redis.Bool(reply, err) + +} + +func HEXISTS(conn redis.Conn, key string, subKey string) (bool, error) { + + reply, err := conn.Do("HEXISTS", key, subKey) + return redis.Bool(reply, err) + +} + +func Expire(conn redis.Conn, key string, seconds int) error { + _, err := conn.Do("EXPIRE", key, seconds) + return err + +} + +func HINCRBY(conn redis.Conn, key, subKey string, value int) error { + _, err := conn.Do("HINCRBY", key, subKey, value) + return err +} +func GET(conn redis.Conn, key string) (interface{}, error) { + return conn.Do("GET", key) +} + +func Ttl(conn redis.Conn, key string) (int, error) { + + reply, err := conn.Do("TTL", key) + if err != nil { + return 0, err + } + n, _ := strconv.Atoi(fmt.Sprint(reply)) + return n, nil + +} + func Get(key string) (string, error) { redisClient := labelmsg.Get() defer redisClient.Close() diff --git a/modules/setting/phone.go b/modules/setting/phone.go new file mode 100644 index 000000000..16b4ebf19 --- /dev/null +++ b/modules/setting/phone.go @@ -0,0 +1,47 @@ +package setting + +import ( + "code.gitea.io/gitea/modules/log" +) + +type Phone struct { + Enabled bool + VerifyCodeLength int + AccessKeyId string + AccessKeySecret string + SignName string + TemplateCode string + CodeTimeout int + RetryInterval int + MaxRetryTimes int +} + +var ( + // Phone verify info + PhoneService *Phone +) + +func newPhoneService() { + sec := Cfg.Section("phone") + // Check phone setting. + if !sec.Key("ENABLED").MustBool() { + PhoneService = &Phone{ + Enabled: sec.Key("ENABLED").MustBool(), + } + return + } + + PhoneService = &Phone{ + Enabled: sec.Key("ENABLED").MustBool(), + VerifyCodeLength: sec.Key("VERIFY_CODE_LEN").MustInt(6), + AccessKeyId: sec.Key("AccessKeyId").String(), + AccessKeySecret: sec.Key("AccessKeySecret").String(), + SignName: sec.Key("SignName").String(), + TemplateCode: sec.Key("TemplateCode").String(), + CodeTimeout: sec.Key("CODE_TIMEOUT").MustInt(60 * 5), + RetryInterval: sec.Key("RETRY_INTERVAL").MustInt(60 * 2), + MaxRetryTimes: sec.Key("MAX_RETRY").MustInt(5), + } + + log.Info("Phone Service Enabled") +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 2058c51a8..6ec54fdff 100755 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -7,6 +7,7 @@ package setting import ( "encoding/base64" + "encoding/json" "fmt" "io" "io/ioutil" @@ -64,7 +65,16 @@ const ( ReCaptcha = "recaptcha" ) -// settings +type C2NetSequenceInfo struct { + ID int `json:"id"` + Name string `json:"name"` + Content string `json:"content"` +} + +type C2NetSqInfos struct { + C2NetSqInfo []*C2NetSequenceInfo `json:"sequence"` +} + var ( // AppVer settings AppVer string @@ -453,19 +463,26 @@ var ( DecompressOBSTaskName string //cloudbrain config - CBAuthUser string - CBAuthPassword string - RestServerHost string - JobPath string - CBCodePathPrefix string - JobType string - GpuTypes string - DebugServerHost string - ResourceSpecs string - MaxDuration int64 - TrainGpuTypes string - TrainResourceSpecs string - MaxDatasetNum int + + CBAuthUser string + CBAuthPassword string + RestServerHost string + JobPath string + CBCodePathPrefix string + JobType string + GpuTypes string + SpecialPools string + DebugServerHost string + ResourceSpecs string + MaxDuration int64 + TrainGpuTypes string + TrainResourceSpecs string + InferenceGpuTypes string + InferenceResourceSpecs string + MaxModelSize float64 + MaxDatasetNum int + CullIdleTimeout string + CullInterval string //benchmark config IsBenchmarkEnabled bool @@ -531,13 +548,16 @@ var ( //grampus config Grampus = struct { - Env string - Host string - UserName string - Password string - SpecialPools string + Env string + Host string + UserName string + Password string + SpecialPools string + C2NetSequence string }{} + C2NetInfos *C2NetSqInfos + //elk config ElkUrl string ElkUser string @@ -612,6 +632,24 @@ var ( OrgName 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. @@ -1311,7 +1349,14 @@ func NewContext() { MaxDuration = sec.Key("MAX_DURATION").MustInt64(14400) TrainGpuTypes = sec.Key("TRAIN_GPU_TYPES").MustString("") TrainResourceSpecs = sec.Key("TRAIN_RESOURCE_SPECS").MustString("") + MaxModelSize = sec.Key("MAX_MODEL_SIZE").MustFloat64(500) + InferenceGpuTypes = sec.Key("INFERENCE_GPU_TYPES").MustString("") + InferenceResourceSpecs = sec.Key("INFERENCE_RESOURCE_SPECS").MustString("") + SpecialPools = sec.Key("SPECIAL_POOL").MustString("") + MaxDatasetNum = sec.Key("MAX_DATASET_NUM").MustInt(5) + CullIdleTimeout = sec.Key("CULL_IDLE_TIMEOUT").MustString("900") + CullInterval = sec.Key("CULL_INTERVAL").MustString("60") sec = Cfg.Section("benchmark") IsBenchmarkEnabled = sec.Key("ENABLED").MustBool(false) @@ -1406,6 +1451,27 @@ func NewContext() { Course.TeamName = sec.Key("team_name").MustString("") 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() { @@ -1416,7 +1482,12 @@ func GetGrampusConfig() { Grampus.UserName = sec.Key("USERNAME").MustString("") Grampus.Password = sec.Key("PASSWORD").MustString("") Grampus.SpecialPools = sec.Key("SPECIAL_POOL").MustString("") - + Grampus.C2NetSequence = sec.Key("C2NET_SEQUENCE").MustString("{\"sequence\":[{\"id\":1,\"name\":\"cloudbrain_one\",\"content\":\"鹏城云脑一号\"},{\"id\":2,\"name\":\"cloudbrain_two\",\"content\":\"鹏城云脑二号\"},{\"id\":3,\"name\":\"beida\",\"content\":\"北大人工智能集群系统\"},{\"id\":4,\"name\":\"hefei\",\"content\":\"合肥类脑智能开放平台\"},{\"id\":5,\"name\":\"wuhan\",\"content\":\"武汉人工智能计算中心\"},{\"id\":6,\"name\":\"xian\",\"content\":\"西安未来人工智能计算中心\"},{\"id\":7,\"pclcci\":\"more\",\"content\":\"鹏城云计算所\"},{\"id\":8,\"name\":\"xuchang\",\"content\":\"中原人工智能计算中心\"},{\"id\":9,\"name\":\"chengdu\",\"content\":\"成都人工智能计算中心\"},{\"id\":10,\"name\":\"more\",\"content\":\"横琴先进智能计算中心\"},{\"id\":11,\"name\":\"more\",\"content\":\"国家超级计算济南中心\"}]}") + if Grampus.C2NetSequence != "" { + if err := json.Unmarshal([]byte(Grampus.C2NetSequence), &C2NetInfos); err != nil { + log.Error("Unmarshal(C2NetSequence) failed:%v", err) + } + } } func SetRadarMapConfig() { @@ -1554,4 +1625,5 @@ func NewServices() { newIndexerService() newTaskService() NewQueueService() + newPhoneService() } diff --git a/modules/setting/slideimage.go b/modules/setting/slideimage.go new file mode 100644 index 000000000..c68beb185 --- /dev/null +++ b/modules/setting/slideimage.go @@ -0,0 +1,12 @@ +package setting + +import ( + "image" +) + +var ( + // the original images for generate slide image + SlideImagesBg []*image.Image + SlideMaskImage *image.Image + SlideImagesCount int +) diff --git a/modules/slideimage/slideimage.go b/modules/slideimage/slideimage.go new file mode 100644 index 000000000..748cc2d6c --- /dev/null +++ b/modules/slideimage/slideimage.go @@ -0,0 +1,308 @@ +package slideimage + +import ( + "bytes" + "image" + "image/png" + "math" + "math/rand" + "path" + "strconv" + "strings" + "time" + + "code.gitea.io/gitea/modules/labelmsg" + "github.com/gomodule/redigo/redis" + + "code.gitea.io/gitea/modules/public" + + "code.gitea.io/gitea/modules/log" + + "code.gitea.io/gitea/modules/setting" + + "code.gitea.io/gitea/modules/redis/redis_client" + + "gitea.com/macaron/macaron" + "github.com/disintegration/imaging" + "github.com/google/uuid" +) + +type SlideImage struct { + SubURL string + URLPrefix string + SampleImages int + StdWidth int + StdHeight int + MaskSize int + ImageY int + ImageXStart int + MinImageX int + Expiration int + Tolerance int + CachePrefix string + CacheManualPrefix string +} + +type Options struct { + // Suburl path. Default is empty. + SubURL string + // URL prefix of getting captcha pictures. Default is "/slideimage/". + URLPrefix string + //Default is 4 + SampleImages int + //Image width default 391 + StdWidth int + //Image Height default 196 + StdHeight int + // default 51 + MaskSize int + // default 125 + ImageY int + //default 0 + ImageXStart int + //容忍的误差 default 2px + Tolerance int + // default 150 + MinImageX int + // default 600 seconds + Expiration int + //default slide: + CachePrefix string + //default mslide: 验证通过,在缓存中记录已进行过人工操作,然后在发送验证码之前再进行校验是否进行了人工操作。 + CacheManualPrefix string +} + +func NewSlideImage(opt Options) *SlideImage { + return &SlideImage{ + SubURL: opt.SubURL, + URLPrefix: opt.URLPrefix, + SampleImages: opt.SampleImages, + StdWidth: opt.StdWidth, + StdHeight: opt.StdHeight, + MaskSize: opt.MaskSize, + ImageY: opt.ImageY, + ImageXStart: opt.ImageXStart, + Tolerance: opt.Tolerance, + MinImageX: opt.MinImageX, + Expiration: opt.Expiration, + CachePrefix: opt.CachePrefix, + } +} + +func prepareOptions(options []Options) Options { + var opt Options + if len(options) > 0 { + opt = options[0] + } + + opt.SubURL = strings.TrimSuffix(opt.SubURL, "/") + + // Defaults. + if len(opt.URLPrefix) == 0 { + opt.URLPrefix = "/slideimage/" + } else if opt.URLPrefix[len(opt.URLPrefix)-1] != '/' { + opt.URLPrefix += "/" + } + if opt.SampleImages == 0 { + opt.SampleImages = 4 + } + if opt.StdWidth == 0 { + opt.StdWidth = 391 + } + if opt.StdHeight == 0 { + opt.StdHeight = 196 + } + if opt.MaskSize == 0 { + opt.MaskSize = 51 + } + if opt.ImageY == 0 { + opt.ImageY = 75 + } + if opt.ImageXStart == 0 { + opt.ImageXStart = 2 + } + + if opt.Tolerance == 0 { + opt.Tolerance = 2 + } + + if opt.MinImageX == 0 { + opt.MinImageX = 150 + } + if opt.Expiration == 0 { + opt.Expiration = 600 + } + + if len(opt.CachePrefix) == 0 { + opt.CachePrefix = "slide:" + } + if len(opt.CacheManualPrefix) == 0 { + opt.CacheManualPrefix = "mslide:" + } + + return opt +} + +func (s *SlideImage) key(id string) string { + return s.CachePrefix + id +} +func (s *SlideImage) mkey(id string) string { + return s.CacheManualPrefix + id +} + +func (s *SlideImage) VerifyManual(id string) (bool, error) { + redisConn := labelmsg.Get() + defer redisConn.Close() + return redis_client.EXISTS(redisConn, s.mkey(id)) +} + +func (s *SlideImage) Verify(id string, x int) bool { + redisConn := labelmsg.Get() + defer redisConn.Close() + + v, err := redis_client.GET(redisConn, s.key(id)) + v1, err := redis.String(v, err) + if err != nil { + log.Warn("redis err", err) + return false + } + if v1 == "" { + return false + } + values := strings.Split(v1, "-") + imageRandX, _ := strconv.Atoi(values[1]) + if int(math.Abs(float64(imageRandX-x))) <= s.Tolerance { + redis_client.SETNX(redisConn, s.mkey(id), "1", s.Expiration) + return true + } + return false + +} + +func (s *SlideImage) CreateCode() (string, int, int) { + nums := rand.Intn(s.SampleImages) + imageId := uuid.New().String() + + //获取随机x坐标 + imageRandX := rand.Intn(s.StdWidth - s.MaskSize - 3) + if imageRandX < s.MinImageX { + imageRandX += s.MinImageX + } + redis_client.Setex(s.key(imageId), strconv.Itoa(nums)+"-"+strconv.Itoa(imageRandX), time.Second*time.Duration(s.Expiration)) + return imageId, nums, imageRandX +} + +func SlideImager(options ...Options) macaron.Handler { + return func(ctx *macaron.Context) { + slideImage := NewSlideImage(prepareOptions(options)) + + if strings.HasPrefix(ctx.Req.URL.Path, slideImage.URLPrefix) { + id := path.Base(ctx.Req.URL.Path) + if i := strings.Index(id, "."); i > -1 { + id = id[:i] + } + isScreenshot := strings.HasSuffix(id, "screenshot") + if isScreenshot { + id = strings.TrimSuffix(id, "screenshot") + } + + key := slideImage.key(id) + v, err := redis_client.Get(key) + + if err != nil || v == "" { + ctx.Status(404) + ctx.Write([]byte("not found")) + //png.Encode(ctx.Resp, *setting.SlideImagesBg[0]) + return + } + + values := strings.Split(v, "-") + + imageIndex, _ := strconv.Atoi(values[0]) + imageRandX, _ := strconv.Atoi(values[1]) + imageBg := setting.SlideImagesBg[imageIndex] + + maxPotion := image.Point{ + X: imageRandX + slideImage.MaskSize, + Y: slideImage.ImageY + slideImage.MaskSize, + } + minPotion := image.Point{ + X: imageRandX, + Y: slideImage.ImageY, + } + subimg := image.Rectangle{ + Max: maxPotion, + Min: minPotion, + } + + if isScreenshot { + data := imaging.Crop(*imageBg, subimg) + png.Encode(ctx.Resp, data) + + } else { + data := imaging.Overlay(*imageBg, *setting.SlideMaskImage, minPotion, 1.0) + png.Encode(ctx.Resp, data) + } + ctx.Status(200) + return + + } + ctx.Data["SlideImageInfo"] = slideImage + ctx.Data["EnablePhone"] = setting.PhoneService.Enabled + ctx.Map(slideImage) + + } +} + +func InitSlideImage() { + if setting.PhoneService.Enabled { + + filenames, err := public.Dir(path.Join("img", "slide", "bg")) + if err != nil { + panic("Slide Image Service init failed") + } + maskFileName, err := public.Dir(path.Join("img", "slide", "mask")) + if err != nil { + panic("Slide Image Service init failed") + } + + for _, filename := range filenames { + if strings.HasSuffix(filename, ".png") { + content, err := public.Asset(path.Join("img", "slide", "bg", filename)) + + if err != nil { + log.Warn("can not open "+filename, err) + continue + } + + m, err := png.Decode(bytes.NewReader(content)) + + if err != nil { + log.Warn("can not decode "+filename, err) + continue + } + setting.SlideImagesBg = append(setting.SlideImagesBg, &m) + } + + } + setting.SlideImagesCount = len(setting.SlideImagesBg) + if setting.SlideImagesCount == 0 { + panic("Slide Image Service init failed") + } + + maskContent, err := public.Asset(path.Join("img", "slide", "mask", maskFileName[0])) + + if err != nil { + panic("Slide Image Service init failed") + } + + MaskImage, err := png.Decode(bytes.NewReader(maskContent)) + if err != nil { + panic("Slide Image Service init failed") + } + setting.SlideMaskImage = &MaskImage + + log.Info("Slide Image Service Enabled") + + } +} diff --git a/modules/storage/minio_ext.go b/modules/storage/minio_ext.go index 514ac7204..4ad83da82 100755 --- a/modules/storage/minio_ext.go +++ b/modules/storage/minio_ext.go @@ -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) { _, core, err := getClients() var fileTotalSize int64 diff --git a/modules/storage/obs.go b/modules/storage/obs.go index 33730b72c..29b7998f7 100755 --- a/modules/storage/obs.go +++ b/modules/storage/obs.go @@ -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.Bucket = srcBucket // 设置每页100个对象 @@ -330,6 +370,7 @@ func GetOneLevelAllObjectUnderDir(bucket string, prefixRootPath string, relative output, err := ObsCli.ListObjects(input) fileInfos := make([]FileInfo, 0) prefixLen := len(input.Prefix) + fileMap := make(map[string]bool, 0) if err == nil { for _, val := range output.Contents { log.Info("val key=" + val.Key) @@ -338,23 +379,51 @@ func GetOneLevelAllObjectUnderDir(bucket string, prefixRootPath string, relative if val.Key == input.Prefix { 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 + } else { + fileMap[files[0]] = true } - if strings.HasSuffix(val.Key, "/") { + ParenDir := relativePath + fileName = files[0] + if len(files) > 1 { isDir = true - fileName = val.Key[prefixLen : len(val.Key)-1] - relativePath += val.Key[prefixLen:] + ParenDir += fileName + "/" } else { 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{ ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"), FileName: fileName, Size: val.Size, IsDir: isDir, - ParenDir: relativePath, + ParenDir: ParenDir, } fileInfos = append(fileInfos, fileInfo) } @@ -424,6 +493,7 @@ func GetObsListObject(jobName, outPutPath, parentDir, versionName string) ([]Fil input := &obs.ListObjectsInput{} input.Bucket = setting.Bucket 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, "/") output, err := ObsCli.ListObjects(input) fileInfos := make([]FileInfo, 0) @@ -575,6 +645,8 @@ func GetObsLogFileName(prefix string) (string, error) { log.Error("PutObject failed:", err.Error()) return "", err } - + if output == nil || len(output.Contents) == 0 { + return "", errors.New("obs log files not exist") + } return output.Contents[0].Key, nil } diff --git a/modules/templates/helper.go b/modules/templates/helper.go index dbb9354aa..857e365f8 100755 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -18,6 +18,7 @@ import ( "path/filepath" "regexp" "runtime" + "strconv" "strings" texttmpl "text/template" "time" @@ -327,6 +328,7 @@ func NewFuncMap() []template.FuncMap { }, "GetRefType": GetRefType, "GetRefName": GetRefName, + "MB2GB": MB2GB, }} } @@ -785,3 +787,14 @@ func GetRefName(ref string) string { reg := regexp.MustCompile(REF_TYPE_PATTERN) return reg.ReplaceAllString(ref, "") } + +func MB2GB(size int64) string { + s := strconv.FormatFloat(float64(size)/float64(1024), 'f', 2, 64) + for strings.HasSuffix(s, "0") { + s = strings.TrimSuffix(s, "0") + } + if strings.HasSuffix(s, ".") { + s = strings.TrimSuffix(s, ".") + } + return s +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 39a892cc7..b641f4011 100755 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -32,6 +32,8 @@ captcha = CAPTCHA twofa = Two-Factor Authentication twofa_scratch = Two-Factor Scratch Code passcode = Passcode +use_and_privacy_agree = I have read and agree to the use agreement and privacy agreement +sign_up_agree_tips = should agree to the use agreement and privacy agreement! u2f_insert_key = Insert your security key u2f_sign_in = Press the button on your security key. If your security key has no button, re-insert it. @@ -197,6 +199,7 @@ no_reply_address_helper = Domain name for users with a hidden email address. For [home] uname_holder = Username or Email Address +login_uname_holder=Username/Email/Phone number uname_holder_cloud_brain = cloudbrain username password_holder = Password switch_dashboard_context = Switch Dashboard Context @@ -335,11 +338,16 @@ resent_limit_prompt = You have already requested an activation email recently. P has_unconfirmed_mail = Hi %s, you have an unconfirmed email address (%s). If you haven't received a confirmation email or need to resend a new one, please click on the button below. resend_mail = Click here to resend your activation email email_not_associate = The email address is not associated with any account. +email_not_main=The email address is wrong, please input your primary email address. +email_not_right=The email address is not associated with any account, please input the right email address. send_reset_mail = Send Account Recovery Email +please_enter_main_email=Please enter your primary email +please_enter_main_email_tips=Tips: Only the primary email can receive the recovery email. reset_password = Account Recovery invalid_code = Your confirmation code is invalid or has expired. reset_password_helper = Recover Account reset_password_wrong_user = You are signed in as %s, but the account recovery link is for %s +reset_password_wrong_user_phone=You are signed in, but the phone number is used by other user. password_too_short = Password length cannot be less than %d characters. non_local_account = Non-local users can not update their password through the openi web interface. verify = Verify @@ -374,6 +382,37 @@ authorization_failed = Authorization failed authorization_failed_desc = The authorization failed because we detected an invalid request. Please contact the maintainer of the app you've tried to authorize. disable_forgot_password_mail = Account recovery is disabled. Please contact your site administrator. sspi_auth_failed = SSPI authentication failed +[phone] +format_err=The format of phone number is wrong. +query_err=Fail to query phone number, please try again later. +already_register=The phone number is already used. +not_register=The phone number is wrong. +not_modify=The phone number is not updated. +max_times=One phone number can not send verification code more than %s times a day. +too_fast=Send too frequently, please try again later. +manual_first=Please slide to finish the jigsaw first. +verify_code_fail=Please input right verification code. +bind_phone=Please Bind Your Phone. +bind_phone_fail=Fail to bind phone number, please try again later. +phone_number=Phone number +drag_the_slider_to_fill_the_puzzle=Drag the slider to the right to fill the puzzle +mobile_phone_verification_code=Phone verification code +please_enter_SMS_verification_code=Please enter SMS verification code +get_verification_code=Get verification code +new_login_password=New login password +please_enter_new_password=Please enter new password +second_resend=S resend +please_bind_your_mobile_number=Please Bind Your Phone Number +submit=Submit +please_enter_the_correct_mobile_number=Please enter the correct phone number +please_enter_the_correct_mobile_phone_verification_code=Please enter the correct phone verification code +email_retrieve_password=Email retrieve password +mobile_number_retrieve_password=Phone number retrieve password +mobile_login=Mobile login +account_password_login=Account password login +cloud_brain_user_login=Cloud brain user login +modify_phone_number=Modify phone number + [mail] activate_account = Please activate your account @@ -520,6 +559,7 @@ static.CollectImage=Collect Image Count static.CollectedImage=Collected Image Count static.RecommendImage=Recommended Image Count static.email=Email +static.phone=Phone static.location=Location static.all=All static.public.user_business_analysis_current_month=Current_Month @@ -997,7 +1037,9 @@ image_delete_fail=Failed to delete image, please try again later. image_overwrite=You had submitted the same name image before, are you sure to overwrite the original image? download=Download score=Score - +wait_count_start = There are currently +wait_count_end = tasks queued +file_limit_100 = Display up to 100 files or folders in a single directory images.name = Image Tag images.name_placerholder = Please enter the image name image.label_tooltips = Example Python 3.7, Tensorflow 2.0, cuda 10, pytorch 1.6 @@ -1176,6 +1218,14 @@ model.manage.Recall = Recall model.manage.sava_model = Sava Model model.manage.model_manage = ModelManage 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.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。 @@ -2501,6 +2551,7 @@ users.new_account = Create User Account users.name = Username users.full_name = Full Name users.activated = Activated +users.bind_phone = Bind Phone users.admin = Admin users.restricted = Restricted users.repos = Repos @@ -3080,4 +3131,10 @@ INFERENCE = INFERENCE BENCHMARK = BENCHMARK brain_area = Brain Area -error.dataset_select = dataset select error:the count exceed the limit or has same name \ No newline at end of file +Delete_failed=Fail to delete the job, please try again later. +Not_Stopped=The job is not stopped, can not be deleted. +Already_stopped=The job is already stopped. +Stopped_failed=Fail to stop the job, please try again later. +Stopped_success_update_status_fail=Succeed in stopping th job, but failed to update the job status and duration time. + +error.dataset_select = dataset select error:the count exceed the limit or has same name diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index b9acb6ec0..87630d6c0 100755 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -32,6 +32,8 @@ captcha=验证码 twofa=两步验证 twofa_scratch=两步验证口令 passcode=验证码 +use_and_privacy_agree = 我已阅读并同意 使用协议隐私协议 +sign_up_agree_tips = 注册时需同意使用协议和隐私协议 u2f_insert_key=插入安全密钥 u2f_sign_in=按下安全密钥上的按钮。如果安全密钥没有按钮,请重新插入。 @@ -198,6 +200,7 @@ no_reply_address_helper=具有隐藏电子邮件地址的用户的域名。例 [home] uname_holder=登录名或电子邮箱地址 +login_uname_holder=用户名/邮箱/手机号 uname_holder_cloud_brain=云脑登录名 password_holder=密码 switch_dashboard_context=切换控制面板用户 @@ -339,11 +342,16 @@ resent_limit_prompt=您请求发送激活邮件过于频繁,请等待 3 分钟 has_unconfirmed_mail=%s 您好,系统检测到您有一封发送至 %s 但未被确认的邮件。如果您未收到激活邮件,或需要重新发送,请单击下方的按钮。 resend_mail=单击此处重新发送确认邮件 email_not_associate=您输入的邮箱地址未被关联到任何帐号! -send_reset_mail=发送账户恢复邮件 +email_not_main=电子邮箱地址不正确,请输入您设置的主要邮箱地址。 +email_not_right=您输入了不存在的邮箱地址,请输入正确的邮箱地址。 +send_reset_mail=发送密码找回邮件 +please_enter_main_email=请输入接收通知提醒的主要邮箱地址 +please_enter_main_email_tips=说明:如果您设置了多个邮箱地址,只有主要邮箱可以收到密码找回邮件,其他邮箱无法收到。 reset_password=账户恢复 invalid_code=此确认密钥无效或已过期。 reset_password_helper=恢复账户 reset_password_wrong_user=您已作为 %s 登录,无法使用链接恢复 %s 的账户。 +reset_password_wrong_user_phone=您已登录,不能用别的账号的手机恢复。 password_too_short=密码长度不能少于 %d 位。 non_local_account=非本地帐户不能通过 openi 的 web 界面更改密码。 verify=验证 @@ -378,6 +386,37 @@ authorization_failed=授权失败 authorization_failed_desc=授权失败,这是一个无效的请求。请联系尝试授权应用的管理员。 disable_forgot_password_mail = Account recovery is disabled. Please contact your site administrator. sspi_auth_failed=SSPI 认证失败 +[phone] +format_err=手机号格式错误。 +query_err=查询手机号失败,请稍后再试。 +already_register=手机号已被使用。 +not_register=手机号输入错误。 +not_modify=手机号未修改。 +max_times=一个手机号每天发送验证码次数不能超过%s次。 +too_fast=验证码发送太频繁,请稍后再试。 +manual_first=请先拖动滑块填充拼图。 +verify_code_fail=请输入正确的短信验证码。 +bind_phone=请绑定手机号。 +bind_phone_fail=绑定手机号失败,请稍后再试。 +phone_number=手机号码 +drag_the_slider_to_fill_the_puzzle=向右拖动滑块填充拼图 +mobile_phone_verification_code=手机验证码 +please_enter_SMS_verification_code=请输入短信验证码 +get_verification_code=获取验证码 +new_login_password=新的登录密码 +please_enter_new_password=请输入新的密码 +second_resend=S后重发 +please_bind_your_mobile_number=请绑定手机号 +submit=提交 +please_enter_the_correct_mobile_number=请输入正确的手机号 +please_enter_the_correct_mobile_phone_verification_code=请输入正确格式的手机验证码 +email_retrieve_password=邮箱找回密码 +mobile_number_retrieve_password=手机号找回密码 +mobile_login=手机登录 +account_password_login=账号密码登录 +cloud_brain_user_login=云脑1用户登录 +modify_phone_number=修改手机号 + [mail] activate_account=请激活您的帐户 @@ -525,6 +564,7 @@ static.CollectImage=收藏镜像数 static.CollectedImage=被收藏镜像数 static.RecommendImage=被推荐镜像数 static.email=Email +static.phone=电话 static.location=所在地区 static.all=所有 static.public.user_business_analysis_current_month=本月 @@ -997,8 +1037,9 @@ image_delete_fail=删除镜像失败,请稍后再试。 image_overwrite=您已经提交过相同名称的镜像,您确定要覆盖原来提交的镜像吗? download=模型下载 score=评分 - - +wait_count_start = 当前有 +wait_count_end = 个任务正在排队 +file_limit_100 = 单目录下最多显示100个文件或文件夹 images.name = 镜像Tag images.name_placerholder = 请输入镜像Tag image.label_tooltips = 如Python 3.7, Tensorflow 2.0, cuda 10, pytorch 1.6 @@ -1189,6 +1230,14 @@ model.manage.Recall = 召回率 model.manage.sava_model = 保存模型 model.manage.model_manage = 模型管理 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.dataset_path_rule = 训练脚本存储在/cache/code中,数据集存储在/cache/dataset中,训练输出请存储在/cache/output中以供后续下载。 @@ -2516,6 +2565,7 @@ users.new_account=创建新帐户 users.name=用户名 users.full_name=全名 users.activated=已激活 +users.bind_phone=手机验证 users.admin=管理员 users.restricted=受限 users.repos=项目数 @@ -3095,4 +3145,11 @@ INFERENCE = 推理任务 BENCHMARK = 评测任务 brain_area = 脑区 -error.dataset_select = 数据集选择错误:数量超过限制或者有同名数据集 \ No newline at end of file +Delete_failed=任务删除失败,请稍后再试。 +Not_Stopped=任务还未终止,不能删除。 +Already_stopped=任务已停止。 +Stopped_failed=任务停止失败,请稍后再试。 +Stopped_success_update_status_fail=任务停止成功,状态及运行时间更新失败。 + + +error.dataset_select = 数据集选择错误:数量超过限制或者有同名数据集 diff --git a/public/home/home.js b/public/home/home.js index 95ea3da4c..70b9d7253 100755 --- a/public/home/home.js +++ b/public/home/home.js @@ -119,7 +119,6 @@ document.onreadystatechange = function () { continue; } } - refresh3DInfo(record); var recordPrefix = getMsg(record); if(record.OpType == "6" || record.OpType == "10" || record.OpType == "12" || record.OpType == "13"){ html += recordPrefix + actionName; @@ -208,29 +207,6 @@ function getTaskLink(record){ return re; } -function refresh3DInfo(record){ - if(record.OpType == "25" || record.OpType == "29" || record.OpType == "31"){ - //cloudbrain one - var lines = $('.rotation3D__line'); - var span = $('.rotation3D__line').find("span")[0]; - //console.log(span); - span.innerText =record.RefName; - //$('.rotation3D__line').find("span").eq(0).text(record.RefName) - //console.log("cloudbrain one line length=" + lines.length); - //lines[0].find("span").text(record.RefName); - }else if(record.OpType == "26" || record.OpType == "27" || record.OpType == "28"){ - //cloudbrain two - var lines = $('.rotation3D__line'); - //console.log("cloudbrain two line length=" + lines.length); - var span = $('.rotation3D__line').find("span")[1]; - //console.log(span); - if(span != null){ - span.innerText =record.RefName; - } - } - -} - function getMsg(record){ var html =""; html += "
"; diff --git a/public/img/slide/bg/1.png b/public/img/slide/bg/1.png new file mode 100644 index 000000000..d76aa3725 Binary files /dev/null and b/public/img/slide/bg/1.png differ diff --git a/public/img/slide/bg/2.png b/public/img/slide/bg/2.png new file mode 100644 index 000000000..73536b138 Binary files /dev/null and b/public/img/slide/bg/2.png differ diff --git a/public/img/slide/bg/3.png b/public/img/slide/bg/3.png new file mode 100644 index 000000000..530e5b5c0 Binary files /dev/null and b/public/img/slide/bg/3.png differ diff --git a/public/img/slide/bg/4.png b/public/img/slide/bg/4.png new file mode 100644 index 000000000..c9b0127f0 Binary files /dev/null and b/public/img/slide/bg/4.png differ diff --git a/public/img/slide/mask/mask.png b/public/img/slide/mask/mask.png new file mode 100644 index 000000000..562f75b05 Binary files /dev/null and b/public/img/slide/mask/mask.png differ diff --git a/public/self/ztree/css/awesomeStyle/awesome.css b/public/self/ztree/css/awesomeStyle/awesome.css new file mode 100644 index 000000000..5fa82249a --- /dev/null +++ b/public/self/ztree/css/awesomeStyle/awesome.css @@ -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; +} diff --git a/public/self/ztree/css/awesomeStyle/awesome.less b/public/self/ztree/css/awesomeStyle/awesome.less new file mode 100644 index 000000000..bf8508e4d --- /dev/null +++ b/public/self/ztree/css/awesomeStyle/awesome.less @@ -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} + diff --git a/public/self/ztree/css/awesomeStyle/fa.less b/public/self/ztree/css/awesomeStyle/fa.less new file mode 100644 index 000000000..3714884a7 --- /dev/null +++ b/public/self/ztree/css/awesomeStyle/fa.less @@ -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"; + diff --git a/public/self/ztree/css/awesomeStyle/img/loading.gif b/public/self/ztree/css/awesomeStyle/img/loading.gif new file mode 100644 index 000000000..e8c289293 Binary files /dev/null and b/public/self/ztree/css/awesomeStyle/img/loading.gif differ diff --git a/public/self/ztree/css/demo.css b/public/self/ztree/css/demo.css new file mode 100644 index 000000000..f6dba0de8 --- /dev/null +++ b/public/self/ztree/css/demo.css @@ -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} \ No newline at end of file diff --git a/public/self/ztree/css/metroStyle/img/line_conn.png b/public/self/ztree/css/metroStyle/img/line_conn.png new file mode 100644 index 000000000..b211da2fa Binary files /dev/null and b/public/self/ztree/css/metroStyle/img/line_conn.png differ diff --git a/public/self/ztree/css/metroStyle/img/loading.gif b/public/self/ztree/css/metroStyle/img/loading.gif new file mode 100644 index 000000000..e8c289293 Binary files /dev/null and b/public/self/ztree/css/metroStyle/img/loading.gif differ diff --git a/public/self/ztree/css/metroStyle/img/metro.gif b/public/self/ztree/css/metroStyle/img/metro.gif new file mode 100644 index 000000000..664b969a2 Binary files /dev/null and b/public/self/ztree/css/metroStyle/img/metro.gif differ diff --git a/public/self/ztree/css/metroStyle/img/metro.png b/public/self/ztree/css/metroStyle/img/metro.png new file mode 100644 index 000000000..e9e58a3a7 Binary files /dev/null and b/public/self/ztree/css/metroStyle/img/metro.png differ diff --git a/public/self/ztree/css/metroStyle/metroStyle.css b/public/self/ztree/css/metroStyle/metroStyle.css new file mode 100644 index 000000000..af81f4239 --- /dev/null +++ b/public/self/ztree/css/metroStyle/metroStyle.css @@ -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} diff --git a/public/self/ztree/css/zTreeStyle/img/diy/1_close.png b/public/self/ztree/css/zTreeStyle/img/diy/1_close.png new file mode 100644 index 000000000..68ccb3c3b Binary files /dev/null and b/public/self/ztree/css/zTreeStyle/img/diy/1_close.png differ diff --git a/public/self/ztree/css/zTreeStyle/img/diy/1_open.png b/public/self/ztree/css/zTreeStyle/img/diy/1_open.png new file mode 100644 index 000000000..d6ff36d3a Binary files /dev/null and b/public/self/ztree/css/zTreeStyle/img/diy/1_open.png differ diff --git a/public/self/ztree/css/zTreeStyle/img/diy/2.png b/public/self/ztree/css/zTreeStyle/img/diy/2.png new file mode 100644 index 000000000..9eff506ba Binary files /dev/null and b/public/self/ztree/css/zTreeStyle/img/diy/2.png differ diff --git a/public/self/ztree/css/zTreeStyle/img/diy/3.png b/public/self/ztree/css/zTreeStyle/img/diy/3.png new file mode 100644 index 000000000..d7ba6d0c6 Binary files /dev/null and b/public/self/ztree/css/zTreeStyle/img/diy/3.png differ diff --git a/public/self/ztree/css/zTreeStyle/img/diy/4.png b/public/self/ztree/css/zTreeStyle/img/diy/4.png new file mode 100644 index 000000000..753e2bfd5 Binary files /dev/null and b/public/self/ztree/css/zTreeStyle/img/diy/4.png differ diff --git a/public/self/ztree/css/zTreeStyle/img/diy/5.png b/public/self/ztree/css/zTreeStyle/img/diy/5.png new file mode 100644 index 000000000..0c5eccd56 Binary files /dev/null and b/public/self/ztree/css/zTreeStyle/img/diy/5.png differ diff --git a/public/self/ztree/css/zTreeStyle/img/diy/6.png b/public/self/ztree/css/zTreeStyle/img/diy/6.png new file mode 100644 index 000000000..070b8352d Binary files /dev/null and b/public/self/ztree/css/zTreeStyle/img/diy/6.png differ diff --git a/public/self/ztree/css/zTreeStyle/img/diy/7.png b/public/self/ztree/css/zTreeStyle/img/diy/7.png new file mode 100644 index 000000000..532b037f2 Binary files /dev/null and b/public/self/ztree/css/zTreeStyle/img/diy/7.png differ diff --git a/public/self/ztree/css/zTreeStyle/img/diy/8.png b/public/self/ztree/css/zTreeStyle/img/diy/8.png new file mode 100644 index 000000000..a8f3a86e7 Binary files /dev/null and b/public/self/ztree/css/zTreeStyle/img/diy/8.png differ diff --git a/public/self/ztree/css/zTreeStyle/img/diy/9.png b/public/self/ztree/css/zTreeStyle/img/diy/9.png new file mode 100644 index 000000000..4db73cd41 Binary files /dev/null and b/public/self/ztree/css/zTreeStyle/img/diy/9.png differ diff --git a/public/self/ztree/css/zTreeStyle/img/line_conn.gif b/public/self/ztree/css/zTreeStyle/img/line_conn.gif new file mode 100644 index 000000000..d561d36a9 Binary files /dev/null and b/public/self/ztree/css/zTreeStyle/img/line_conn.gif differ diff --git a/public/self/ztree/css/zTreeStyle/img/loading.gif b/public/self/ztree/css/zTreeStyle/img/loading.gif new file mode 100644 index 000000000..e8c289293 Binary files /dev/null and b/public/self/ztree/css/zTreeStyle/img/loading.gif differ diff --git a/public/self/ztree/css/zTreeStyle/img/zTreeStandard.gif b/public/self/ztree/css/zTreeStyle/img/zTreeStandard.gif new file mode 100644 index 000000000..4b640d22e Binary files /dev/null and b/public/self/ztree/css/zTreeStyle/img/zTreeStandard.gif differ diff --git a/public/self/ztree/css/zTreeStyle/img/zTreeStandard.png b/public/self/ztree/css/zTreeStyle/img/zTreeStandard.png new file mode 100644 index 000000000..cd46ddde9 Binary files /dev/null and b/public/self/ztree/css/zTreeStyle/img/zTreeStandard.png differ diff --git a/public/self/ztree/css/zTreeStyle/zTreeStyle.css b/public/self/ztree/css/zTreeStyle/zTreeStyle.css new file mode 100644 index 000000000..39e346a23 --- /dev/null +++ b/public/self/ztree/css/zTreeStyle/zTreeStyle.css @@ -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; +}*/ \ No newline at end of file diff --git a/public/self/ztree/js/jquery-1.4.4.min.js b/public/self/ztree/js/jquery-1.4.4.min.js new file mode 100644 index 000000000..8f3ca2e2d --- /dev/null +++ b/public/self/ztree/js/jquery-1.4.4.min.js @@ -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;kd)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(;K0))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
a";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="";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="
";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="
t
";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-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=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=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-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;h0?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;p0){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;i0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p=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 in[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=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";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="";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="

";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="
";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;n0)for(var h=d;h0},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-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-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=/\s]+\/)>/g,P={option:[1, +""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_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
","
"];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>");try{for(var b=0,d=this.length;b0||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;f0?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>");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]===""&&!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>/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("
").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=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-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); diff --git a/public/self/ztree/js/jquery.ztree.all.js b/public/self/ztree/js/jquery.ztree.all.js new file mode 100644 index 000000000..dbca0e564 --- /dev/null +++ b/public/self/ztree/js/jquery.ztree.all.js @@ -0,0 +1,3878 @@ +/* + * JQuery zTree core + * 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 settings = {}, roots = {}, caches = {}, + //default consts of core + _consts = { + className: { + BUTTON: "button", + LEVEL: "level", + ICO_LOADING: "ico_loading", + SWITCH: "switch", + NAME: 'node_name' + }, + event: { + NODECREATED: "ztree_nodeCreated", + CLICK: "ztree_click", + EXPAND: "ztree_expand", + COLLAPSE: "ztree_collapse", + ASYNC_SUCCESS: "ztree_async_success", + ASYNC_ERROR: "ztree_async_error", + REMOVE: "ztree_remove", + SELECTED: "ztree_selected", + UNSELECTED: "ztree_unselected" + }, + id: { + A: "_a", + ICON: "_ico", + SPAN: "_span", + SWITCH: "_switch", + UL: "_ul" + }, + line: { + ROOT: "root", + ROOTS: "roots", + CENTER: "center", + BOTTOM: "bottom", + NOLINE: "noline", + LINE: "line" + }, + folder: { + OPEN: "open", + CLOSE: "close", + DOCU: "docu" + }, + node: { + CURSELECTED: "curSelectedNode" + } + }, + //default setting of core + _setting = { + treeId: "", + treeObj: null, + view: { + addDiyDom: null, + autoCancelSelected: true, + dblClickExpand: true, + expandSpeed: "fast", + fontCss: {}, + nodeClasses: {}, + nameIsHTML: false, + selectedMulti: true, + showIcon: true, + showLine: true, + showTitle: true, + txtSelectedEnable: false + }, + data: { + key: { + isParent: "isParent", + children: "children", + name: "name", + title: "", + url: "url", + icon: "icon" + }, + render: { + name: null, + title: null, + }, + simpleData: { + enable: false, + idKey: "id", + pIdKey: "pId", + rootPId: null + }, + keep: { + parent: false, + leaf: false + } + }, + async: { + enable: false, + contentType: "application/x-www-form-urlencoded", + type: "post", + dataType: "text", + headers: {}, + xhrFields: {}, + url: "", + autoParam: [], + otherParam: [], + dataFilter: null + }, + callback: { + beforeAsync: null, + beforeClick: null, + beforeDblClick: null, + beforeRightClick: null, + beforeMouseDown: null, + beforeMouseUp: null, + beforeExpand: null, + beforeCollapse: null, + beforeRemove: null, + + onAsyncError: null, + onAsyncSuccess: null, + onNodeCreated: null, + onClick: null, + onDblClick: null, + onRightClick: null, + onMouseDown: null, + onMouseUp: null, + onExpand: null, + onCollapse: null, + onRemove: null + } + }, + //default root of core + //zTree use root to save full data + _initRoot = function (setting) { + var r = data.getRoot(setting); + if (!r) { + r = {}; + data.setRoot(setting, r); + } + data.nodeChildren(setting, r, []); + r.expandTriggerFlag = false; + r.curSelectedList = []; + r.noSelection = true; + r.createdNodes = []; + r.zId = 0; + r._ver = (new Date()).getTime(); + }, + //default cache of core + _initCache = function (setting) { + var c = data.getCache(setting); + if (!c) { + c = {}; + data.setCache(setting, c); + } + c.nodes = []; + c.doms = []; + }, + //default bindEvent of core + _bindEvent = function (setting) { + var o = setting.treeObj, + c = consts.event; + o.bind(c.NODECREATED, function (event, treeId, node) { + tools.apply(setting.callback.onNodeCreated, [event, treeId, node]); + }); + + o.bind(c.CLICK, function (event, srcEvent, treeId, node, clickFlag) { + tools.apply(setting.callback.onClick, [srcEvent, treeId, node, clickFlag]); + }); + + o.bind(c.EXPAND, function (event, treeId, node) { + tools.apply(setting.callback.onExpand, [event, treeId, node]); + }); + + o.bind(c.COLLAPSE, function (event, treeId, node) { + tools.apply(setting.callback.onCollapse, [event, treeId, node]); + }); + + o.bind(c.ASYNC_SUCCESS, function (event, treeId, node, msg) { + tools.apply(setting.callback.onAsyncSuccess, [event, treeId, node, msg]); + }); + + o.bind(c.ASYNC_ERROR, function (event, treeId, node, XMLHttpRequest, textStatus, errorThrown) { + tools.apply(setting.callback.onAsyncError, [event, treeId, node, XMLHttpRequest, textStatus, errorThrown]); + }); + + o.bind(c.REMOVE, function (event, treeId, treeNode) { + tools.apply(setting.callback.onRemove, [event, treeId, treeNode]); + }); + + o.bind(c.SELECTED, function (event, treeId, node) { + tools.apply(setting.callback.onSelected, [treeId, node]); + }); + o.bind(c.UNSELECTED, function (event, treeId, node) { + tools.apply(setting.callback.onUnSelected, [treeId, node]); + }); + }, + _unbindEvent = function (setting) { + var o = setting.treeObj, + c = consts.event; + o.unbind(c.NODECREATED) + .unbind(c.CLICK) + .unbind(c.EXPAND) + .unbind(c.COLLAPSE) + .unbind(c.ASYNC_SUCCESS) + .unbind(c.ASYNC_ERROR) + .unbind(c.REMOVE) + .unbind(c.SELECTED) + .unbind(c.UNSELECTED); + }, + //default event proxy of core + _eventProxy = function (event) { + var target = event.target, + setting = data.getSetting(event.data.treeId), + tId = "", node = null, + nodeEventType = "", treeEventType = "", + nodeEventCallback = null, treeEventCallback = null, + tmp = null; + + if (tools.eqs(event.type, "mousedown")) { + treeEventType = "mousedown"; + } else if (tools.eqs(event.type, "mouseup")) { + treeEventType = "mouseup"; + } else if (tools.eqs(event.type, "contextmenu")) { + treeEventType = "contextmenu"; + } else if (tools.eqs(event.type, "click")) { + if (tools.eqs(target.tagName, "span") && target.getAttribute("treeNode" + consts.id.SWITCH) !== null) { + tId = tools.getNodeMainDom(target).id; + nodeEventType = "switchNode"; + } else { + tmp = tools.getMDom(setting, target, [{tagName: "a", attrName: "treeNode" + consts.id.A}]); + if (tmp) { + tId = tools.getNodeMainDom(tmp).id; + nodeEventType = "clickNode"; + } + } + } else if (tools.eqs(event.type, "dblclick")) { + treeEventType = "dblclick"; + tmp = tools.getMDom(setting, target, [{tagName: "a", attrName: "treeNode" + consts.id.A}]); + if (tmp) { + tId = tools.getNodeMainDom(tmp).id; + nodeEventType = "switchNode"; + } + } + if (treeEventType.length > 0 && tId.length == 0) { + tmp = tools.getMDom(setting, target, [{tagName: "a", attrName: "treeNode" + consts.id.A}]); + if (tmp) { + tId = tools.getNodeMainDom(tmp).id; + } + } + // event to node + if (tId.length > 0) { + node = data.getNodeCache(setting, tId); + switch (nodeEventType) { + case "switchNode" : + var isParent = data.nodeIsParent(setting, node); + if (!isParent) { + nodeEventType = ""; + } else if (tools.eqs(event.type, "click") + || (tools.eqs(event.type, "dblclick") && tools.apply(setting.view.dblClickExpand, [setting.treeId, node], setting.view.dblClickExpand))) { + nodeEventCallback = handler.onSwitchNode; + } else { + nodeEventType = ""; + } + break; + case "clickNode" : + nodeEventCallback = handler.onClickNode; + break; + } + } + // event to zTree + switch (treeEventType) { + case "mousedown" : + treeEventCallback = handler.onZTreeMousedown; + break; + case "mouseup" : + treeEventCallback = handler.onZTreeMouseup; + break; + case "dblclick" : + treeEventCallback = handler.onZTreeDblclick; + break; + case "contextmenu" : + treeEventCallback = handler.onZTreeContextmenu; + break; + } + var proxyResult = { + stop: false, + node: node, + nodeEventType: nodeEventType, + nodeEventCallback: nodeEventCallback, + treeEventType: treeEventType, + treeEventCallback: treeEventCallback + }; + return proxyResult + }, + //default init node of core + _initNode = function (setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) { + if (!n) return; + var r = data.getRoot(setting), + children = data.nodeChildren(setting, n); + n.level = level; + n.tId = setting.treeId + "_" + (++r.zId); + n.parentTId = parentNode ? parentNode.tId : null; + n.open = (typeof n.open == "string") ? tools.eqs(n.open, "true") : !!n.open; + var isParent = data.nodeIsParent(setting, n); + if (tools.isArray(children)) { + data.nodeIsParent(setting, n, true); + n.zAsync = true; + } else { + isParent = data.nodeIsParent(setting, n, isParent); + n.open = (isParent && !setting.async.enable) ? n.open : false; + n.zAsync = !isParent; + } + n.isFirstNode = isFirstNode; + n.isLastNode = isLastNode; + n.getParentNode = function () { + return data.getNodeCache(setting, n.parentTId); + }; + n.getPreNode = function () { + return data.getPreNode(setting, n); + }; + n.getNextNode = function () { + return data.getNextNode(setting, n); + }; + n.getIndex = function () { + return data.getNodeIndex(setting, n); + }; + n.getPath = function () { + return data.getNodePath(setting, n); + }; + n.isAjaxing = false; + data.fixPIdKeyValue(setting, n); + }, + _init = { + bind: [_bindEvent], + unbind: [_unbindEvent], + caches: [_initCache], + nodes: [_initNode], + proxys: [_eventProxy], + roots: [_initRoot], + beforeA: [], + afterA: [], + innerBeforeA: [], + innerAfterA: [], + zTreeTools: [] + }, + //method of operate data + data = { + addNodeCache: function (setting, node) { + data.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = node; + }, + getNodeCacheId: function (tId) { + return tId.substring(tId.lastIndexOf("_") + 1); + }, + addAfterA: function (afterA) { + _init.afterA.push(afterA); + }, + addBeforeA: function (beforeA) { + _init.beforeA.push(beforeA); + }, + addInnerAfterA: function (innerAfterA) { + _init.innerAfterA.push(innerAfterA); + }, + addInnerBeforeA: function (innerBeforeA) { + _init.innerBeforeA.push(innerBeforeA); + }, + addInitBind: function (bindEvent) { + _init.bind.push(bindEvent); + }, + addInitUnBind: function (unbindEvent) { + _init.unbind.push(unbindEvent); + }, + addInitCache: function (initCache) { + _init.caches.push(initCache); + }, + addInitNode: function (initNode) { + _init.nodes.push(initNode); + }, + addInitProxy: function (initProxy, isFirst) { + if (!!isFirst) { + _init.proxys.splice(0, 0, initProxy); + } else { + _init.proxys.push(initProxy); + } + }, + addInitRoot: function (initRoot) { + _init.roots.push(initRoot); + }, + addNodesData: function (setting, parentNode, index, nodes) { + var children = data.nodeChildren(setting, parentNode), params; + if (!children) { + children = data.nodeChildren(setting, parentNode, []); + index = -1; + } else if (index >= children.length) { + index = -1; + } + + if (children.length > 0 && index === 0) { + children[0].isFirstNode = false; + view.setNodeLineIcos(setting, children[0]); + } else if (children.length > 0 && index < 0) { + children[children.length - 1].isLastNode = false; + view.setNodeLineIcos(setting, children[children.length - 1]); + } + data.nodeIsParent(setting, parentNode, true); + + if (index < 0) { + data.nodeChildren(setting, parentNode, children.concat(nodes)); + } else { + params = [index, 0].concat(nodes); + children.splice.apply(children, params); + } + }, + addSelectedNode: function (setting, node) { + var root = data.getRoot(setting); + if (!data.isSelectedNode(setting, node)) { + root.curSelectedList.push(node); + } + }, + addCreatedNode: function (setting, node) { + if (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) { + var root = data.getRoot(setting); + root.createdNodes.push(node); + } + }, + addZTreeTools: function (zTreeTools) { + _init.zTreeTools.push(zTreeTools); + }, + exSetting: function (s) { + $.extend(true, _setting, s); + }, + fixPIdKeyValue: function (setting, node) { + if (setting.data.simpleData.enable) { + node[setting.data.simpleData.pIdKey] = node.parentTId ? node.getParentNode()[setting.data.simpleData.idKey] : setting.data.simpleData.rootPId; + } + }, + getAfterA: function (setting, node, array) { + for (var i = 0, j = _init.afterA.length; i < j; i++) { + _init.afterA[i].apply(this, arguments); + } + }, + getBeforeA: function (setting, node, array) { + for (var i = 0, j = _init.beforeA.length; i < j; i++) { + _init.beforeA[i].apply(this, arguments); + } + }, + getInnerAfterA: function (setting, node, array) { + for (var i = 0, j = _init.innerAfterA.length; i < j; i++) { + _init.innerAfterA[i].apply(this, arguments); + } + }, + getInnerBeforeA: function (setting, node, array) { + for (var i = 0, j = _init.innerBeforeA.length; i < j; i++) { + _init.innerBeforeA[i].apply(this, arguments); + } + }, + getCache: function (setting) { + return caches[setting.treeId]; + }, + getNodeIndex: function (setting, node) { + if (!node) return null; + var p = node.parentTId ? node.getParentNode() : data.getRoot(setting), + children = data.nodeChildren(setting, p); + for (var i = 0, l = children.length - 1; i <= l; i++) { + if (children[i] === node) { + return i; + } + } + return -1; + }, + getNextNode: function (setting, node) { + if (!node) return null; + var p = node.parentTId ? node.getParentNode() : data.getRoot(setting), + children = data.nodeChildren(setting, p); + for (var i = 0, l = children.length - 1; i <= l; i++) { + if (children[i] === node) { + return (i == l ? null : children[i + 1]); + } + } + return null; + }, + getNodeByParam: function (setting, nodes, key, value) { + if (!nodes || !key) return null; + for (var i = 0, l = nodes.length; i < l; i++) { + var node = nodes[i]; + if (node[key] == value) { + return nodes[i]; + } + var children = data.nodeChildren(setting, node); + var tmp = data.getNodeByParam(setting, children, key, value); + if (tmp) return tmp; + } + return null; + }, + getNodeCache: function (setting, tId) { + if (!tId) return null; + var n = caches[setting.treeId].nodes[data.getNodeCacheId(tId)]; + return n ? n : null; + }, + getNodePath: function (setting, node) { + if (!node) return null; + + var path; + if (node.parentTId) { + path = node.getParentNode().getPath(); + } else { + path = []; + } + + if (path) { + path.push(node); + } + + return path; + }, + getNodes: function (setting) { + return data.nodeChildren(setting, data.getRoot(setting)); + }, + getNodesByParam: function (setting, nodes, key, value) { + if (!nodes || !key) return []; + var result = []; + for (var i = 0, l = nodes.length; i < l; i++) { + var node = nodes[i]; + if (node[key] == value) { + result.push(node); + } + var children = data.nodeChildren(setting, node); + result = result.concat(data.getNodesByParam(setting, children, key, value)); + } + return result; + }, + getNodesByParamFuzzy: function (setting, nodes, key, value) { + if (!nodes || !key) return []; + var result = []; + value = value.toLowerCase(); + for (var i = 0, l = nodes.length; i < l; i++) { + var node = nodes[i]; + if (typeof node[key] == "string" && nodes[i][key].toLowerCase().indexOf(value) > -1) { + result.push(node); + } + var children = data.nodeChildren(setting, node); + result = result.concat(data.getNodesByParamFuzzy(setting, children, key, value)); + } + return result; + }, + getNodesByFilter: function (setting, nodes, filter, isSingle, invokeParam) { + if (!nodes) return (isSingle ? null : []); + var result = isSingle ? null : []; + for (var i = 0, l = nodes.length; i < l; i++) { + var node = nodes[i]; + if (tools.apply(filter, [node, invokeParam], false)) { + if (isSingle) { + return node; + } + result.push(node); + } + var children = data.nodeChildren(setting, node); + var tmpResult = data.getNodesByFilter(setting, children, filter, isSingle, invokeParam); + if (isSingle && !!tmpResult) { + return tmpResult; + } + result = isSingle ? tmpResult : result.concat(tmpResult); + } + return result; + }, + getPreNode: function (setting, node) { + if (!node) return null; + var p = node.parentTId ? node.getParentNode() : data.getRoot(setting), + children = data.nodeChildren(setting, p); + for (var i = 0, l = children.length; i < l; i++) { + if (children[i] === node) { + return (i == 0 ? null : children[i - 1]); + } + } + return null; + }, + getRoot: function (setting) { + return setting ? roots[setting.treeId] : null; + }, + getRoots: function () { + return roots; + }, + getSetting: function (treeId) { + return settings[treeId]; + }, + getSettings: function () { + return settings; + }, + getZTreeTools: function (treeId) { + var r = this.getRoot(this.getSetting(treeId)); + return r ? r.treeTools : null; + }, + initCache: function (setting) { + for (var i = 0, j = _init.caches.length; i < j; i++) { + _init.caches[i].apply(this, arguments); + } + }, + initNode: function (setting, level, node, parentNode, preNode, nextNode) { + for (var i = 0, j = _init.nodes.length; i < j; i++) { + _init.nodes[i].apply(this, arguments); + } + }, + initRoot: function (setting) { + for (var i = 0, j = _init.roots.length; i < j; i++) { + _init.roots[i].apply(this, arguments); + } + }, + isSelectedNode: function (setting, node) { + var root = data.getRoot(setting); + for (var i = 0, j = root.curSelectedList.length; i < j; i++) { + if (node === root.curSelectedList[i]) return true; + } + return false; + }, + nodeChildren: function (setting, node, newChildren) { + if (!node) { + return null; + } + var key = setting.data.key.children; + if (typeof newChildren !== 'undefined') { + node[key] = newChildren; + } + return node[key]; + }, + nodeIsParent: function (setting, node, newIsParent) { + if (!node) { + return false; + } + var key = setting.data.key.isParent; + if (typeof newIsParent !== 'undefined') { + if (typeof newIsParent === "string") { + newIsParent = tools.eqs(newIsParent, "true"); + } + newIsParent = !!newIsParent; + node[key] = newIsParent; + } else if (typeof node[key] == "string"){ + node[key] = tools.eqs(node[key], "true"); + } else { + node[key] = !!node[key]; + } + return node[key]; + }, + nodeName: function (setting, node, newName) { + var key = setting.data.key.name; + if (typeof newName !== 'undefined') { + node[key] = newName; + } + var rawName = "" + node[key]; + if(typeof setting.data.render.name === 'function') { + return setting.data.render.name.call(this,rawName,node); + } + return rawName; + }, + nodeTitle: function (setting, node) { + var t = setting.data.key.title === "" ? setting.data.key.name : setting.data.key.title; + var rawTitle = "" + node[t]; + if(typeof setting.data.render.title === 'function') { + return setting.data.render.title.call(this,rawTitle,node); + } + return rawTitle; + }, + removeNodeCache: function (setting, node) { + var children = data.nodeChildren(setting, node); + if (children) { + for (var i = 0, l = children.length; i < l; i++) { + data.removeNodeCache(setting, children[i]); + } + } + data.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = null; + }, + removeSelectedNode: function (setting, node) { + var root = data.getRoot(setting); + for (var i = 0, j = root.curSelectedList.length; i < j; i++) { + if (node === root.curSelectedList[i] || !data.getNodeCache(setting, root.curSelectedList[i].tId)) { + root.curSelectedList.splice(i, 1); + setting.treeObj.trigger(consts.event.UNSELECTED, [setting.treeId, node]); + i--; + j--; + } + } + }, + setCache: function (setting, cache) { + caches[setting.treeId] = cache; + }, + setRoot: function (setting, root) { + roots[setting.treeId] = root; + }, + setZTreeTools: function (setting, zTreeTools) { + for (var i = 0, j = _init.zTreeTools.length; i < j; i++) { + _init.zTreeTools[i].apply(this, arguments); + } + }, + transformToArrayFormat: function (setting, nodes) { + if (!nodes) return []; + var r = []; + if (tools.isArray(nodes)) { + for (var i = 0, l = nodes.length; i < l; i++) { + var node = nodes[i]; + _do(node); + } + } else { + _do(nodes); + } + return r; + + function _do(_node) { + r.push(_node); + var children = data.nodeChildren(setting, _node); + if (children) { + r = r.concat(data.transformToArrayFormat(setting, children)); + } + } + }, + transformTozTreeFormat: function (setting, sNodes) { + var i, l, + key = setting.data.simpleData.idKey, + parentKey = setting.data.simpleData.pIdKey; + if (!key || key == "" || !sNodes) return []; + + if (tools.isArray(sNodes)) { + var r = []; + var tmpMap = {}; + for (i = 0, l = sNodes.length; i < l; i++) { + tmpMap[sNodes[i][key]] = sNodes[i]; + } + for (i = 0, l = sNodes.length; i < l; i++) { + var p = tmpMap[sNodes[i][parentKey]]; + if (p && sNodes[i][key] != sNodes[i][parentKey]) { + var children = data.nodeChildren(setting, p); + if (!children) { + children = data.nodeChildren(setting, p, []); + } + children.push(sNodes[i]); + } else { + r.push(sNodes[i]); + } + } + return r; + } else { + return [sNodes]; + } + } + }, + //method of event proxy + event = { + bindEvent: function (setting) { + for (var i = 0, j = _init.bind.length; i < j; i++) { + _init.bind[i].apply(this, arguments); + } + }, + unbindEvent: function (setting) { + for (var i = 0, j = _init.unbind.length; i < j; i++) { + _init.unbind[i].apply(this, arguments); + } + }, + bindTree: function (setting) { + var eventParam = { + treeId: setting.treeId + }, + o = setting.treeObj; + if (!setting.view.txtSelectedEnable) { + // for can't select text + o.bind('selectstart', handler.onSelectStart).css({ + "-moz-user-select": "-moz-none" + }); + } + o.bind('click', eventParam, event.proxy); + o.bind('dblclick', eventParam, event.proxy); + o.bind('mouseover', eventParam, event.proxy); + o.bind('mouseout', eventParam, event.proxy); + o.bind('mousedown', eventParam, event.proxy); + o.bind('mouseup', eventParam, event.proxy); + o.bind('contextmenu', eventParam, event.proxy); + }, + unbindTree: function (setting) { + var o = setting.treeObj; + o.unbind('selectstart', handler.onSelectStart) + .unbind('click', event.proxy) + .unbind('dblclick', event.proxy) + .unbind('mouseover', event.proxy) + .unbind('mouseout', event.proxy) + .unbind('mousedown', event.proxy) + .unbind('mouseup', event.proxy) + .unbind('contextmenu', event.proxy); + }, + doProxy: function (e) { + var results = []; + for (var i = 0, j = _init.proxys.length; i < j; i++) { + var proxyResult = _init.proxys[i].apply(this, arguments); + results.push(proxyResult); + if (proxyResult.stop) { + break; + } + } + return results; + }, + proxy: function (e) { + var setting = data.getSetting(e.data.treeId); + if (!tools.uCanDo(setting, e)) return true; + var results = event.doProxy(e), + r = true, x = false; + for (var i = 0, l = results.length; i < l; i++) { + var proxyResult = results[i]; + if (proxyResult.nodeEventCallback) { + x = true; + r = proxyResult.nodeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r; + } + if (proxyResult.treeEventCallback) { + x = true; + r = proxyResult.treeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r; + } + } + return r; + } + }, + //method of event handler + handler = { + onSwitchNode: function (event, node) { + var setting = data.getSetting(event.data.treeId); + if (node.open) { + if (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false) return true; + data.getRoot(setting).expandTriggerFlag = true; + view.switchNode(setting, node); + } else { + if (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false) return true; + data.getRoot(setting).expandTriggerFlag = true; + view.switchNode(setting, node); + } + return true; + }, + onClickNode: function (event, node) { + var setting = data.getSetting(event.data.treeId), + clickFlag = ((setting.view.autoCancelSelected && (event.ctrlKey || event.metaKey)) && data.isSelectedNode(setting, node)) ? 0 : (setting.view.autoCancelSelected && (event.ctrlKey || event.metaKey) && setting.view.selectedMulti) ? 2 : 1; + if (tools.apply(setting.callback.beforeClick, [setting.treeId, node, clickFlag], true) == false) return true; + if (clickFlag === 0) { + view.cancelPreSelectedNode(setting, node); + } else { + view.selectNode(setting, node, clickFlag === 2); + } + setting.treeObj.trigger(consts.event.CLICK, [event, setting.treeId, node, clickFlag]); + return true; + }, + onZTreeMousedown: function (event, node) { + var setting = data.getSetting(event.data.treeId); + if (tools.apply(setting.callback.beforeMouseDown, [setting.treeId, node], true)) { + tools.apply(setting.callback.onMouseDown, [event, setting.treeId, node]); + } + return true; + }, + onZTreeMouseup: function (event, node) { + var setting = data.getSetting(event.data.treeId); + if (tools.apply(setting.callback.beforeMouseUp, [setting.treeId, node], true)) { + tools.apply(setting.callback.onMouseUp, [event, setting.treeId, node]); + } + return true; + }, + onZTreeDblclick: function (event, node) { + var setting = data.getSetting(event.data.treeId); + if (tools.apply(setting.callback.beforeDblClick, [setting.treeId, node], true)) { + tools.apply(setting.callback.onDblClick, [event, setting.treeId, node]); + } + return true; + }, + onZTreeContextmenu: function (event, node) { + var setting = data.getSetting(event.data.treeId); + if (tools.apply(setting.callback.beforeRightClick, [setting.treeId, node], true)) { + tools.apply(setting.callback.onRightClick, [event, setting.treeId, node]); + } + return (typeof setting.callback.onRightClick) != "function"; + }, + onSelectStart: function (e) { + var n = e.originalEvent.srcElement.nodeName.toLowerCase(); + return (n === "input" || n === "textarea"); + } + }, + //method of tools for zTree + tools = { + apply: function (fun, param, defaultValue) { + if ((typeof fun) == "function") { + return fun.apply(zt, param ? param : []); + } + return defaultValue; + }, + canAsync: function (setting, node) { + var children = data.nodeChildren(setting, node); + var isParent = data.nodeIsParent(setting, node); + return (setting.async.enable && node && isParent && !(node.zAsync || (children && children.length > 0))); + }, + clone: function (obj) { + if (obj === null) return null; + var o = tools.isArray(obj) ? [] : {}; + for (var i in obj) { + o[i] = (obj[i] instanceof Date) ? new Date(obj[i].getTime()) : (typeof obj[i] === "object" ? tools.clone(obj[i]) : obj[i]); + } + return o; + }, + eqs: function (str1, str2) { + return str1.toLowerCase() === str2.toLowerCase(); + }, + isArray: function (arr) { + return Object.prototype.toString.apply(arr) === "[object Array]"; + }, + isElement: function (o) { + return ( + typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2 + o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName === "string" + ); + }, + $: function (node, exp, setting) { + if (!!exp && typeof exp != "string") { + setting = exp; + exp = ""; + } + if (typeof node == "string") { + return $(node, setting ? setting.treeObj.get(0).ownerDocument : null); + } else { + return $("#" + node.tId + exp, setting ? setting.treeObj : null); + } + }, + getMDom: function (setting, curDom, targetExpr) { + if (!curDom) return null; + while (curDom && curDom.id !== setting.treeId) { + for (var i = 0, l = targetExpr.length; curDom.tagName && i < l; i++) { + if (tools.eqs(curDom.tagName, targetExpr[i].tagName) && curDom.getAttribute(targetExpr[i].attrName) !== null) { + return curDom; + } + } + curDom = curDom.parentNode; + } + return null; + }, + getNodeMainDom: function (target) { + return ($(target).parent("li").get(0) || $(target).parentsUntil("li").parent().get(0)); + }, + isChildOrSelf: function (dom, parentId) { + return ($(dom).closest("#" + parentId).length > 0); + }, + uCanDo: function (setting, e) { + return true; + } + }, + //method of operate ztree dom + view = { + addNodes: function (setting, parentNode, index, newNodes, isSilent) { + var isParent = data.nodeIsParent(setting, parentNode); + if (setting.data.keep.leaf && parentNode && !isParent) { + return; + } + if (!tools.isArray(newNodes)) { + newNodes = [newNodes]; + } + if (setting.data.simpleData.enable) { + newNodes = data.transformTozTreeFormat(setting, newNodes); + } + if (parentNode) { + var target_switchObj = $$(parentNode, consts.id.SWITCH, setting), + target_icoObj = $$(parentNode, consts.id.ICON, setting), + target_ulObj = $$(parentNode, consts.id.UL, setting); + + if (!parentNode.open) { + view.replaceSwitchClass(parentNode, target_switchObj, consts.folder.CLOSE); + view.replaceIcoClass(parentNode, target_icoObj, consts.folder.CLOSE); + parentNode.open = false; + target_ulObj.css({ + "display": "none" + }); + } + + data.addNodesData(setting, parentNode, index, newNodes); + view.createNodes(setting, parentNode.level + 1, newNodes, parentNode, index); + if (!isSilent) { + view.expandCollapseParentNode(setting, parentNode, true); + } + } else { + data.addNodesData(setting, data.getRoot(setting), index, newNodes); + view.createNodes(setting, 0, newNodes, null, index); + } + }, + appendNodes: function (setting, level, nodes, parentNode, index, initFlag, openFlag) { + if (!nodes) return []; + var html = []; + + var tmpPNode = (parentNode) ? parentNode : data.getRoot(setting), + tmpPChild = data.nodeChildren(setting, tmpPNode), + isFirstNode, isLastNode; + + if (!tmpPChild || index >= tmpPChild.length - nodes.length) { + index = -1; + } + + for (var i = 0, l = nodes.length; i < l; i++) { + var node = nodes[i]; + if (initFlag) { + isFirstNode = ((index === 0 || tmpPChild.length == nodes.length) && (i == 0)); + isLastNode = (index < 0 && i == (nodes.length - 1)); + data.initNode(setting, level, node, parentNode, isFirstNode, isLastNode, openFlag); + data.addNodeCache(setting, node); + } + var isParent = data.nodeIsParent(setting, node); + + var childHtml = []; + var children = data.nodeChildren(setting, node); + if (children && children.length > 0) { + //make child html first, because checkType + childHtml = view.appendNodes(setting, level + 1, children, node, -1, initFlag, openFlag && node.open); + } + if (openFlag) { + view.makeDOMNodeMainBefore(html, setting, node); + view.makeDOMNodeLine(html, setting, node); + data.getBeforeA(setting, node, html); + view.makeDOMNodeNameBefore(html, setting, node); + data.getInnerBeforeA(setting, node, html); + view.makeDOMNodeIcon(html, setting, node); + data.getInnerAfterA(setting, node, html); + view.makeDOMNodeNameAfter(html, setting, node); + data.getAfterA(setting, node, html); + if (isParent && node.open) { + view.makeUlHtml(setting, node, html, childHtml.join('')); + } + view.makeDOMNodeMainAfter(html, setting, node); + data.addCreatedNode(setting, node); + } + } + return html; + }, + appendParentULDom: function (setting, node) { + var html = [], + nObj = $$(node, setting); + if (!nObj.get(0) && !!node.parentTId) { + view.appendParentULDom(setting, node.getParentNode()); + nObj = $$(node, setting); + } + var ulObj = $$(node, consts.id.UL, setting); + if (ulObj.get(0)) { + ulObj.remove(); + } + var children = data.nodeChildren(setting, node), + childHtml = view.appendNodes(setting, node.level + 1, children, node, -1, false, true); + view.makeUlHtml(setting, node, html, childHtml.join('')); + nObj.append(html.join('')); + }, + asyncNode: function (setting, node, isSilent, callback) { + var i, l; + var isParent = data.nodeIsParent(setting, node); + if (node && !isParent) { + tools.apply(callback); + return false; + } else if (node && node.isAjaxing) { + return false; + } else if (tools.apply(setting.callback.beforeAsync, [setting.treeId, node], true) == false) { + tools.apply(callback); + return false; + } + if (node) { + node.isAjaxing = true; + var icoObj = $$(node, consts.id.ICON, setting); + icoObj.attr({"style": "", "class": consts.className.BUTTON + " " + consts.className.ICO_LOADING}); + } + + var tmpParam = {}; + var autoParam = tools.apply(setting.async.autoParam, [setting.treeId, node], setting.async.autoParam); + for (i = 0, l = autoParam.length; node && i < l; i++) { + var pKey = autoParam[i].split("="), spKey = pKey; + if (pKey.length > 1) { + spKey = pKey[1]; + pKey = pKey[0]; + } + tmpParam[spKey] = node[pKey]; + } + var otherParam = tools.apply(setting.async.otherParam, [setting.treeId, node], setting.async.otherParam); + if (tools.isArray(otherParam)) { + for (i = 0, l = otherParam.length; i < l; i += 2) { + tmpParam[otherParam[i]] = otherParam[i + 1]; + } + } else { + for (var p in otherParam) { + tmpParam[p] = otherParam[p]; + } + } + + var _tmpV = data.getRoot(setting)._ver; + $.ajax({ + contentType: setting.async.contentType, + cache: false, + type: setting.async.type, + url: tools.apply(setting.async.url, [setting.treeId, node], setting.async.url), + data: setting.async.contentType.indexOf('application/json') > -1 ? JSON.stringify(tmpParam) : tmpParam, + dataType: setting.async.dataType, + headers: setting.async.headers, + xhrFields: setting.async.xhrFields, + success: function (msg) { + if (_tmpV != data.getRoot(setting)._ver) { + return; + } + var newNodes = []; + try { + if (!msg || msg.length == 0) { + newNodes = []; + } else if (typeof msg == "string") { + newNodes = eval("(" + msg + ")"); + } else { + newNodes = msg; + } + } catch (err) { + newNodes = msg; + } + + if (node) { + node.isAjaxing = null; + node.zAsync = true; + } + view.setNodeLineIcos(setting, node); + if (newNodes && newNodes !== "") { + newNodes = tools.apply(setting.async.dataFilter, [setting.treeId, node, newNodes], newNodes); + view.addNodes(setting, node, -1, !!newNodes ? tools.clone(newNodes) : [], !!isSilent); + } else { + view.addNodes(setting, node, -1, [], !!isSilent); + } + setting.treeObj.trigger(consts.event.ASYNC_SUCCESS, [setting.treeId, node, msg]); + tools.apply(callback); + }, + error: function (XMLHttpRequest, textStatus, errorThrown) { + if (_tmpV != data.getRoot(setting)._ver) { + return; + } + if (node) node.isAjaxing = null; + view.setNodeLineIcos(setting, node); + setting.treeObj.trigger(consts.event.ASYNC_ERROR, [setting.treeId, node, XMLHttpRequest, textStatus, errorThrown]); + } + }); + return true; + }, + cancelPreSelectedNode: function (setting, node, excludeNode) { + var list = data.getRoot(setting).curSelectedList, + i, n; + for (i = list.length - 1; i >= 0; i--) { + n = list[i]; + if (node === n || (!node && (!excludeNode || excludeNode !== n))) { + $$(n, consts.id.A, setting).removeClass(consts.node.CURSELECTED); + if (node) { + data.removeSelectedNode(setting, node); + break; + } else { + list.splice(i, 1); + setting.treeObj.trigger(consts.event.UNSELECTED, [setting.treeId, n]); + } + } + } + }, + createNodeCallback: function (setting) { + if (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) { + var root = data.getRoot(setting); + while (root.createdNodes.length > 0) { + var node = root.createdNodes.shift(); + tools.apply(setting.view.addDiyDom, [setting.treeId, node]); + if (!!setting.callback.onNodeCreated) { + setting.treeObj.trigger(consts.event.NODECREATED, [setting.treeId, node]); + } + } + } + }, + createNodes: function (setting, level, nodes, parentNode, index) { + if (!nodes || nodes.length == 0) return; + var root = data.getRoot(setting), + openFlag = !parentNode || parentNode.open || !!$$(data.nodeChildren(setting, parentNode)[0], setting).get(0); + root.createdNodes = []; + var zTreeHtml = view.appendNodes(setting, level, nodes, parentNode, index, true, openFlag), + parentObj, nextObj; + + if (!parentNode) { + parentObj = setting.treeObj; + //setting.treeObj.append(zTreeHtml.join('')); + } else { + var ulObj = $$(parentNode, consts.id.UL, setting); + if (ulObj.get(0)) { + parentObj = ulObj; + //ulObj.append(zTreeHtml.join('')); + } + } + if (parentObj) { + if (index >= 0) { + nextObj = parentObj.children()[index]; + } + if (index >= 0 && nextObj) { + $(nextObj).before(zTreeHtml.join('')); + } else { + parentObj.append(zTreeHtml.join('')); + } + } + + view.createNodeCallback(setting); + }, + destroy: function (setting) { + if (!setting) return; + data.initCache(setting); + data.initRoot(setting); + event.unbindTree(setting); + event.unbindEvent(setting); + setting.treeObj.empty(); + delete settings[setting.treeId]; + }, + expandCollapseNode: function (setting, node, expandFlag, animateFlag, callback) { + var root = data.getRoot(setting); + var tmpCb, _callback; + if (!node) { + tools.apply(callback, []); + return; + } + var children = data.nodeChildren(setting, node); + var isParent = data.nodeIsParent(setting, node); + if (root.expandTriggerFlag) { + _callback = callback; + tmpCb = function () { + if (_callback) _callback(); + if (node.open) { + setting.treeObj.trigger(consts.event.EXPAND, [setting.treeId, node]); + } else { + setting.treeObj.trigger(consts.event.COLLAPSE, [setting.treeId, node]); + } + }; + callback = tmpCb; + root.expandTriggerFlag = false; + } + if (!node.open && isParent && ((!$$(node, consts.id.UL, setting).get(0)) || (children && children.length > 0 && !$$(children[0], setting).get(0)))) { + view.appendParentULDom(setting, node); + view.createNodeCallback(setting); + } + if (node.open == expandFlag) { + tools.apply(callback, []); + return; + } + var ulObj = $$(node, consts.id.UL, setting), + switchObj = $$(node, consts.id.SWITCH, setting), + icoObj = $$(node, consts.id.ICON, setting); + + if (isParent) { + node.open = !node.open; + if (node.iconOpen && node.iconClose) { + icoObj.attr("style", view.makeNodeIcoStyle(setting, node)); + } + + if (node.open) { + view.replaceSwitchClass(node, switchObj, consts.folder.OPEN); + view.replaceIcoClass(node, icoObj, consts.folder.OPEN); + if (animateFlag == false || setting.view.expandSpeed == "") { + ulObj.show(); + tools.apply(callback, []); + } else { + if (children && children.length > 0) { + ulObj.slideDown(setting.view.expandSpeed, callback); + } else { + ulObj.show(); + tools.apply(callback, []); + } + } + } else { + view.replaceSwitchClass(node, switchObj, consts.folder.CLOSE); + view.replaceIcoClass(node, icoObj, consts.folder.CLOSE); + if (animateFlag == false || setting.view.expandSpeed == "" || !(children && children.length > 0)) { + ulObj.hide(); + tools.apply(callback, []); + } else { + ulObj.slideUp(setting.view.expandSpeed, callback); + } + } + } else { + tools.apply(callback, []); + } + }, + expandCollapseParentNode: function (setting, node, expandFlag, animateFlag, callback) { + if (!node) return; + if (!node.parentTId) { + view.expandCollapseNode(setting, node, expandFlag, animateFlag, callback); + return; + } else { + view.expandCollapseNode(setting, node, expandFlag, animateFlag); + } + if (node.parentTId) { + view.expandCollapseParentNode(setting, node.getParentNode(), expandFlag, animateFlag, callback); + } + }, + expandCollapseSonNode: function (setting, node, expandFlag, animateFlag, callback) { + var root = data.getRoot(setting), + treeNodes = (node) ? data.nodeChildren(setting, node) : data.nodeChildren(setting, root), + selfAnimateSign = (node) ? false : animateFlag, + expandTriggerFlag = data.getRoot(setting).expandTriggerFlag; + data.getRoot(setting).expandTriggerFlag = false; + if (treeNodes) { + for (var i = 0, l = treeNodes.length; i < l; i++) { + if (treeNodes[i]) view.expandCollapseSonNode(setting, treeNodes[i], expandFlag, selfAnimateSign); + } + } + data.getRoot(setting).expandTriggerFlag = expandTriggerFlag; + view.expandCollapseNode(setting, node, expandFlag, animateFlag, callback); + }, + isSelectedNode: function (setting, node) { + if (!node) { + return false; + } + var list = data.getRoot(setting).curSelectedList, + i; + for (i = list.length - 1; i >= 0; i--) { + if (node === list[i]) { + return true; + } + } + return false; + }, + makeDOMNodeIcon: function (html, setting, node) { + var nameStr = data.nodeName(setting, node), + name = setting.view.nameIsHTML ? nameStr : nameStr.replace(/&/g, '&').replace(//g, '>'); + html.push("", name, ""); + }, + makeDOMNodeLine: function (html, setting, node) { + html.push(""); + }, + makeDOMNodeMainAfter: function (html, setting, node) { + html.push(""); + }, + makeDOMNodeMainBefore: function (html, setting, node) { + html.push("
  • "); + }, + makeDOMNodeNameAfter: function (html, setting, node) { + html.push(""); + }, + makeDOMNodeNameBefore: function (html, setting, node) { + var title = data.nodeTitle(setting, node), + url = view.makeNodeUrl(setting, node), + fontcss = view.makeNodeFontCss(setting, node), + nodeClasses = view.makeNodeClasses(setting, node), + fontStyle = []; + for (var f in fontcss) { + fontStyle.push(f, ":", fontcss[f], ";"); + } + html.push(" 0) ? " href='" + url + "'" : ""), " target='", view.makeNodeTarget(node), "' style='", fontStyle.join(''), + "'"); + if (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle) && title) { + html.push("title='", title.replace(/'/g, "'").replace(//g, '>'), "'"); + } + html.push(">"); + }, + makeNodeFontCss: function (setting, node) { + var fontCss = tools.apply(setting.view.fontCss, [setting.treeId, node], setting.view.fontCss); + return (fontCss && ((typeof fontCss) != "function")) ? fontCss : {}; + }, + makeNodeClasses: function (setting, node) { + var classes = tools.apply(setting.view.nodeClasses, [setting.treeId, node], setting.view.nodeClasses); + return (classes && (typeof classes !== "function")) ? classes : {add:[], remove:[]}; + }, + makeNodeIcoClass: function (setting, node) { + var icoCss = ["ico"]; + if (!node.isAjaxing) { + var isParent = data.nodeIsParent(setting, node); + icoCss[0] = (node.iconSkin ? node.iconSkin + "_" : "") + icoCss[0]; + if (isParent) { + icoCss.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE); + } else { + icoCss.push(consts.folder.DOCU); + } + } + return consts.className.BUTTON + " " + icoCss.join('_'); + }, + makeNodeIcoStyle: function (setting, node) { + var icoStyle = []; + if (!node.isAjaxing) { + var isParent = data.nodeIsParent(setting, node); + var icon = (isParent && node.iconOpen && node.iconClose) ? (node.open ? node.iconOpen : node.iconClose) : node[setting.data.key.icon]; + if (icon) icoStyle.push("background:url(", icon, ") 0 0 no-repeat;"); + if (setting.view.showIcon == false || !tools.apply(setting.view.showIcon, [setting.treeId, node], true)) { + icoStyle.push("display:none;"); + } + } + return icoStyle.join(''); + }, + makeNodeLineClass: function (setting, node) { + var lineClass = []; + if (setting.view.showLine) { + if (node.level == 0 && node.isFirstNode && node.isLastNode) { + lineClass.push(consts.line.ROOT); + } else if (node.level == 0 && node.isFirstNode) { + lineClass.push(consts.line.ROOTS); + } else if (node.isLastNode) { + lineClass.push(consts.line.BOTTOM); + } else { + lineClass.push(consts.line.CENTER); + } + } else { + lineClass.push(consts.line.NOLINE); + } + if (data.nodeIsParent(setting, node)) { + lineClass.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE); + } else { + lineClass.push(consts.folder.DOCU); + } + return view.makeNodeLineClassEx(node) + lineClass.join('_'); + }, + makeNodeLineClassEx: function (node) { + return consts.className.BUTTON + " " + consts.className.LEVEL + node.level + " " + consts.className.SWITCH + " "; + }, + makeNodeTarget: function (node) { + return (node.target || "_blank"); + }, + makeNodeUrl: function (setting, node) { + var urlKey = setting.data.key.url; + return node[urlKey] ? node[urlKey] : null; + }, + makeUlHtml: function (setting, node, html, content) { + html.push("
      "); + html.push(content); + html.push("
    "); + }, + makeUlLineClass: function (setting, node) { + return ((setting.view.showLine && !node.isLastNode) ? consts.line.LINE : ""); + }, + removeChildNodes: function (setting, node) { + if (!node) return; + var nodes = data.nodeChildren(setting, node); + if (!nodes) return; + + for (var i = 0, l = nodes.length; i < l; i++) { + data.removeNodeCache(setting, nodes[i]); + } + data.removeSelectedNode(setting); + delete node[setting.data.key.children]; + + if (!setting.data.keep.parent) { + data.nodeIsParent(setting, node, false); + node.open = false; + var tmp_switchObj = $$(node, consts.id.SWITCH, setting), + tmp_icoObj = $$(node, consts.id.ICON, setting); + view.replaceSwitchClass(node, tmp_switchObj, consts.folder.DOCU); + view.replaceIcoClass(node, tmp_icoObj, consts.folder.DOCU); + $$(node, consts.id.UL, setting).remove(); + } else { + $$(node, consts.id.UL, setting).empty(); + } + }, + scrollIntoView: function (setting, dom) { + if (!dom) { + return; + } + // support IE 7 / 8 + if (typeof Element === 'undefined' || typeof HTMLElement === 'undefined') { + var contRect = setting.treeObj.get(0).getBoundingClientRect(), + findMeRect = dom.getBoundingClientRect(); + if (findMeRect.top < contRect.top || findMeRect.bottom > contRect.bottom + || findMeRect.right > contRect.right || findMeRect.left < contRect.left) { + dom.scrollIntoView(); + } + return; + } + // CC-BY jocki84@googlemail.com, https://gist.github.com/jocki84/6ffafd003387179a988e + if (!Element.prototype.scrollIntoViewIfNeeded) { + Element.prototype.scrollIntoViewIfNeeded = function (centerIfNeeded) { + "use strict"; + + function makeRange(start, length) { + return {"start": start, "length": length, "end": start + length}; + } + + function coverRange(inner, outer) { + if ( + false === centerIfNeeded || + (outer.start < inner.end && inner.start < outer.end) + ) { + return Math.max( + inner.end - outer.length, + Math.min(outer.start, inner.start) + ); + } + return (inner.start + inner.end - outer.length) / 2; + } + + function makePoint(x, y) { + return { + "x": x, + "y": y, + "translate": function translate(dX, dY) { + return makePoint(x + dX, y + dY); + } + }; + } + + function absolute(elem, pt) { + while (elem) { + pt = pt.translate(elem.offsetLeft, elem.offsetTop); + elem = elem.offsetParent; + } + return pt; + } + + var target = absolute(this, makePoint(0, 0)), + extent = makePoint(this.offsetWidth, this.offsetHeight), + elem = this.parentNode, + origin; + + while (elem instanceof HTMLElement) { + // Apply desired scroll amount. + origin = absolute(elem, makePoint(elem.clientLeft, elem.clientTop)); + elem.scrollLeft = coverRange( + makeRange(target.x - origin.x, extent.x), + makeRange(elem.scrollLeft, elem.clientWidth) + ); + elem.scrollTop = coverRange( + makeRange(target.y - origin.y, extent.y), + makeRange(elem.scrollTop, elem.clientHeight) + ); + + // Determine actual scroll amount by reading back scroll properties. + target = target.translate(-elem.scrollLeft, -elem.scrollTop); + elem = elem.parentNode; + } + }; + } + dom.scrollIntoViewIfNeeded(); + }, + setFirstNode: function (setting, parentNode) { + var children = data.nodeChildren(setting, parentNode); + if (children.length > 0) { + children[0].isFirstNode = true; + } + }, + setLastNode: function (setting, parentNode) { + var children = data.nodeChildren(setting, parentNode); + if (children.length > 0) { + children[children.length - 1].isLastNode = true; + } + }, + removeNode: function (setting, node) { + var root = data.getRoot(setting), + parentNode = (node.parentTId) ? node.getParentNode() : root; + + node.isFirstNode = false; + node.isLastNode = false; + node.getPreNode = function () { + return null; + }; + node.getNextNode = function () { + return null; + }; + + if (!data.getNodeCache(setting, node.tId)) { + return; + } + + $$(node, setting).remove(); + data.removeNodeCache(setting, node); + data.removeSelectedNode(setting, node); + + var children = data.nodeChildren(setting, parentNode); + for (var i = 0, l = children.length; i < l; i++) { + if (children[i].tId == node.tId) { + children.splice(i, 1); + break; + } + } + view.setFirstNode(setting, parentNode); + view.setLastNode(setting, parentNode); + + var tmp_ulObj, tmp_switchObj, tmp_icoObj, + childLength = children.length; + + //repair nodes old parent + if (!setting.data.keep.parent && childLength == 0) { + //old parentNode has no child nodes + data.nodeIsParent(setting, parentNode, false); + parentNode.open = false; + delete parentNode[setting.data.key.children]; + tmp_ulObj = $$(parentNode, consts.id.UL, setting); + tmp_switchObj = $$(parentNode, consts.id.SWITCH, setting); + tmp_icoObj = $$(parentNode, consts.id.ICON, setting); + view.replaceSwitchClass(parentNode, tmp_switchObj, consts.folder.DOCU); + view.replaceIcoClass(parentNode, tmp_icoObj, consts.folder.DOCU); + tmp_ulObj.css("display", "none"); + + } else if (setting.view.showLine && childLength > 0) { + //old parentNode has child nodes + var newLast = children[childLength - 1]; + tmp_ulObj = $$(newLast, consts.id.UL, setting); + tmp_switchObj = $$(newLast, consts.id.SWITCH, setting); + tmp_icoObj = $$(newLast, consts.id.ICON, setting); + if (parentNode == root) { + if (children.length == 1) { + //node was root, and ztree has only one root after move node + view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.ROOT); + } else { + var tmp_first_switchObj = $$(children[0], consts.id.SWITCH, setting); + view.replaceSwitchClass(children[0], tmp_first_switchObj, consts.line.ROOTS); + view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM); + } + } else { + view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM); + } + tmp_ulObj.removeClass(consts.line.LINE); + } + }, + replaceIcoClass: function (node, obj, newName) { + if (!obj || node.isAjaxing) return; + var tmpName = obj.attr("class"); + if (tmpName == undefined) return; + var tmpList = tmpName.split("_"); + switch (newName) { + case consts.folder.OPEN: + case consts.folder.CLOSE: + case consts.folder.DOCU: + tmpList[tmpList.length - 1] = newName; + break; + } + obj.attr("class", tmpList.join("_")); + }, + replaceSwitchClass: function (node, obj, newName) { + if (!obj) return; + var tmpName = obj.attr("class"); + if (tmpName == undefined) return; + var tmpList = tmpName.split("_"); + switch (newName) { + case consts.line.ROOT: + case consts.line.ROOTS: + case consts.line.CENTER: + case consts.line.BOTTOM: + case consts.line.NOLINE: + tmpList[0] = view.makeNodeLineClassEx(node) + newName; + break; + case consts.folder.OPEN: + case consts.folder.CLOSE: + case consts.folder.DOCU: + tmpList[1] = newName; + break; + } + obj.attr("class", tmpList.join("_")); + if (newName !== consts.folder.DOCU) { + obj.removeAttr("disabled"); + } else { + obj.attr("disabled", "disabled"); + } + }, + selectNode: function (setting, node, addFlag) { + if (!addFlag) { + view.cancelPreSelectedNode(setting, null, node); + } + $$(node, consts.id.A, setting).addClass(consts.node.CURSELECTED); + data.addSelectedNode(setting, node); + setting.treeObj.trigger(consts.event.SELECTED, [setting.treeId, node]); + }, + setNodeFontCss: function (setting, treeNode) { + var aObj = $$(treeNode, consts.id.A, setting), + fontCss = view.makeNodeFontCss(setting, treeNode); + if (fontCss) { + aObj.css(fontCss); + } + }, + setNodeClasses: function (setting, treeNode) { + var aObj = $$(treeNode, consts.id.A, setting), + classes = view.makeNodeClasses(setting, treeNode); + if ('add' in classes && classes.add.length) { + aObj.addClass(classes.add.join(' ')); + } + if ('remove' in classes && classes.remove.length) { + aObj.removeClass(classes.remove.join(' ')); + } + }, + setNodeLineIcos: function (setting, node) { + if (!node) return; + var switchObj = $$(node, consts.id.SWITCH, setting), + ulObj = $$(node, consts.id.UL, setting), + icoObj = $$(node, consts.id.ICON, setting), + ulLine = view.makeUlLineClass(setting, node); + if (ulLine.length == 0) { + ulObj.removeClass(consts.line.LINE); + } else { + ulObj.addClass(ulLine); + } + switchObj.attr("class", view.makeNodeLineClass(setting, node)); + if (data.nodeIsParent(setting, node)) { + switchObj.removeAttr("disabled"); + } else { + switchObj.attr("disabled", "disabled"); + } + icoObj.removeAttr("style"); + icoObj.attr("style", view.makeNodeIcoStyle(setting, node)); + icoObj.attr("class", view.makeNodeIcoClass(setting, node)); + }, + setNodeName: function (setting, node) { + var title = data.nodeTitle(setting, node), + nObj = $$(node, consts.id.SPAN, setting); + nObj.empty(); + if (setting.view.nameIsHTML) { + nObj.html(data.nodeName(setting, node)); + } else { + nObj.text(data.nodeName(setting, node)); + } + if (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle)) { + var aObj = $$(node, consts.id.A, setting); + aObj.attr("title", !title ? "" : title); + } + }, + setNodeTarget: function (setting, node) { + var aObj = $$(node, consts.id.A, setting); + aObj.attr("target", view.makeNodeTarget(node)); + }, + setNodeUrl: function (setting, node) { + var aObj = $$(node, consts.id.A, setting), + url = view.makeNodeUrl(setting, node); + if (url == null || url.length == 0) { + aObj.removeAttr("href"); + } else { + aObj.attr("href", url); + } + }, + switchNode: function (setting, node) { + if (node.open || !tools.canAsync(setting, node)) { + view.expandCollapseNode(setting, node, !node.open); + } else if (setting.async.enable) { + if (!view.asyncNode(setting, node)) { + view.expandCollapseNode(setting, node, !node.open); + return; + } + } else if (node) { + view.expandCollapseNode(setting, node, !node.open); + } + } + }; + // zTree defind + $.fn.zTree = { + consts: _consts, + _z: { + tools: tools, + view: view, + event: event, + data: data + }, + getZTreeObj: function (treeId) { + var o = data.getZTreeTools(treeId); + return o ? o : null; + }, + destroy: function (treeId) { + if (!!treeId && treeId.length > 0) { + view.destroy(data.getSetting(treeId)); + } else { + for (var s in settings) { + view.destroy(settings[s]); + } + } + }, + init: function (obj, zSetting, zNodes) { + var setting = tools.clone(_setting); + $.extend(true, setting, zSetting); + setting.treeId = obj.attr("id"); + setting.treeObj = obj; + setting.treeObj.empty(); + settings[setting.treeId] = setting; + //For some older browser,(e.g., ie6) + if (typeof document.body.style.maxHeight === "undefined") { + setting.view.expandSpeed = ""; + } + data.initRoot(setting); + var root = data.getRoot(setting); + zNodes = zNodes ? tools.clone(tools.isArray(zNodes) ? zNodes : [zNodes]) : []; + if (setting.data.simpleData.enable) { + data.nodeChildren(setting, root, data.transformTozTreeFormat(setting, zNodes)); + } else { + data.nodeChildren(setting, root, zNodes); + } + + data.initCache(setting); + event.unbindTree(setting); + event.bindTree(setting); + event.unbindEvent(setting); + event.bindEvent(setting); + + var zTreeTools = { + setting: setting, + addNodes: function (parentNode, index, newNodes, isSilent) { + if (!parentNode) parentNode = null; + var isParent = data.nodeIsParent(setting, parentNode); + if (parentNode && !isParent && setting.data.keep.leaf) return null; + + var i = parseInt(index, 10); + if (isNaN(i)) { + isSilent = !!newNodes; + newNodes = index; + index = -1; + } else { + index = i; + } + if (!newNodes) return null; + + + var xNewNodes = tools.clone(tools.isArray(newNodes) ? newNodes : [newNodes]); + + function addCallback() { + view.addNodes(setting, parentNode, index, xNewNodes, (isSilent == true)); + } + + if (tools.canAsync(setting, parentNode)) { + view.asyncNode(setting, parentNode, isSilent, addCallback); + } else { + addCallback(); + } + return xNewNodes; + }, + cancelSelectedNode: function (node) { + view.cancelPreSelectedNode(setting, node); + }, + destroy: function () { + view.destroy(setting); + }, + expandAll: function (expandFlag) { + expandFlag = !!expandFlag; + view.expandCollapseSonNode(setting, null, expandFlag, true); + return expandFlag; + }, + expandNode: function (node, expandFlag, sonSign, focus, callbackFlag) { + if (!node || !data.nodeIsParent(setting, node)) return null; + if (expandFlag !== true && expandFlag !== false) { + expandFlag = !node.open; + } + callbackFlag = !!callbackFlag; + + if (callbackFlag && expandFlag && (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false)) { + return null; + } else if (callbackFlag && !expandFlag && (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false)) { + return null; + } + if (expandFlag && node.parentTId) { + view.expandCollapseParentNode(setting, node.getParentNode(), expandFlag, false); + } + if (expandFlag === node.open && !sonSign) { + return null; + } + + data.getRoot(setting).expandTriggerFlag = callbackFlag; + if (!tools.canAsync(setting, node) && sonSign) { + view.expandCollapseSonNode(setting, node, expandFlag, true, showNodeFocus); + } else { + node.open = !expandFlag; + view.switchNode(this.setting, node); + showNodeFocus(); + } + return expandFlag; + + function showNodeFocus() { + var a = $$(node, consts.id.A, setting).get(0); + if (a && focus !== false) { + view.scrollIntoView(setting, a); + } + } + }, + getNodes: function () { + return data.getNodes(setting); + }, + getNodeByParam: function (key, value, parentNode) { + if (!key) return null; + return data.getNodeByParam(setting, parentNode ? data.nodeChildren(setting, parentNode) : data.getNodes(setting), key, value); + }, + getNodeByTId: function (tId) { + return data.getNodeCache(setting, tId); + }, + getNodesByParam: function (key, value, parentNode) { + if (!key) return null; + return data.getNodesByParam(setting, parentNode ? data.nodeChildren(setting, parentNode) : data.getNodes(setting), key, value); + }, + getNodesByParamFuzzy: function (key, value, parentNode) { + if (!key) return null; + return data.getNodesByParamFuzzy(setting, parentNode ? data.nodeChildren(setting, parentNode) : data.getNodes(setting), key, value); + }, + getNodesByFilter: function (filter, isSingle, parentNode, invokeParam) { + isSingle = !!isSingle; + if (!filter || (typeof filter != "function")) return (isSingle ? null : []); + return data.getNodesByFilter(setting, parentNode ? data.nodeChildren(setting, parentNode) : data.getNodes(setting), filter, isSingle, invokeParam); + }, + getNodeIndex: function (node) { + if (!node) return null; + var parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting); + var children = data.nodeChildren(setting, parentNode); + for (var i = 0, l = children.length; i < l; i++) { + if (children[i] == node) return i; + } + return -1; + }, + getSelectedNodes: function () { + var r = [], list = data.getRoot(setting).curSelectedList; + for (var i = 0, l = list.length; i < l; i++) { + r.push(list[i]); + } + return r; + }, + isSelectedNode: function (node) { + return data.isSelectedNode(setting, node); + }, + reAsyncChildNodesPromise: function (parentNode, reloadType, isSilent) { + var promise = new Promise(function (resolve, reject) { + try { + zTreeTools.reAsyncChildNodes(parentNode, reloadType, isSilent, function () { + resolve(parentNode); + }); + } catch (e) { + reject(e); + } + }); + return promise; + }, + reAsyncChildNodes: function (parentNode, reloadType, isSilent, callback) { + if (!this.setting.async.enable) return; + var isRoot = !parentNode; + if (isRoot) { + parentNode = data.getRoot(setting); + } + if (reloadType == "refresh") { + var children = data.nodeChildren(setting, parentNode); + for (var i = 0, l = children ? children.length : 0; i < l; i++) { + data.removeNodeCache(setting, children[i]); + } + data.removeSelectedNode(setting); + data.nodeChildren(setting, parentNode, []); + if (isRoot) { + this.setting.treeObj.empty(); + } else { + var ulObj = $$(parentNode, consts.id.UL, setting); + ulObj.empty(); + } + } + view.asyncNode(this.setting, isRoot ? null : parentNode, !!isSilent, callback); + }, + refresh: function () { + this.setting.treeObj.empty(); + var root = data.getRoot(setting), + nodes = data.nodeChildren(setting, root); + data.initRoot(setting); + data.nodeChildren(setting, root, nodes); + data.initCache(setting); + view.createNodes(setting, 0, data.nodeChildren(setting, root), null, -1); + }, + removeChildNodes: function (node) { + if (!node) return null; + var nodes = data.nodeChildren(setting, node); + view.removeChildNodes(setting, node); + return nodes ? nodes : null; + }, + removeNode: function (node, callbackFlag) { + if (!node) return; + callbackFlag = !!callbackFlag; + if (callbackFlag && tools.apply(setting.callback.beforeRemove, [setting.treeId, node], true) == false) return; + view.removeNode(setting, node); + if (callbackFlag) { + this.setting.treeObj.trigger(consts.event.REMOVE, [setting.treeId, node]); + } + }, + selectNode: function (node, addFlag, isSilent) { + if (!node) return; + if (tools.uCanDo(setting)) { + addFlag = setting.view.selectedMulti && addFlag; + if (node.parentTId) { + view.expandCollapseParentNode(setting, node.getParentNode(), true, false, showNodeFocus); + } else if (!isSilent) { + try { + $$(node, setting).focus().blur(); + } catch (e) { + } + } + view.selectNode(setting, node, addFlag); + } + + function showNodeFocus() { + if (isSilent) { + return; + } + var a = $$(node, setting).get(0); + view.scrollIntoView(setting, a); + } + }, + transformTozTreeNodes: function (simpleNodes) { + return data.transformTozTreeFormat(setting, simpleNodes); + }, + transformToArray: function (nodes) { + return data.transformToArrayFormat(setting, nodes); + }, + updateNode: function (node, checkTypeFlag) { + if (!node) return; + var nObj = $$(node, setting); + if (nObj.get(0) && tools.uCanDo(setting)) { + view.setNodeName(setting, node); + view.setNodeTarget(setting, node); + view.setNodeUrl(setting, node); + view.setNodeLineIcos(setting, node); + view.setNodeFontCss(setting, node); + view.setNodeClasses(setting, node); + } + } + }; + root.treeTools = zTreeTools; + data.setZTreeTools(setting, zTreeTools); + var children = data.nodeChildren(setting, root); + if (children && children.length > 0) { + view.createNodes(setting, 0, children, null, -1); + } else if (setting.async.enable && setting.async.url && setting.async.url !== '') { + view.asyncNode(setting); + } + return zTreeTools; + } + }; + + var zt = $.fn.zTree, + $$ = tools.$, + consts = zt.consts; +})(jQuery); +/* + * 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(""); + } + }, + //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); +/* + * JQuery zTree exedit + * 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 exedit + var _consts = { + event: { + DRAG: "ztree_drag", + DROP: "ztree_drop", + RENAME: "ztree_rename", + DRAGMOVE: "ztree_dragmove" + }, + id: { + EDIT: "_edit", + INPUT: "_input", + REMOVE: "_remove" + }, + move: { + TYPE_INNER: "inner", + TYPE_PREV: "prev", + TYPE_NEXT: "next" + }, + node: { + CURSELECTED_EDIT: "curSelectedNode_Edit", + TMPTARGET_TREE: "tmpTargetzTree", + TMPTARGET_NODE: "tmpTargetNode" + } + }, + //default setting of exedit + _setting = { + edit: { + enable: false, + editNameSelectAll: false, + showRemoveBtn: true, + showRenameBtn: true, + removeTitle: "remove", + renameTitle: "rename", + drag: { + autoExpandTrigger: false, + isCopy: true, + isMove: true, + prev: true, + next: true, + inner: true, + minMoveSize: 5, + borderMax: 10, + borderMin: -5, + maxShowNodeNum: 5, + autoOpenTime: 500 + } + }, + view: { + addHoverDom: null, + removeHoverDom: null + }, + callback: { + beforeDrag: null, + beforeDragOpen: null, + beforeDrop: null, + beforeEditName: null, + beforeRename: null, + onDrag: null, + onDragMove: null, + onDrop: null, + onRename: null + } + }, + //default root of exedit + _initRoot = function (setting) { + var r = data.getRoot(setting), rs = data.getRoots(); + r.curEditNode = null; + r.curEditInput = null; + r.curHoverNode = null; + r.dragFlag = 0; + r.dragNodeShowBefore = []; + r.dragMaskList = new Array(); + rs.showHoverDom = true; + }, + //default cache of exedit + _initCache = function (treeId) { + }, + //default bind event of exedit + _bindEvent = function (setting) { + var o = setting.treeObj; + var c = consts.event; + o.bind(c.RENAME, function (event, treeId, treeNode, isCancel) { + tools.apply(setting.callback.onRename, [event, treeId, treeNode, isCancel]); + }); + + o.bind(c.DRAG, function (event, srcEvent, treeId, treeNodes) { + tools.apply(setting.callback.onDrag, [srcEvent, treeId, treeNodes]); + }); + + o.bind(c.DRAGMOVE, function (event, srcEvent, treeId, treeNodes) { + tools.apply(setting.callback.onDragMove, [srcEvent, treeId, treeNodes]); + }); + + o.bind(c.DROP, function (event, srcEvent, treeId, treeNodes, targetNode, moveType, isCopy) { + tools.apply(setting.callback.onDrop, [srcEvent, treeId, treeNodes, targetNode, moveType, isCopy]); + }); + }, + _unbindEvent = function (setting) { + var o = setting.treeObj; + var c = consts.event; + o.unbind(c.RENAME); + o.unbind(c.DRAG); + o.unbind(c.DRAGMOVE); + o.unbind(c.DROP); + }, + //default event proxy of exedit + _eventProxy = function (e) { + var target = e.target, + setting = data.getSetting(e.data.treeId), + relatedTarget = e.relatedTarget, + tId = "", node = null, + nodeEventType = "", treeEventType = "", + nodeEventCallback = null, treeEventCallback = null, + tmp = null; + + if (tools.eqs(e.type, "mouseover")) { + tmp = tools.getMDom(setting, target, [{tagName: "a", attrName: "treeNode" + consts.id.A}]); + if (tmp) { + tId = tools.getNodeMainDom(tmp).id; + nodeEventType = "hoverOverNode"; + } + } else if (tools.eqs(e.type, "mouseout")) { + tmp = tools.getMDom(setting, relatedTarget, [{tagName: "a", attrName: "treeNode" + consts.id.A}]); + if (!tmp) { + tId = "remove"; + nodeEventType = "hoverOutNode"; + } + } else if (tools.eqs(e.type, "mousedown")) { + tmp = tools.getMDom(setting, target, [{tagName: "a", attrName: "treeNode" + consts.id.A}]); + if (tmp) { + tId = tools.getNodeMainDom(tmp).id; + nodeEventType = "mousedownNode"; + } + } + if (tId.length > 0) { + node = data.getNodeCache(setting, tId); + switch (nodeEventType) { + case "mousedownNode" : + nodeEventCallback = _handler.onMousedownNode; + break; + case "hoverOverNode" : + nodeEventCallback = _handler.onHoverOverNode; + break; + case "hoverOutNode" : + nodeEventCallback = _handler.onHoverOutNode; + break; + } + } + var proxyResult = { + stop: false, + node: node, + nodeEventType: nodeEventType, + nodeEventCallback: nodeEventCallback, + treeEventType: treeEventType, + treeEventCallback: treeEventCallback + }; + return proxyResult + }, + //default init node of exedit + _initNode = function (setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) { + if (!n) return; + n.isHover = false; + n.editNameFlag = false; + }, + //update zTreeObj, add method of edit + _zTreeTools = function (setting, zTreeTools) { + zTreeTools.cancelEditName = function (newName) { + var root = data.getRoot(this.setting); + if (!root.curEditNode) return; + view.cancelCurEditNode(this.setting, newName ? newName : null, true); + } + zTreeTools.copyNode = function (targetNode, node, moveType, isSilent) { + if (!node) return null; + var isParent = data.nodeIsParent(setting, targetNode); + if (targetNode && !isParent && this.setting.data.keep.leaf && moveType === consts.move.TYPE_INNER) return null; + var _this = this, + newNode = tools.clone(node); + if (!targetNode) { + targetNode = null; + moveType = consts.move.TYPE_INNER; + } + if (moveType == consts.move.TYPE_INNER) { + function copyCallback() { + view.addNodes(_this.setting, targetNode, -1, [newNode], isSilent); + } + + if (tools.canAsync(this.setting, targetNode)) { + view.asyncNode(this.setting, targetNode, isSilent, copyCallback); + } else { + copyCallback(); + } + } else { + view.addNodes(this.setting, targetNode.parentNode, -1, [newNode], isSilent); + view.moveNode(this.setting, targetNode, newNode, moveType, false, isSilent); + } + return newNode; + } + zTreeTools.editName = function (node) { + if (!node || !node.tId || node !== data.getNodeCache(this.setting, node.tId)) return; + if (node.parentTId) view.expandCollapseParentNode(this.setting, node.getParentNode(), true); + view.editNode(this.setting, node) + } + zTreeTools.moveNode = function (targetNode, node, moveType, isSilent) { + if (!node) return node; + var isParent = data.nodeIsParent(setting, targetNode); + if (targetNode && !isParent && this.setting.data.keep.leaf && moveType === consts.move.TYPE_INNER) { + return null; + } else if (targetNode && ((node.parentTId == targetNode.tId && moveType == consts.move.TYPE_INNER) || $$(node, this.setting).find("#" + targetNode.tId).length > 0)) { + return null; + } else if (!targetNode) { + targetNode = null; + } + var _this = this; + + function moveCallback() { + view.moveNode(_this.setting, targetNode, node, moveType, false, isSilent); + } + + if (tools.canAsync(this.setting, targetNode) && moveType === consts.move.TYPE_INNER) { + view.asyncNode(this.setting, targetNode, isSilent, moveCallback); + } else { + moveCallback(); + } + return node; + } + zTreeTools.setEditable = function (editable) { + this.setting.edit.enable = editable; + return this.refresh(); + } + }, + //method of operate data + _data = { + setSonNodeLevel: function (setting, parentNode, node) { + if (!node) return; + var children = data.nodeChildren(setting, node); + var oldLevel = node.level; + node.level = (parentNode) ? parentNode.level + 1 : 0; + view.repairNodeLevelClass(setting, node, oldLevel); + + if (!children) return; + for (var i = 0, l = children.length; i < l; i++) { + if (children[i]) data.setSonNodeLevel(setting, node, children[i]); + } + } + }, + //method of event proxy + _event = {}, + //method of event handler + _handler = { + onHoverOverNode: function (event, node) { + var setting = data.getSetting(event.data.treeId), + root = data.getRoot(setting); + if (root.curHoverNode != node) { + _handler.onHoverOutNode(event); + } + root.curHoverNode = node; + view.addHoverDom(setting, node); + }, + onHoverOutNode: function (event, node) { + var setting = data.getSetting(event.data.treeId), + root = data.getRoot(setting); + if (root.curHoverNode && !data.isSelectedNode(setting, root.curHoverNode)) { + view.removeTreeDom(setting, root.curHoverNode); + root.curHoverNode = null; + } + }, + onMousedownNode: function (eventMouseDown, _node) { + var i, l, + setting = data.getSetting(eventMouseDown.data.treeId), + root = data.getRoot(setting), roots = data.getRoots(); + //right click can't drag & drop + if (eventMouseDown.button == 2 || !setting.edit.enable || (!setting.edit.drag.isCopy && !setting.edit.drag.isMove)) return true; + + //input of edit node name can't drag & drop + var target = eventMouseDown.target, + _nodes = data.getRoot(setting).curSelectedList, + nodes = []; + if (!data.isSelectedNode(setting, _node)) { + nodes = [_node]; + } else { + for (i = 0, l = _nodes.length; i < l; i++) { + if (_nodes[i].editNameFlag && tools.eqs(target.tagName, "input") && target.getAttribute("treeNode" + consts.id.INPUT) !== null) { + return true; + } + nodes.push(_nodes[i]); + if (nodes[0].parentTId !== _nodes[i].parentTId) { + nodes = [_node]; + break; + } + } + } + + view.editNodeBlur = true; + view.cancelCurEditNode(setting); + + var doc = $(setting.treeObj.get(0).ownerDocument), + body = $(setting.treeObj.get(0).ownerDocument.body), curNode, tmpArrow, tmpTarget, + isOtherTree = false, + targetSetting = setting, + sourceSetting = setting, + preNode, nextNode, + preTmpTargetNodeId = null, + preTmpMoveType = null, + tmpTargetNodeId = null, + moveType = consts.move.TYPE_INNER, + mouseDownX = eventMouseDown.clientX, + mouseDownY = eventMouseDown.clientY, + startTime = (new Date()).getTime(); + + if (tools.uCanDo(setting)) { + doc.bind("mousemove", _docMouseMove); + } + + function _docMouseMove(event) { + //avoid start drag after click node + if (root.dragFlag == 0 && Math.abs(mouseDownX - event.clientX) < setting.edit.drag.minMoveSize + && Math.abs(mouseDownY - event.clientY) < setting.edit.drag.minMoveSize) { + return true; + } + var i, l, tmpNode, tmpDom, tmpNodes; + body.css("cursor", "pointer"); + + if (root.dragFlag == 0) { + if (tools.apply(setting.callback.beforeDrag, [setting.treeId, nodes], true) == false) { + _docMouseUp(event); + return true; + } + + for (i = 0, l = nodes.length; i < l; i++) { + if (i == 0) { + root.dragNodeShowBefore = []; + } + tmpNode = nodes[i]; + if (data.nodeIsParent(setting, tmpNode) && tmpNode.open) { + view.expandCollapseNode(setting, tmpNode, !tmpNode.open); + root.dragNodeShowBefore[tmpNode.tId] = true; + } else { + root.dragNodeShowBefore[tmpNode.tId] = false; + } + } + + root.dragFlag = 1; + roots.showHoverDom = false; + tools.showIfameMask(setting, true); + + //sort + var isOrder = true, lastIndex = -1; + if (nodes.length > 1) { + var pNodes = nodes[0].parentTId ? data.nodeChildren(setting, nodes[0].getParentNode()) : data.getNodes(setting); + tmpNodes = []; + for (i = 0, l = pNodes.length; i < l; i++) { + if (root.dragNodeShowBefore[pNodes[i].tId] !== undefined) { + if (isOrder && lastIndex > -1 && (lastIndex + 1) !== i) { + isOrder = false; + } + tmpNodes.push(pNodes[i]); + lastIndex = i; + } + if (nodes.length === tmpNodes.length) { + nodes = tmpNodes; + break; + } + } + } + if (isOrder) { + preNode = nodes[0].getPreNode(); + nextNode = nodes[nodes.length - 1].getNextNode(); + } + + //set node in selected + curNode = $$("
      ", setting); + for (i = 0, l = nodes.length; i < l; i++) { + tmpNode = nodes[i]; + tmpNode.editNameFlag = false; + view.selectNode(setting, tmpNode, i > 0); + view.removeTreeDom(setting, tmpNode); + + if (i > setting.edit.drag.maxShowNodeNum - 1) { + continue; + } + + tmpDom = $$("
    • ", setting); + tmpDom.append($$(tmpNode, consts.id.A, setting).clone()); + tmpDom.css("padding", "0"); + tmpDom.children("#" + tmpNode.tId + consts.id.A).removeClass(consts.node.CURSELECTED); + curNode.append(tmpDom); + if (i == setting.edit.drag.maxShowNodeNum - 1) { + tmpDom = $$("
    • ...
    • ", setting); + curNode.append(tmpDom); + } + } + curNode.attr("id", nodes[0].tId + consts.id.UL + "_tmp"); + curNode.addClass(setting.treeObj.attr("class")); + curNode.appendTo(body); + + tmpArrow = $$("", setting); + tmpArrow.attr("id", "zTreeMove_arrow_tmp"); + tmpArrow.appendTo(body); + + setting.treeObj.trigger(consts.event.DRAG, [event, setting.treeId, nodes]); + } + + if (root.dragFlag == 1) { + if (tmpTarget && tmpArrow.attr("id") == event.target.id && tmpTargetNodeId && (event.clientX + doc.scrollLeft() + 2) > ($("#" + tmpTargetNodeId + consts.id.A, tmpTarget).offset().left)) { + var xT = $("#" + tmpTargetNodeId + consts.id.A, tmpTarget); + event.target = (xT.length > 0) ? xT.get(0) : event.target; + } else if (tmpTarget) { + tmpTarget.removeClass(consts.node.TMPTARGET_TREE); + if (tmpTargetNodeId) $("#" + tmpTargetNodeId + consts.id.A, tmpTarget).removeClass(consts.node.TMPTARGET_NODE + "_" + consts.move.TYPE_PREV) + .removeClass(consts.node.TMPTARGET_NODE + "_" + _consts.move.TYPE_NEXT).removeClass(consts.node.TMPTARGET_NODE + "_" + _consts.move.TYPE_INNER); + } + tmpTarget = null; + tmpTargetNodeId = null; + + //judge drag & drop in multi ztree + isOtherTree = false; + targetSetting = setting; + var settings = data.getSettings(); + for (var s in settings) { + if (settings[s].treeId && settings[s].edit.enable && settings[s].treeId != setting.treeId + && (event.target.id == settings[s].treeId || $(event.target).parents("#" + settings[s].treeId).length > 0)) { + isOtherTree = true; + targetSetting = settings[s]; + } + } + + var docScrollTop = doc.scrollTop(), + docScrollLeft = doc.scrollLeft(), + treeOffset = targetSetting.treeObj.offset(), + scrollHeight = targetSetting.treeObj.get(0).scrollHeight, + scrollWidth = targetSetting.treeObj.get(0).scrollWidth, + dTop = (event.clientY + docScrollTop - treeOffset.top), + dBottom = (targetSetting.treeObj.height() + treeOffset.top - event.clientY - docScrollTop), + dLeft = (event.clientX + docScrollLeft - treeOffset.left), + dRight = (targetSetting.treeObj.width() + treeOffset.left - event.clientX - docScrollLeft), + isTop = (dTop < setting.edit.drag.borderMax && dTop > setting.edit.drag.borderMin), + isBottom = (dBottom < setting.edit.drag.borderMax && dBottom > setting.edit.drag.borderMin), + isLeft = (dLeft < setting.edit.drag.borderMax && dLeft > setting.edit.drag.borderMin), + isRight = (dRight < setting.edit.drag.borderMax && dRight > setting.edit.drag.borderMin), + isTreeInner = dTop > setting.edit.drag.borderMin && dBottom > setting.edit.drag.borderMin && dLeft > setting.edit.drag.borderMin && dRight > setting.edit.drag.borderMin, + isTreeTop = (isTop && targetSetting.treeObj.scrollTop() <= 0), + isTreeBottom = (isBottom && (targetSetting.treeObj.scrollTop() + targetSetting.treeObj.height() + 10) >= scrollHeight), + isTreeLeft = (isLeft && targetSetting.treeObj.scrollLeft() <= 0), + isTreeRight = (isRight && (targetSetting.treeObj.scrollLeft() + targetSetting.treeObj.width() + 10) >= scrollWidth); + + if (event.target && tools.isChildOrSelf(event.target, targetSetting.treeId)) { + //get node
    • dom + var targetObj = event.target; + while (targetObj && targetObj.tagName && !tools.eqs(targetObj.tagName, "li") && targetObj.id != targetSetting.treeId) { + targetObj = targetObj.parentNode; + } + + var canMove = true; + //don't move to self or children of self + for (i = 0, l = nodes.length; i < l; i++) { + tmpNode = nodes[i]; + if (targetObj.id === tmpNode.tId) { + canMove = false; + break; + } else if ($$(tmpNode, setting).find("#" + targetObj.id).length > 0) { + canMove = false; + break; + } + } + if (canMove && event.target && tools.isChildOrSelf(event.target, targetObj.id + consts.id.A)) { + tmpTarget = $(targetObj); + tmpTargetNodeId = targetObj.id; + } + } + + //the mouse must be in zTree + tmpNode = nodes[0]; + if (isTreeInner && tools.isChildOrSelf(event.target, targetSetting.treeId)) { + //judge mouse move in root of ztree + if (!tmpTarget && (event.target.id == targetSetting.treeId || isTreeTop || isTreeBottom || isTreeLeft || isTreeRight) && (isOtherTree || (!isOtherTree && tmpNode.parentTId))) { + tmpTarget = targetSetting.treeObj; + } + //auto scroll top + if (isTop) { + targetSetting.treeObj.scrollTop(targetSetting.treeObj.scrollTop() - 10); + } else if (isBottom) { + targetSetting.treeObj.scrollTop(targetSetting.treeObj.scrollTop() + 10); + } + if (isLeft) { + targetSetting.treeObj.scrollLeft(targetSetting.treeObj.scrollLeft() - 10); + } else if (isRight) { + targetSetting.treeObj.scrollLeft(targetSetting.treeObj.scrollLeft() + 10); + } + //auto scroll left + if (tmpTarget && tmpTarget != targetSetting.treeObj && tmpTarget.offset().left < targetSetting.treeObj.offset().left) { + targetSetting.treeObj.scrollLeft(targetSetting.treeObj.scrollLeft() + tmpTarget.offset().left - targetSetting.treeObj.offset().left); + } + } + + curNode.css({ + "top": (event.clientY + docScrollTop + 3) + "px", + "left": (event.clientX + docScrollLeft + 3) + "px" + }); + + var dX = 0; + var dY = 0; + if (tmpTarget && tmpTarget.attr("id") != targetSetting.treeId) { + var tmpTargetNode = tmpTargetNodeId == null ? null : data.getNodeCache(targetSetting, tmpTargetNodeId), + isCopy = ((event.ctrlKey || event.metaKey) && setting.edit.drag.isMove && setting.edit.drag.isCopy) || (!setting.edit.drag.isMove && setting.edit.drag.isCopy), + isPrev = !!(preNode && tmpTargetNodeId === preNode.tId), + isNext = !!(nextNode && tmpTargetNodeId === nextNode.tId), + isInner = (tmpNode.parentTId && tmpNode.parentTId == tmpTargetNodeId), + canPrev = (isCopy || !isNext) && tools.apply(targetSetting.edit.drag.prev, [targetSetting.treeId, nodes, tmpTargetNode], !!targetSetting.edit.drag.prev), + canNext = (isCopy || !isPrev) && tools.apply(targetSetting.edit.drag.next, [targetSetting.treeId, nodes, tmpTargetNode], !!targetSetting.edit.drag.next), + canInner = (isCopy || !isInner) && !(targetSetting.data.keep.leaf && !data.nodeIsParent(setting, tmpTargetNode)) && tools.apply(targetSetting.edit.drag.inner, [targetSetting.treeId, nodes, tmpTargetNode], !!targetSetting.edit.drag.inner); + + function clearMove() { + tmpTarget = null; + tmpTargetNodeId = ""; + moveType = consts.move.TYPE_INNER; + tmpArrow.css({ + "display": "none" + }); + if (window.zTreeMoveTimer) { + clearTimeout(window.zTreeMoveTimer); + window.zTreeMoveTargetNodeTId = null + } + } + + if (!canPrev && !canNext && !canInner) { + clearMove(); + } else { + var tmpTargetA = $("#" + tmpTargetNodeId + consts.id.A, tmpTarget), + tmpNextA = tmpTargetNode.isLastNode ? null : $("#" + tmpTargetNode.getNextNode().tId + consts.id.A, tmpTarget.next()), + tmpTop = tmpTargetA.offset().top, + tmpLeft = tmpTargetA.offset().left, + prevPercent = canPrev ? (canInner ? 0.25 : (canNext ? 0.5 : 1)) : -1, + nextPercent = canNext ? (canInner ? 0.75 : (canPrev ? 0.5 : 0)) : -1, + dY_percent = (event.clientY + docScrollTop - tmpTop) / tmpTargetA.height(); + + if ((prevPercent == 1 || dY_percent <= prevPercent && dY_percent >= -.2) && canPrev) { + dX = 1 - tmpArrow.width(); + dY = tmpTop - tmpArrow.height() / 2; + moveType = consts.move.TYPE_PREV; + } else if ((nextPercent == 0 || dY_percent >= nextPercent && dY_percent <= 1.2) && canNext) { + dX = 1 - tmpArrow.width(); + dY = (tmpNextA == null || (data.nodeIsParent(setting, tmpTargetNode) && tmpTargetNode.open)) ? (tmpTop + tmpTargetA.height() - tmpArrow.height() / 2) : (tmpNextA.offset().top - tmpArrow.height() / 2); + moveType = consts.move.TYPE_NEXT; + } else if (canInner) { + dX = 5 - tmpArrow.width(); + dY = tmpTop; + moveType = consts.move.TYPE_INNER; + } else { + clearMove(); + } + + if (tmpTarget) { + tmpArrow.css({ + "display": "block", + "top": dY + "px", + "left": (tmpLeft + dX) + "px" + }); + tmpTargetA.addClass(consts.node.TMPTARGET_NODE + "_" + moveType); + + if (preTmpTargetNodeId != tmpTargetNodeId || preTmpMoveType != moveType) { + startTime = (new Date()).getTime(); + } + if (tmpTargetNode && data.nodeIsParent(setting, tmpTargetNode) && moveType == consts.move.TYPE_INNER) { + var startTimer = true; + if (window.zTreeMoveTimer && window.zTreeMoveTargetNodeTId !== tmpTargetNode.tId) { + clearTimeout(window.zTreeMoveTimer); + window.zTreeMoveTargetNodeTId = null; + } else if (window.zTreeMoveTimer && window.zTreeMoveTargetNodeTId === tmpTargetNode.tId) { + startTimer = false; + } + if (startTimer) { + window.zTreeMoveTimer = setTimeout(function () { + if (moveType != consts.move.TYPE_INNER) return; + if (tmpTargetNode && data.nodeIsParent(setting, tmpTargetNode) && !tmpTargetNode.open && (new Date()).getTime() - startTime > targetSetting.edit.drag.autoOpenTime + && tools.apply(targetSetting.callback.beforeDragOpen, [targetSetting.treeId, tmpTargetNode], true)) { + view.switchNode(targetSetting, tmpTargetNode); + if (targetSetting.edit.drag.autoExpandTrigger) { + targetSetting.treeObj.trigger(consts.event.EXPAND, [targetSetting.treeId, tmpTargetNode]); + } + } + }, targetSetting.edit.drag.autoOpenTime + 50); + window.zTreeMoveTargetNodeTId = tmpTargetNode.tId; + } + } + } + } + } else { + moveType = consts.move.TYPE_INNER; + if (tmpTarget && tools.apply(targetSetting.edit.drag.inner, [targetSetting.treeId, nodes, null], !!targetSetting.edit.drag.inner)) { + tmpTarget.addClass(consts.node.TMPTARGET_TREE); + } else { + tmpTarget = null; + } + tmpArrow.css({ + "display": "none" + }); + if (window.zTreeMoveTimer) { + clearTimeout(window.zTreeMoveTimer); + window.zTreeMoveTargetNodeTId = null; + } + } + preTmpTargetNodeId = tmpTargetNodeId; + preTmpMoveType = moveType; + + setting.treeObj.trigger(consts.event.DRAGMOVE, [event, setting.treeId, nodes]); + } + return false; + } + + doc.bind("mouseup", _docMouseUp); + + function _docMouseUp(event) { + if (window.zTreeMoveTimer) { + clearTimeout(window.zTreeMoveTimer); + window.zTreeMoveTargetNodeTId = null; + } + preTmpTargetNodeId = null; + preTmpMoveType = null; + doc.unbind("mousemove", _docMouseMove); + doc.unbind("mouseup", _docMouseUp); + doc.unbind("selectstart", _docSelect); + body.css("cursor", ""); + if (tmpTarget) { + tmpTarget.removeClass(consts.node.TMPTARGET_TREE); + if (tmpTargetNodeId) $("#" + tmpTargetNodeId + consts.id.A, tmpTarget).removeClass(consts.node.TMPTARGET_NODE + "_" + consts.move.TYPE_PREV) + .removeClass(consts.node.TMPTARGET_NODE + "_" + _consts.move.TYPE_NEXT).removeClass(consts.node.TMPTARGET_NODE + "_" + _consts.move.TYPE_INNER); + } + tools.showIfameMask(setting, false); + + roots.showHoverDom = true; + if (root.dragFlag == 0) return; + root.dragFlag = 0; + + var i, l, tmpNode; + for (i = 0, l = nodes.length; i < l; i++) { + tmpNode = nodes[i]; + if (data.nodeIsParent(setting, tmpNode) && root.dragNodeShowBefore[tmpNode.tId] && !tmpNode.open) { + view.expandCollapseNode(setting, tmpNode, !tmpNode.open); + delete root.dragNodeShowBefore[tmpNode.tId]; + } + } + + if (curNode) curNode.remove(); + if (tmpArrow) tmpArrow.remove(); + + var isCopy = ((event.ctrlKey || event.metaKey) && setting.edit.drag.isMove && setting.edit.drag.isCopy) || (!setting.edit.drag.isMove && setting.edit.drag.isCopy); + if (!isCopy && tmpTarget && tmpTargetNodeId && nodes[0].parentTId && tmpTargetNodeId == nodes[0].parentTId && moveType == consts.move.TYPE_INNER) { + tmpTarget = null; + } + if (tmpTarget) { + var dragTargetNode = tmpTargetNodeId == null ? null : data.getNodeCache(targetSetting, tmpTargetNodeId); + if (tools.apply(setting.callback.beforeDrop, [targetSetting.treeId, nodes, dragTargetNode, moveType, isCopy], true) == false) { + view.selectNodes(sourceSetting, nodes); + return; + } + var newNodes = isCopy ? tools.clone(nodes) : nodes; + + function dropCallback() { + if (isOtherTree) { + if (!isCopy) { + for (var i = 0, l = nodes.length; i < l; i++) { + view.removeNode(setting, nodes[i]); + } + } + if (moveType == consts.move.TYPE_INNER) { + view.addNodes(targetSetting, dragTargetNode, -1, newNodes); + } else { + view.addNodes(targetSetting, dragTargetNode.getParentNode(), moveType == consts.move.TYPE_PREV ? dragTargetNode.getIndex() : dragTargetNode.getIndex() + 1, newNodes); + } + } else { + if (isCopy && moveType == consts.move.TYPE_INNER) { + view.addNodes(targetSetting, dragTargetNode, -1, newNodes); + } else if (isCopy) { + view.addNodes(targetSetting, dragTargetNode.getParentNode(), moveType == consts.move.TYPE_PREV ? dragTargetNode.getIndex() : dragTargetNode.getIndex() + 1, newNodes); + } else { + if (moveType != consts.move.TYPE_NEXT) { + for (i = 0, l = newNodes.length; i < l; i++) { + view.moveNode(targetSetting, dragTargetNode, newNodes[i], moveType, false); + } + } else { + for (i = -1, l = newNodes.length - 1; i < l; l--) { + view.moveNode(targetSetting, dragTargetNode, newNodes[l], moveType, false); + } + } + } + } + view.selectNodes(targetSetting, newNodes); + + var a = $$(newNodes[0], setting).get(0); + view.scrollIntoView(setting, a); + + setting.treeObj.trigger(consts.event.DROP, [event, targetSetting.treeId, newNodes, dragTargetNode, moveType, isCopy]); + } + + if (moveType == consts.move.TYPE_INNER && tools.canAsync(targetSetting, dragTargetNode)) { + view.asyncNode(targetSetting, dragTargetNode, false, dropCallback); + } else { + dropCallback(); + } + + } else { + view.selectNodes(sourceSetting, nodes); + setting.treeObj.trigger(consts.event.DROP, [event, setting.treeId, nodes, null, null, null]); + } + } + + doc.bind("selectstart", _docSelect); + + function _docSelect() { + return false; + } + + // 2018-03-30 FireFox has fixed this issue. + //Avoid FireFox's Bug + //If zTree Div CSS set 'overflow', so drag node outside of zTree, and event.target is error. + // if(eventMouseDown.preventDefault) { + // eventMouseDown.preventDefault(); + // } + return true; + } + }, + //method of tools for zTree + _tools = { + getAbs: function (obj) { + var oRect = obj.getBoundingClientRect(), + scrollTop = document.body.scrollTop + document.documentElement.scrollTop, + scrollLeft = document.body.scrollLeft + document.documentElement.scrollLeft; + return [oRect.left + scrollLeft, oRect.top + scrollTop]; + }, + inputFocus: function (inputObj) { + if (inputObj.get(0)) { + inputObj.focus(); + tools.setCursorPosition(inputObj.get(0), inputObj.val().length); + } + }, + inputSelect: function (inputObj) { + if (inputObj.get(0)) { + inputObj.focus(); + inputObj.select(); + } + }, + setCursorPosition: function (obj, pos) { + if (obj.setSelectionRange) { + obj.focus(); + obj.setSelectionRange(pos, pos); + } else if (obj.createTextRange) { + var range = obj.createTextRange(); + range.collapse(true); + range.moveEnd('character', pos); + range.moveStart('character', pos); + range.select(); + } + }, + showIfameMask: function (setting, showSign) { + var root = data.getRoot(setting); + //clear full mask + while (root.dragMaskList.length > 0) { + root.dragMaskList[0].remove(); + root.dragMaskList.shift(); + } + if (showSign) { + //show mask + var iframeList = $$("iframe", setting); + for (var i = 0, l = iframeList.length; i < l; i++) { + var obj = iframeList.get(i), + r = tools.getAbs(obj), + dragMask = $$("
      ", setting); + dragMask.appendTo($$("body", setting)); + root.dragMaskList.push(dragMask); + } + } + } + }, + //method of operate ztree dom + _view = { + addEditBtn: function (setting, node) { + if (node.editNameFlag || $$(node, consts.id.EDIT, setting).length > 0) { + return; + } + if (!tools.apply(setting.edit.showRenameBtn, [setting.treeId, node], setting.edit.showRenameBtn)) { + return; + } + var aObj = $$(node, consts.id.A, setting), + editStr = ""; + aObj.append(editStr); + + $$(node, consts.id.EDIT, setting).bind('click', + function () { + if (!tools.uCanDo(setting) || tools.apply(setting.callback.beforeEditName, [setting.treeId, node], true) == false) return false; + view.editNode(setting, node); + return false; + } + ).show(); + }, + addRemoveBtn: function (setting, node) { + if (node.editNameFlag || $$(node, consts.id.REMOVE, setting).length > 0) { + return; + } + if (!tools.apply(setting.edit.showRemoveBtn, [setting.treeId, node], setting.edit.showRemoveBtn)) { + return; + } + var aObj = $$(node, consts.id.A, setting), + removeStr = ""; + aObj.append(removeStr); + + $$(node, consts.id.REMOVE, setting).bind('click', + function () { + if (!tools.uCanDo(setting) || tools.apply(setting.callback.beforeRemove, [setting.treeId, node], true) == false) return false; + view.removeNode(setting, node); + setting.treeObj.trigger(consts.event.REMOVE, [setting.treeId, node]); + return false; + } + ).bind('mousedown', + function (eventMouseDown) { + return true; + } + ).show(); + }, + addHoverDom: function (setting, node) { + if (data.getRoots().showHoverDom) { + node.isHover = true; + if (setting.edit.enable) { + view.addEditBtn(setting, node); + view.addRemoveBtn(setting, node); + } + tools.apply(setting.view.addHoverDom, [setting.treeId, node]); + } + }, + cancelCurEditNode: function (setting, forceName, isCancel) { + var root = data.getRoot(setting), + node = root.curEditNode; + + if (node) { + var inputObj = root.curEditInput, + newName = forceName ? forceName : (isCancel ? data.nodeName(setting, node) : inputObj.val()); + if (tools.apply(setting.callback.beforeRename, [setting.treeId, node, newName, isCancel], true) === false) { + return false; + } + data.nodeName(setting, node, newName); + var aObj = $$(node, consts.id.A, setting); + aObj.removeClass(consts.node.CURSELECTED_EDIT); + inputObj.unbind(); + view.setNodeName(setting, node); + node.editNameFlag = false; + root.curEditNode = null; + root.curEditInput = null; + view.selectNode(setting, node, false); + setting.treeObj.trigger(consts.event.RENAME, [setting.treeId, node, isCancel]); + } + root.noSelection = true; + return true; + }, + editNode: function (setting, node) { + var root = data.getRoot(setting); + view.editNodeBlur = false; + if (data.isSelectedNode(setting, node) && root.curEditNode == node && node.editNameFlag) { + setTimeout(function () { + tools.inputFocus(root.curEditInput); + }, 0); + return; + } + node.editNameFlag = true; + view.removeTreeDom(setting, node); + view.cancelCurEditNode(setting); + view.selectNode(setting, node, false); + $$(node, consts.id.SPAN, setting).html(""); + var inputObj = $$(node, consts.id.INPUT, setting); + inputObj.attr("value", data.nodeName(setting, node)); + if (setting.edit.editNameSelectAll) { + tools.inputSelect(inputObj); + } else { + tools.inputFocus(inputObj); + } + + inputObj.bind('blur', function (event) { + if (!view.editNodeBlur) { + view.cancelCurEditNode(setting); + } + }).bind('keydown', function (event) { + if (event.keyCode == "13") { + view.editNodeBlur = true; + view.cancelCurEditNode(setting); + } else if (event.keyCode == "27") { + view.cancelCurEditNode(setting, null, true); + } + }).bind('click', function (event) { + return false; + }).bind('dblclick', function (event) { + return false; + }); + + $$(node, consts.id.A, setting).addClass(consts.node.CURSELECTED_EDIT); + root.curEditInput = inputObj; + root.noSelection = false; + root.curEditNode = node; + }, + moveNode: function (setting, targetNode, node, moveType, animateFlag, isSilent) { + var root = data.getRoot(setting); + if (targetNode == node) return; + if (setting.data.keep.leaf && targetNode && !data.nodeIsParent(setting, targetNode) && moveType == consts.move.TYPE_INNER) return; + var oldParentNode = (node.parentTId ? node.getParentNode() : root), + targetNodeIsRoot = (targetNode === null || targetNode == root); + if (targetNodeIsRoot && targetNode === null) targetNode = root; + if (targetNodeIsRoot) moveType = consts.move.TYPE_INNER; + var targetParentNode = (targetNode.parentTId ? targetNode.getParentNode() : root); + + if (moveType != consts.move.TYPE_PREV && moveType != consts.move.TYPE_NEXT) { + moveType = consts.move.TYPE_INNER; + } + + if (moveType == consts.move.TYPE_INNER) { + if (targetNodeIsRoot) { + //parentTId of root node is null + node.parentTId = null; + } else { + if (!data.nodeIsParent(setting, targetNode)) { + data.nodeIsParent(setting, targetNode, true); + targetNode.open = !!targetNode.open; + view.setNodeLineIcos(setting, targetNode); + } + node.parentTId = targetNode.tId; + } + } + + //move node Dom + var targetObj, target_ulObj; + if (targetNodeIsRoot) { + targetObj = setting.treeObj; + target_ulObj = targetObj; + } else { + if (!isSilent && moveType == consts.move.TYPE_INNER) { + view.expandCollapseNode(setting, targetNode, true, false); + } else if (!isSilent) { + view.expandCollapseNode(setting, targetNode.getParentNode(), true, false); + } + targetObj = $$(targetNode, setting); + target_ulObj = $$(targetNode, consts.id.UL, setting); + if (!!targetObj.get(0) && !target_ulObj.get(0)) { + var ulstr = []; + view.makeUlHtml(setting, targetNode, ulstr, ''); + targetObj.append(ulstr.join('')); + } + target_ulObj = $$(targetNode, consts.id.UL, setting); + } + var nodeDom = $$(node, setting); + if (!nodeDom.get(0)) { + nodeDom = view.appendNodes(setting, node.level, [node], null, -1, false, true).join(''); + } else if (!targetObj.get(0)) { + nodeDom.remove(); + } + if (target_ulObj.get(0) && moveType == consts.move.TYPE_INNER) { + target_ulObj.append(nodeDom); + } else if (targetObj.get(0) && moveType == consts.move.TYPE_PREV) { + targetObj.before(nodeDom); + } else if (targetObj.get(0) && moveType == consts.move.TYPE_NEXT) { + targetObj.after(nodeDom); + } + + //repair the data after move + var i, l, + tmpSrcIndex = -1, + tmpTargetIndex = 0, + oldNeighbor = null, + newNeighbor = null, + oldLevel = node.level; + var oldChildren = data.nodeChildren(setting, oldParentNode); + var targetParentChildren = data.nodeChildren(setting, targetParentNode); + var targetChildren = data.nodeChildren(setting, targetNode); + if (node.isFirstNode) { + tmpSrcIndex = 0; + if (oldChildren.length > 1) { + oldNeighbor = oldChildren[1]; + oldNeighbor.isFirstNode = true; + } + } else if (node.isLastNode) { + tmpSrcIndex = oldChildren.length - 1; + oldNeighbor = oldChildren[tmpSrcIndex - 1]; + oldNeighbor.isLastNode = true; + } else { + for (i = 0, l = oldChildren.length; i < l; i++) { + if (oldChildren[i].tId == node.tId) { + tmpSrcIndex = i; + break; + } + } + } + if (tmpSrcIndex >= 0) { + oldChildren.splice(tmpSrcIndex, 1); + } + if (moveType != consts.move.TYPE_INNER) { + for (i = 0, l = targetParentChildren.length; i < l; i++) { + if (targetParentChildren[i].tId == targetNode.tId) tmpTargetIndex = i; + } + } + if (moveType == consts.move.TYPE_INNER) { + if (!targetChildren) { + targetChildren = data.nodeChildren(setting, targetNode, []); + } + if (targetChildren.length > 0) { + newNeighbor = targetChildren[targetChildren.length - 1]; + newNeighbor.isLastNode = false; + } + targetChildren.splice(targetChildren.length, 0, node); + node.isLastNode = true; + node.isFirstNode = (targetChildren.length == 1); + } else if (targetNode.isFirstNode && moveType == consts.move.TYPE_PREV) { + targetParentChildren.splice(tmpTargetIndex, 0, node); + newNeighbor = targetNode; + newNeighbor.isFirstNode = false; + node.parentTId = targetNode.parentTId; + node.isFirstNode = true; + node.isLastNode = false; + + } else if (targetNode.isLastNode && moveType == consts.move.TYPE_NEXT) { + targetParentChildren.splice(tmpTargetIndex + 1, 0, node); + newNeighbor = targetNode; + newNeighbor.isLastNode = false; + node.parentTId = targetNode.parentTId; + node.isFirstNode = false; + node.isLastNode = true; + + } else { + if (moveType == consts.move.TYPE_PREV) { + targetParentChildren.splice(tmpTargetIndex, 0, node); + } else { + targetParentChildren.splice(tmpTargetIndex + 1, 0, node); + } + node.parentTId = targetNode.parentTId; + node.isFirstNode = false; + node.isLastNode = false; + } + data.fixPIdKeyValue(setting, node); + data.setSonNodeLevel(setting, node.getParentNode(), node); + + //repair node what been moved + view.setNodeLineIcos(setting, node); + view.repairNodeLevelClass(setting, node, oldLevel); + + //repair node's old parentNode dom + if (!setting.data.keep.parent && oldChildren.length < 1) { + //old parentNode has no child nodes + data.nodeIsParent(setting, oldParentNode, false); + oldParentNode.open = false; + var tmp_ulObj = $$(oldParentNode, consts.id.UL, setting), + tmp_switchObj = $$(oldParentNode, consts.id.SWITCH, setting), + tmp_icoObj = $$(oldParentNode, consts.id.ICON, setting); + view.replaceSwitchClass(oldParentNode, tmp_switchObj, consts.folder.DOCU); + view.replaceIcoClass(oldParentNode, tmp_icoObj, consts.folder.DOCU); + tmp_ulObj.css("display", "none"); + + } else if (oldNeighbor) { + //old neighbor node + view.setNodeLineIcos(setting, oldNeighbor); + } + + //new neighbor node + if (newNeighbor) { + view.setNodeLineIcos(setting, newNeighbor); + } + + //repair checkbox / radio + if (!!setting.check && setting.check.enable && view.repairChkClass) { + view.repairChkClass(setting, oldParentNode); + view.repairParentChkClassWithSelf(setting, oldParentNode); + if (oldParentNode != node.parent) + view.repairParentChkClassWithSelf(setting, node); + } + + //expand parents after move + if (!isSilent) { + view.expandCollapseParentNode(setting, node.getParentNode(), true, animateFlag); + } + }, + removeEditBtn: function (setting, node) { + $$(node, consts.id.EDIT, setting).unbind().remove(); + }, + removeRemoveBtn: function (setting, node) { + $$(node, consts.id.REMOVE, setting).unbind().remove(); + }, + removeTreeDom: function (setting, node) { + node.isHover = false; + view.removeEditBtn(setting, node); + view.removeRemoveBtn(setting, node); + tools.apply(setting.view.removeHoverDom, [setting.treeId, node]); + }, + repairNodeLevelClass: function (setting, node, oldLevel) { + if (oldLevel === node.level) return; + var liObj = $$(node, setting), + aObj = $$(node, consts.id.A, setting), + ulObj = $$(node, consts.id.UL, setting), + oldClass = consts.className.LEVEL + oldLevel, + newClass = consts.className.LEVEL + node.level; + liObj.removeClass(oldClass); + liObj.addClass(newClass); + aObj.removeClass(oldClass); + aObj.addClass(newClass); + ulObj.removeClass(oldClass); + ulObj.addClass(newClass); + }, + selectNodes: function (setting, nodes) { + for (var i = 0, l = nodes.length; i < l; i++) { + view.selectNode(setting, nodes[i], i > 0); + } + } + }, + + _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.exSetting(_setting); + data.addInitBind(_bindEvent); + data.addInitUnBind(_unbindEvent); + data.addInitCache(_initCache); + data.addInitNode(_initNode); + data.addInitProxy(_eventProxy); + data.addInitRoot(_initRoot); + data.addZTreeTools(_zTreeTools); + + var _cancelPreSelectedNode = view.cancelPreSelectedNode; + view.cancelPreSelectedNode = function (setting, node) { + var list = data.getRoot(setting).curSelectedList; + for (var i = 0, j = list.length; i < j; i++) { + if (!node || node === list[i]) { + view.removeTreeDom(setting, list[i]); + if (node) break; + } + } + if (_cancelPreSelectedNode) _cancelPreSelectedNode.apply(view, arguments); + } + + var _createNodes = view.createNodes; + view.createNodes = function (setting, level, nodes, parentNode, index) { + if (_createNodes) { + _createNodes.apply(view, arguments); + } + if (!nodes) return; + if (view.repairParentChkClassWithSelf) { + view.repairParentChkClassWithSelf(setting, parentNode); + } + } + + var _makeNodeUrl = view.makeNodeUrl; + view.makeNodeUrl = function (setting, node) { + return setting.edit.enable ? null : (_makeNodeUrl.apply(view, arguments)); + } + + var _removeNode = view.removeNode; + view.removeNode = function (setting, node) { + var root = data.getRoot(setting); + if (root.curEditNode === node) root.curEditNode = null; + if (_removeNode) { + _removeNode.apply(view, arguments); + } + } + + var _selectNode = view.selectNode; + view.selectNode = function (setting, node, addFlag) { + var root = data.getRoot(setting); + if (data.isSelectedNode(setting, node) && root.curEditNode == node && node.editNameFlag) { + return false; + } + if (_selectNode) _selectNode.apply(view, arguments); + view.addHoverDom(setting, node); + return true; + } + + var _uCanDo = tools.uCanDo; + tools.uCanDo = function (setting, e) { + var root = data.getRoot(setting); + if (e && (tools.eqs(e.type, "mouseover") || tools.eqs(e.type, "mouseout") || tools.eqs(e.type, "mousedown") || tools.eqs(e.type, "mouseup"))) { + return true; + } + if (root.curEditNode) { + view.editNodeBlur = false; + root.curEditInput.focus(); + } + return (!root.curEditNode) && (_uCanDo ? _uCanDo.apply(view, arguments) : true); + } +})(jQuery); \ No newline at end of file diff --git a/public/self/ztree/js/jquery.ztree.core.js b/public/self/ztree/js/jquery.ztree.core.js new file mode 100644 index 000000000..9226f19d6 --- /dev/null +++ b/public/self/ztree/js/jquery.ztree.core.js @@ -0,0 +1,2019 @@ +/* + * JQuery zTree core + * 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 settings = {}, roots = {}, caches = {}, + //default consts of core + _consts = { + className: { + BUTTON: "button", + LEVEL: "level", + ICO_LOADING: "ico_loading", + SWITCH: "switch", + NAME: 'node_name' + }, + event: { + NODECREATED: "ztree_nodeCreated", + CLICK: "ztree_click", + EXPAND: "ztree_expand", + COLLAPSE: "ztree_collapse", + ASYNC_SUCCESS: "ztree_async_success", + ASYNC_ERROR: "ztree_async_error", + REMOVE: "ztree_remove", + SELECTED: "ztree_selected", + UNSELECTED: "ztree_unselected" + }, + id: { + A: "_a", + ICON: "_ico", + SPAN: "_span", + SWITCH: "_switch", + UL: "_ul" + }, + line: { + ROOT: "root", + ROOTS: "roots", + CENTER: "center", + BOTTOM: "bottom", + NOLINE: "noline", + LINE: "line" + }, + folder: { + OPEN: "open", + CLOSE: "close", + DOCU: "docu" + }, + node: { + CURSELECTED: "curSelectedNode" + } + }, + //default setting of core + _setting = { + treeId: "", + treeObj: null, + view: { + addDiyDom: null, + autoCancelSelected: true, + dblClickExpand: true, + expandSpeed: "fast", + fontCss: {}, + nodeClasses: {}, + nameIsHTML: false, + selectedMulti: true, + showIcon: true, + showLine: true, + showTitle: true, + txtSelectedEnable: false + }, + data: { + key: { + isParent: "isParent", + children: "children", + name: "name", + title: "", + url: "url", + icon: "icon" + }, + render: { + name: null, + title: null, + }, + simpleData: { + enable: false, + idKey: "id", + pIdKey: "pId", + rootPId: null + }, + keep: { + parent: false, + leaf: false + } + }, + async: { + enable: false, + contentType: "application/x-www-form-urlencoded", + type: "post", + dataType: "text", + headers: {}, + xhrFields: {}, + url: "", + autoParam: [], + otherParam: [], + dataFilter: null + }, + callback: { + beforeAsync: null, + beforeClick: null, + beforeDblClick: null, + beforeRightClick: null, + beforeMouseDown: null, + beforeMouseUp: null, + beforeExpand: null, + beforeCollapse: null, + beforeRemove: null, + + onAsyncError: null, + onAsyncSuccess: null, + onNodeCreated: null, + onClick: null, + onDblClick: null, + onRightClick: null, + onMouseDown: null, + onMouseUp: null, + onExpand: null, + onCollapse: null, + onRemove: null + } + }, + //default root of core + //zTree use root to save full data + _initRoot = function (setting) { + var r = data.getRoot(setting); + if (!r) { + r = {}; + data.setRoot(setting, r); + } + data.nodeChildren(setting, r, []); + r.expandTriggerFlag = false; + r.curSelectedList = []; + r.noSelection = true; + r.createdNodes = []; + r.zId = 0; + r._ver = (new Date()).getTime(); + }, + //default cache of core + _initCache = function (setting) { + var c = data.getCache(setting); + if (!c) { + c = {}; + data.setCache(setting, c); + } + c.nodes = []; + c.doms = []; + }, + //default bindEvent of core + _bindEvent = function (setting) { + var o = setting.treeObj, + c = consts.event; + o.bind(c.NODECREATED, function (event, treeId, node) { + tools.apply(setting.callback.onNodeCreated, [event, treeId, node]); + }); + + o.bind(c.CLICK, function (event, srcEvent, treeId, node, clickFlag) { + tools.apply(setting.callback.onClick, [srcEvent, treeId, node, clickFlag]); + }); + + o.bind(c.EXPAND, function (event, treeId, node) { + tools.apply(setting.callback.onExpand, [event, treeId, node]); + }); + + o.bind(c.COLLAPSE, function (event, treeId, node) { + tools.apply(setting.callback.onCollapse, [event, treeId, node]); + }); + + o.bind(c.ASYNC_SUCCESS, function (event, treeId, node, msg) { + tools.apply(setting.callback.onAsyncSuccess, [event, treeId, node, msg]); + }); + + o.bind(c.ASYNC_ERROR, function (event, treeId, node, XMLHttpRequest, textStatus, errorThrown) { + tools.apply(setting.callback.onAsyncError, [event, treeId, node, XMLHttpRequest, textStatus, errorThrown]); + }); + + o.bind(c.REMOVE, function (event, treeId, treeNode) { + tools.apply(setting.callback.onRemove, [event, treeId, treeNode]); + }); + + o.bind(c.SELECTED, function (event, treeId, node) { + tools.apply(setting.callback.onSelected, [treeId, node]); + }); + o.bind(c.UNSELECTED, function (event, treeId, node) { + tools.apply(setting.callback.onUnSelected, [treeId, node]); + }); + }, + _unbindEvent = function (setting) { + var o = setting.treeObj, + c = consts.event; + o.unbind(c.NODECREATED) + .unbind(c.CLICK) + .unbind(c.EXPAND) + .unbind(c.COLLAPSE) + .unbind(c.ASYNC_SUCCESS) + .unbind(c.ASYNC_ERROR) + .unbind(c.REMOVE) + .unbind(c.SELECTED) + .unbind(c.UNSELECTED); + }, + //default event proxy of core + _eventProxy = function (event) { + var target = event.target, + setting = data.getSetting(event.data.treeId), + tId = "", node = null, + nodeEventType = "", treeEventType = "", + nodeEventCallback = null, treeEventCallback = null, + tmp = null; + + if (tools.eqs(event.type, "mousedown")) { + treeEventType = "mousedown"; + } else if (tools.eqs(event.type, "mouseup")) { + treeEventType = "mouseup"; + } else if (tools.eqs(event.type, "contextmenu")) { + treeEventType = "contextmenu"; + } else if (tools.eqs(event.type, "click")) { + if (tools.eqs(target.tagName, "span") && target.getAttribute("treeNode" + consts.id.SWITCH) !== null) { + tId = tools.getNodeMainDom(target).id; + nodeEventType = "switchNode"; + } else { + tmp = tools.getMDom(setting, target, [{tagName: "a", attrName: "treeNode" + consts.id.A}]); + if (tmp) { + tId = tools.getNodeMainDom(tmp).id; + nodeEventType = "clickNode"; + } + } + } else if (tools.eqs(event.type, "dblclick")) { + treeEventType = "dblclick"; + tmp = tools.getMDom(setting, target, [{tagName: "a", attrName: "treeNode" + consts.id.A}]); + if (tmp) { + tId = tools.getNodeMainDom(tmp).id; + nodeEventType = "switchNode"; + } + } + if (treeEventType.length > 0 && tId.length == 0) { + tmp = tools.getMDom(setting, target, [{tagName: "a", attrName: "treeNode" + consts.id.A}]); + if (tmp) { + tId = tools.getNodeMainDom(tmp).id; + } + } + // event to node + if (tId.length > 0) { + node = data.getNodeCache(setting, tId); + switch (nodeEventType) { + case "switchNode" : + var isParent = data.nodeIsParent(setting, node); + if (!isParent) { + nodeEventType = ""; + } else if (tools.eqs(event.type, "click") + || (tools.eqs(event.type, "dblclick") && tools.apply(setting.view.dblClickExpand, [setting.treeId, node], setting.view.dblClickExpand))) { + nodeEventCallback = handler.onSwitchNode; + } else { + nodeEventType = ""; + } + break; + case "clickNode" : + nodeEventCallback = handler.onClickNode; + break; + } + } + // event to zTree + switch (treeEventType) { + case "mousedown" : + treeEventCallback = handler.onZTreeMousedown; + break; + case "mouseup" : + treeEventCallback = handler.onZTreeMouseup; + break; + case "dblclick" : + treeEventCallback = handler.onZTreeDblclick; + break; + case "contextmenu" : + treeEventCallback = handler.onZTreeContextmenu; + break; + } + var proxyResult = { + stop: false, + node: node, + nodeEventType: nodeEventType, + nodeEventCallback: nodeEventCallback, + treeEventType: treeEventType, + treeEventCallback: treeEventCallback + }; + return proxyResult + }, + //default init node of core + _initNode = function (setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) { + if (!n) return; + var r = data.getRoot(setting), + children = data.nodeChildren(setting, n); + n.level = level; + n.tId = setting.treeId + "_" + (++r.zId); + n.parentTId = parentNode ? parentNode.tId : null; + n.open = (typeof n.open == "string") ? tools.eqs(n.open, "true") : !!n.open; + var isParent = data.nodeIsParent(setting, n); + if (tools.isArray(children)) { + data.nodeIsParent(setting, n, true); + n.zAsync = true; + } else { + isParent = data.nodeIsParent(setting, n, isParent); + n.open = (isParent && !setting.async.enable) ? n.open : false; + n.zAsync = !isParent; + } + n.isFirstNode = isFirstNode; + n.isLastNode = isLastNode; + n.getParentNode = function () { + return data.getNodeCache(setting, n.parentTId); + }; + n.getPreNode = function () { + return data.getPreNode(setting, n); + }; + n.getNextNode = function () { + return data.getNextNode(setting, n); + }; + n.getIndex = function () { + return data.getNodeIndex(setting, n); + }; + n.getPath = function () { + return data.getNodePath(setting, n); + }; + n.isAjaxing = false; + data.fixPIdKeyValue(setting, n); + }, + _init = { + bind: [_bindEvent], + unbind: [_unbindEvent], + caches: [_initCache], + nodes: [_initNode], + proxys: [_eventProxy], + roots: [_initRoot], + beforeA: [], + afterA: [], + innerBeforeA: [], + innerAfterA: [], + zTreeTools: [] + }, + //method of operate data + data = { + addNodeCache: function (setting, node) { + data.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = node; + }, + getNodeCacheId: function (tId) { + return tId.substring(tId.lastIndexOf("_") + 1); + }, + addAfterA: function (afterA) { + _init.afterA.push(afterA); + }, + addBeforeA: function (beforeA) { + _init.beforeA.push(beforeA); + }, + addInnerAfterA: function (innerAfterA) { + _init.innerAfterA.push(innerAfterA); + }, + addInnerBeforeA: function (innerBeforeA) { + _init.innerBeforeA.push(innerBeforeA); + }, + addInitBind: function (bindEvent) { + _init.bind.push(bindEvent); + }, + addInitUnBind: function (unbindEvent) { + _init.unbind.push(unbindEvent); + }, + addInitCache: function (initCache) { + _init.caches.push(initCache); + }, + addInitNode: function (initNode) { + _init.nodes.push(initNode); + }, + addInitProxy: function (initProxy, isFirst) { + if (!!isFirst) { + _init.proxys.splice(0, 0, initProxy); + } else { + _init.proxys.push(initProxy); + } + }, + addInitRoot: function (initRoot) { + _init.roots.push(initRoot); + }, + addNodesData: function (setting, parentNode, index, nodes) { + var children = data.nodeChildren(setting, parentNode), params; + if (!children) { + children = data.nodeChildren(setting, parentNode, []); + index = -1; + } else if (index >= children.length) { + index = -1; + } + + if (children.length > 0 && index === 0) { + children[0].isFirstNode = false; + view.setNodeLineIcos(setting, children[0]); + } else if (children.length > 0 && index < 0) { + children[children.length - 1].isLastNode = false; + view.setNodeLineIcos(setting, children[children.length - 1]); + } + data.nodeIsParent(setting, parentNode, true); + + if (index < 0) { + data.nodeChildren(setting, parentNode, children.concat(nodes)); + } else { + params = [index, 0].concat(nodes); + children.splice.apply(children, params); + } + }, + addSelectedNode: function (setting, node) { + var root = data.getRoot(setting); + if (!data.isSelectedNode(setting, node)) { + root.curSelectedList.push(node); + } + }, + addCreatedNode: function (setting, node) { + if (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) { + var root = data.getRoot(setting); + root.createdNodes.push(node); + } + }, + addZTreeTools: function (zTreeTools) { + _init.zTreeTools.push(zTreeTools); + }, + exSetting: function (s) { + $.extend(true, _setting, s); + }, + fixPIdKeyValue: function (setting, node) { + if (setting.data.simpleData.enable) { + node[setting.data.simpleData.pIdKey] = node.parentTId ? node.getParentNode()[setting.data.simpleData.idKey] : setting.data.simpleData.rootPId; + } + }, + getAfterA: function (setting, node, array) { + for (var i = 0, j = _init.afterA.length; i < j; i++) { + _init.afterA[i].apply(this, arguments); + } + }, + getBeforeA: function (setting, node, array) { + for (var i = 0, j = _init.beforeA.length; i < j; i++) { + _init.beforeA[i].apply(this, arguments); + } + }, + getInnerAfterA: function (setting, node, array) { + for (var i = 0, j = _init.innerAfterA.length; i < j; i++) { + _init.innerAfterA[i].apply(this, arguments); + } + }, + getInnerBeforeA: function (setting, node, array) { + for (var i = 0, j = _init.innerBeforeA.length; i < j; i++) { + _init.innerBeforeA[i].apply(this, arguments); + } + }, + getCache: function (setting) { + return caches[setting.treeId]; + }, + getNodeIndex: function (setting, node) { + if (!node) return null; + var p = node.parentTId ? node.getParentNode() : data.getRoot(setting), + children = data.nodeChildren(setting, p); + for (var i = 0, l = children.length - 1; i <= l; i++) { + if (children[i] === node) { + return i; + } + } + return -1; + }, + getNextNode: function (setting, node) { + if (!node) return null; + var p = node.parentTId ? node.getParentNode() : data.getRoot(setting), + children = data.nodeChildren(setting, p); + for (var i = 0, l = children.length - 1; i <= l; i++) { + if (children[i] === node) { + return (i == l ? null : children[i + 1]); + } + } + return null; + }, + getNodeByParam: function (setting, nodes, key, value) { + if (!nodes || !key) return null; + for (var i = 0, l = nodes.length; i < l; i++) { + var node = nodes[i]; + if (node[key] == value) { + return nodes[i]; + } + var children = data.nodeChildren(setting, node); + var tmp = data.getNodeByParam(setting, children, key, value); + if (tmp) return tmp; + } + return null; + }, + getNodeCache: function (setting, tId) { + if (!tId) return null; + var n = caches[setting.treeId].nodes[data.getNodeCacheId(tId)]; + return n ? n : null; + }, + getNodePath: function (setting, node) { + if (!node) return null; + + var path; + if (node.parentTId) { + path = node.getParentNode().getPath(); + } else { + path = []; + } + + if (path) { + path.push(node); + } + + return path; + }, + getNodes: function (setting) { + return data.nodeChildren(setting, data.getRoot(setting)); + }, + getNodesByParam: function (setting, nodes, key, value) { + if (!nodes || !key) return []; + var result = []; + for (var i = 0, l = nodes.length; i < l; i++) { + var node = nodes[i]; + if (node[key] == value) { + result.push(node); + } + var children = data.nodeChildren(setting, node); + result = result.concat(data.getNodesByParam(setting, children, key, value)); + } + return result; + }, + getNodesByParamFuzzy: function (setting, nodes, key, value) { + if (!nodes || !key) return []; + var result = []; + value = value.toLowerCase(); + for (var i = 0, l = nodes.length; i < l; i++) { + var node = nodes[i]; + if (typeof node[key] == "string" && nodes[i][key].toLowerCase().indexOf(value) > -1) { + result.push(node); + } + var children = data.nodeChildren(setting, node); + result = result.concat(data.getNodesByParamFuzzy(setting, children, key, value)); + } + return result; + }, + getNodesByFilter: function (setting, nodes, filter, isSingle, invokeParam) { + if (!nodes) return (isSingle ? null : []); + var result = isSingle ? null : []; + for (var i = 0, l = nodes.length; i < l; i++) { + var node = nodes[i]; + if (tools.apply(filter, [node, invokeParam], false)) { + if (isSingle) { + return node; + } + result.push(node); + } + var children = data.nodeChildren(setting, node); + var tmpResult = data.getNodesByFilter(setting, children, filter, isSingle, invokeParam); + if (isSingle && !!tmpResult) { + return tmpResult; + } + result = isSingle ? tmpResult : result.concat(tmpResult); + } + return result; + }, + getPreNode: function (setting, node) { + if (!node) return null; + var p = node.parentTId ? node.getParentNode() : data.getRoot(setting), + children = data.nodeChildren(setting, p); + for (var i = 0, l = children.length; i < l; i++) { + if (children[i] === node) { + return (i == 0 ? null : children[i - 1]); + } + } + return null; + }, + getRoot: function (setting) { + return setting ? roots[setting.treeId] : null; + }, + getRoots: function () { + return roots; + }, + getSetting: function (treeId) { + return settings[treeId]; + }, + getSettings: function () { + return settings; + }, + getZTreeTools: function (treeId) { + var r = this.getRoot(this.getSetting(treeId)); + return r ? r.treeTools : null; + }, + initCache: function (setting) { + for (var i = 0, j = _init.caches.length; i < j; i++) { + _init.caches[i].apply(this, arguments); + } + }, + initNode: function (setting, level, node, parentNode, preNode, nextNode) { + for (var i = 0, j = _init.nodes.length; i < j; i++) { + _init.nodes[i].apply(this, arguments); + } + }, + initRoot: function (setting) { + for (var i = 0, j = _init.roots.length; i < j; i++) { + _init.roots[i].apply(this, arguments); + } + }, + isSelectedNode: function (setting, node) { + var root = data.getRoot(setting); + for (var i = 0, j = root.curSelectedList.length; i < j; i++) { + if (node === root.curSelectedList[i]) return true; + } + return false; + }, + nodeChildren: function (setting, node, newChildren) { + if (!node) { + return null; + } + var key = setting.data.key.children; + if (typeof newChildren !== 'undefined') { + node[key] = newChildren; + } + return node[key]; + }, + nodeIsParent: function (setting, node, newIsParent) { + if (!node) { + return false; + } + var key = setting.data.key.isParent; + if (typeof newIsParent !== 'undefined') { + if (typeof newIsParent === "string") { + newIsParent = tools.eqs(newIsParent, "true"); + } + newIsParent = !!newIsParent; + node[key] = newIsParent; + } else if (typeof node[key] == "string"){ + node[key] = tools.eqs(node[key], "true"); + } else { + node[key] = !!node[key]; + } + return node[key]; + }, + nodeName: function (setting, node, newName) { + var key = setting.data.key.name; + if (typeof newName !== 'undefined') { + node[key] = newName; + } + var rawName = "" + node[key]; + if(typeof setting.data.render.name === 'function') { + return setting.data.render.name.call(this,rawName,node); + } + return rawName; + }, + nodeTitle: function (setting, node) { + var t = setting.data.key.title === "" ? setting.data.key.name : setting.data.key.title; + var rawTitle = "" + node[t]; + if(typeof setting.data.render.title === 'function') { + return setting.data.render.title.call(this,rawTitle,node); + } + return rawTitle; + }, + removeNodeCache: function (setting, node) { + var children = data.nodeChildren(setting, node); + if (children) { + for (var i = 0, l = children.length; i < l; i++) { + data.removeNodeCache(setting, children[i]); + } + } + data.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = null; + }, + removeSelectedNode: function (setting, node) { + var root = data.getRoot(setting); + for (var i = 0, j = root.curSelectedList.length; i < j; i++) { + if (node === root.curSelectedList[i] || !data.getNodeCache(setting, root.curSelectedList[i].tId)) { + root.curSelectedList.splice(i, 1); + setting.treeObj.trigger(consts.event.UNSELECTED, [setting.treeId, node]); + i--; + j--; + } + } + }, + setCache: function (setting, cache) { + caches[setting.treeId] = cache; + }, + setRoot: function (setting, root) { + roots[setting.treeId] = root; + }, + setZTreeTools: function (setting, zTreeTools) { + for (var i = 0, j = _init.zTreeTools.length; i < j; i++) { + _init.zTreeTools[i].apply(this, arguments); + } + }, + transformToArrayFormat: function (setting, nodes) { + if (!nodes) return []; + var r = []; + if (tools.isArray(nodes)) { + for (var i = 0, l = nodes.length; i < l; i++) { + var node = nodes[i]; + _do(node); + } + } else { + _do(nodes); + } + return r; + + function _do(_node) { + r.push(_node); + var children = data.nodeChildren(setting, _node); + if (children) { + r = r.concat(data.transformToArrayFormat(setting, children)); + } + } + }, + transformTozTreeFormat: function (setting, sNodes) { + var i, l, + key = setting.data.simpleData.idKey, + parentKey = setting.data.simpleData.pIdKey; + if (!key || key == "" || !sNodes) return []; + + if (tools.isArray(sNodes)) { + var r = []; + var tmpMap = {}; + for (i = 0, l = sNodes.length; i < l; i++) { + tmpMap[sNodes[i][key]] = sNodes[i]; + } + for (i = 0, l = sNodes.length; i < l; i++) { + var p = tmpMap[sNodes[i][parentKey]]; + if (p && sNodes[i][key] != sNodes[i][parentKey]) { + var children = data.nodeChildren(setting, p); + if (!children) { + children = data.nodeChildren(setting, p, []); + } + children.push(sNodes[i]); + } else { + r.push(sNodes[i]); + } + } + return r; + } else { + return [sNodes]; + } + } + }, + //method of event proxy + event = { + bindEvent: function (setting) { + for (var i = 0, j = _init.bind.length; i < j; i++) { + _init.bind[i].apply(this, arguments); + } + }, + unbindEvent: function (setting) { + for (var i = 0, j = _init.unbind.length; i < j; i++) { + _init.unbind[i].apply(this, arguments); + } + }, + bindTree: function (setting) { + var eventParam = { + treeId: setting.treeId + }, + o = setting.treeObj; + if (!setting.view.txtSelectedEnable) { + // for can't select text + o.bind('selectstart', handler.onSelectStart).css({ + "-moz-user-select": "-moz-none" + }); + } + o.bind('click', eventParam, event.proxy); + o.bind('dblclick', eventParam, event.proxy); + o.bind('mouseover', eventParam, event.proxy); + o.bind('mouseout', eventParam, event.proxy); + o.bind('mousedown', eventParam, event.proxy); + o.bind('mouseup', eventParam, event.proxy); + o.bind('contextmenu', eventParam, event.proxy); + }, + unbindTree: function (setting) { + var o = setting.treeObj; + o.unbind('selectstart', handler.onSelectStart) + .unbind('click', event.proxy) + .unbind('dblclick', event.proxy) + .unbind('mouseover', event.proxy) + .unbind('mouseout', event.proxy) + .unbind('mousedown', event.proxy) + .unbind('mouseup', event.proxy) + .unbind('contextmenu', event.proxy); + }, + doProxy: function (e) { + var results = []; + for (var i = 0, j = _init.proxys.length; i < j; i++) { + var proxyResult = _init.proxys[i].apply(this, arguments); + results.push(proxyResult); + if (proxyResult.stop) { + break; + } + } + return results; + }, + proxy: function (e) { + var setting = data.getSetting(e.data.treeId); + if (!tools.uCanDo(setting, e)) return true; + var results = event.doProxy(e), + r = true, x = false; + for (var i = 0, l = results.length; i < l; i++) { + var proxyResult = results[i]; + if (proxyResult.nodeEventCallback) { + x = true; + r = proxyResult.nodeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r; + } + if (proxyResult.treeEventCallback) { + x = true; + r = proxyResult.treeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r; + } + } + return r; + } + }, + //method of event handler + handler = { + onSwitchNode: function (event, node) { + var setting = data.getSetting(event.data.treeId); + if (node.open) { + if (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false) return true; + data.getRoot(setting).expandTriggerFlag = true; + view.switchNode(setting, node); + } else { + if (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false) return true; + data.getRoot(setting).expandTriggerFlag = true; + view.switchNode(setting, node); + } + return true; + }, + onClickNode: function (event, node) { + var setting = data.getSetting(event.data.treeId), + clickFlag = ((setting.view.autoCancelSelected && (event.ctrlKey || event.metaKey)) && data.isSelectedNode(setting, node)) ? 0 : (setting.view.autoCancelSelected && (event.ctrlKey || event.metaKey) && setting.view.selectedMulti) ? 2 : 1; + if (tools.apply(setting.callback.beforeClick, [setting.treeId, node, clickFlag], true) == false) return true; + if (clickFlag === 0) { + view.cancelPreSelectedNode(setting, node); + } else { + view.selectNode(setting, node, clickFlag === 2); + } + setting.treeObj.trigger(consts.event.CLICK, [event, setting.treeId, node, clickFlag]); + return true; + }, + onZTreeMousedown: function (event, node) { + var setting = data.getSetting(event.data.treeId); + if (tools.apply(setting.callback.beforeMouseDown, [setting.treeId, node], true)) { + tools.apply(setting.callback.onMouseDown, [event, setting.treeId, node]); + } + return true; + }, + onZTreeMouseup: function (event, node) { + var setting = data.getSetting(event.data.treeId); + if (tools.apply(setting.callback.beforeMouseUp, [setting.treeId, node], true)) { + tools.apply(setting.callback.onMouseUp, [event, setting.treeId, node]); + } + return true; + }, + onZTreeDblclick: function (event, node) { + var setting = data.getSetting(event.data.treeId); + if (tools.apply(setting.callback.beforeDblClick, [setting.treeId, node], true)) { + tools.apply(setting.callback.onDblClick, [event, setting.treeId, node]); + } + return true; + }, + onZTreeContextmenu: function (event, node) { + var setting = data.getSetting(event.data.treeId); + if (tools.apply(setting.callback.beforeRightClick, [setting.treeId, node], true)) { + tools.apply(setting.callback.onRightClick, [event, setting.treeId, node]); + } + return (typeof setting.callback.onRightClick) != "function"; + }, + onSelectStart: function (e) { + var n = e.originalEvent.srcElement.nodeName.toLowerCase(); + return (n === "input" || n === "textarea"); + } + }, + //method of tools for zTree + tools = { + apply: function (fun, param, defaultValue) { + if ((typeof fun) == "function") { + return fun.apply(zt, param ? param : []); + } + return defaultValue; + }, + canAsync: function (setting, node) { + var children = data.nodeChildren(setting, node); + var isParent = data.nodeIsParent(setting, node); + return (setting.async.enable && node && isParent && !(node.zAsync || (children && children.length > 0))); + }, + clone: function (obj) { + if (obj === null) return null; + var o = tools.isArray(obj) ? [] : {}; + for (var i in obj) { + o[i] = (obj[i] instanceof Date) ? new Date(obj[i].getTime()) : (typeof obj[i] === "object" ? tools.clone(obj[i]) : obj[i]); + } + return o; + }, + eqs: function (str1, str2) { + return str1.toLowerCase() === str2.toLowerCase(); + }, + isArray: function (arr) { + return Object.prototype.toString.apply(arr) === "[object Array]"; + }, + isElement: function (o) { + return ( + typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2 + o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName === "string" + ); + }, + $: function (node, exp, setting) { + if (!!exp && typeof exp != "string") { + setting = exp; + exp = ""; + } + if (typeof node == "string") { + return $(node, setting ? setting.treeObj.get(0).ownerDocument : null); + } else { + return $("#" + node.tId + exp, setting ? setting.treeObj : null); + } + }, + getMDom: function (setting, curDom, targetExpr) { + if (!curDom) return null; + while (curDom && curDom.id !== setting.treeId) { + for (var i = 0, l = targetExpr.length; curDom.tagName && i < l; i++) { + if (tools.eqs(curDom.tagName, targetExpr[i].tagName) && curDom.getAttribute(targetExpr[i].attrName) !== null) { + return curDom; + } + } + curDom = curDom.parentNode; + } + return null; + }, + getNodeMainDom: function (target) { + return ($(target).parent("li").get(0) || $(target).parentsUntil("li").parent().get(0)); + }, + isChildOrSelf: function (dom, parentId) { + return ($(dom).closest("#" + parentId).length > 0); + }, + uCanDo: function (setting, e) { + return true; + } + }, + //method of operate ztree dom + view = { + addNodes: function (setting, parentNode, index, newNodes, isSilent) { + var isParent = data.nodeIsParent(setting, parentNode); + if (setting.data.keep.leaf && parentNode && !isParent) { + return; + } + if (!tools.isArray(newNodes)) { + newNodes = [newNodes]; + } + if (setting.data.simpleData.enable) { + newNodes = data.transformTozTreeFormat(setting, newNodes); + } + if (parentNode) { + var target_switchObj = $$(parentNode, consts.id.SWITCH, setting), + target_icoObj = $$(parentNode, consts.id.ICON, setting), + target_ulObj = $$(parentNode, consts.id.UL, setting); + + if (!parentNode.open) { + view.replaceSwitchClass(parentNode, target_switchObj, consts.folder.CLOSE); + view.replaceIcoClass(parentNode, target_icoObj, consts.folder.CLOSE); + parentNode.open = false; + target_ulObj.css({ + "display": "none" + }); + } + + data.addNodesData(setting, parentNode, index, newNodes); + view.createNodes(setting, parentNode.level + 1, newNodes, parentNode, index); + if (!isSilent) { + view.expandCollapseParentNode(setting, parentNode, true); + } + } else { + data.addNodesData(setting, data.getRoot(setting), index, newNodes); + view.createNodes(setting, 0, newNodes, null, index); + } + }, + appendNodes: function (setting, level, nodes, parentNode, index, initFlag, openFlag) { + if (!nodes) return []; + var html = []; + + var tmpPNode = (parentNode) ? parentNode : data.getRoot(setting), + tmpPChild = data.nodeChildren(setting, tmpPNode), + isFirstNode, isLastNode; + + if (!tmpPChild || index >= tmpPChild.length - nodes.length) { + index = -1; + } + + for (var i = 0, l = nodes.length; i < l; i++) { + var node = nodes[i]; + if (initFlag) { + isFirstNode = ((index === 0 || tmpPChild.length == nodes.length) && (i == 0)); + isLastNode = (index < 0 && i == (nodes.length - 1)); + data.initNode(setting, level, node, parentNode, isFirstNode, isLastNode, openFlag); + data.addNodeCache(setting, node); + } + var isParent = data.nodeIsParent(setting, node); + + var childHtml = []; + var children = data.nodeChildren(setting, node); + if (children && children.length > 0) { + //make child html first, because checkType + childHtml = view.appendNodes(setting, level + 1, children, node, -1, initFlag, openFlag && node.open); + } + if (openFlag) { + view.makeDOMNodeMainBefore(html, setting, node); + view.makeDOMNodeLine(html, setting, node); + data.getBeforeA(setting, node, html); + view.makeDOMNodeNameBefore(html, setting, node); + data.getInnerBeforeA(setting, node, html); + view.makeDOMNodeIcon(html, setting, node); + data.getInnerAfterA(setting, node, html); + view.makeDOMNodeNameAfter(html, setting, node); + data.getAfterA(setting, node, html); + if (isParent && node.open) { + view.makeUlHtml(setting, node, html, childHtml.join('')); + } + view.makeDOMNodeMainAfter(html, setting, node); + data.addCreatedNode(setting, node); + } + } + return html; + }, + appendParentULDom: function (setting, node) { + var html = [], + nObj = $$(node, setting); + if (!nObj.get(0) && !!node.parentTId) { + view.appendParentULDom(setting, node.getParentNode()); + nObj = $$(node, setting); + } + var ulObj = $$(node, consts.id.UL, setting); + if (ulObj.get(0)) { + ulObj.remove(); + } + var children = data.nodeChildren(setting, node), + childHtml = view.appendNodes(setting, node.level + 1, children, node, -1, false, true); + view.makeUlHtml(setting, node, html, childHtml.join('')); + nObj.append(html.join('')); + }, + asyncNode: function (setting, node, isSilent, callback) { + var i, l; + var isParent = data.nodeIsParent(setting, node); + if (node && !isParent) { + tools.apply(callback); + return false; + } else if (node && node.isAjaxing) { + return false; + } else if (tools.apply(setting.callback.beforeAsync, [setting.treeId, node], true) == false) { + tools.apply(callback); + return false; + } + if (node) { + node.isAjaxing = true; + var icoObj = $$(node, consts.id.ICON, setting); + icoObj.attr({"style": "", "class": consts.className.BUTTON + " " + consts.className.ICO_LOADING}); + } + + var tmpParam = {}; + var autoParam = tools.apply(setting.async.autoParam, [setting.treeId, node], setting.async.autoParam); + for (i = 0, l = autoParam.length; node && i < l; i++) { + var pKey = autoParam[i].split("="), spKey = pKey; + if (pKey.length > 1) { + spKey = pKey[1]; + pKey = pKey[0]; + } + tmpParam[spKey] = node[pKey]; + } + var otherParam = tools.apply(setting.async.otherParam, [setting.treeId, node], setting.async.otherParam); + if (tools.isArray(otherParam)) { + for (i = 0, l = otherParam.length; i < l; i += 2) { + tmpParam[otherParam[i]] = otherParam[i + 1]; + } + } else { + for (var p in otherParam) { + tmpParam[p] = otherParam[p]; + } + } + + var _tmpV = data.getRoot(setting)._ver; + $.ajax({ + contentType: setting.async.contentType, + cache: false, + type: setting.async.type, + url: tools.apply(setting.async.url, [setting.treeId, node], setting.async.url), + data: setting.async.contentType.indexOf('application/json') > -1 ? JSON.stringify(tmpParam) : tmpParam, + dataType: setting.async.dataType, + headers: setting.async.headers, + xhrFields: setting.async.xhrFields, + success: function (msg) { + if (_tmpV != data.getRoot(setting)._ver) { + return; + } + var newNodes = []; + try { + if (!msg || msg.length == 0) { + newNodes = []; + } else if (typeof msg == "string") { + newNodes = eval("(" + msg + ")"); + } else { + newNodes = msg; + } + } catch (err) { + newNodes = msg; + } + + if (node) { + node.isAjaxing = null; + node.zAsync = true; + } + view.setNodeLineIcos(setting, node); + if (newNodes && newNodes !== "") { + newNodes = tools.apply(setting.async.dataFilter, [setting.treeId, node, newNodes], newNodes); + view.addNodes(setting, node, -1, !!newNodes ? tools.clone(newNodes) : [], !!isSilent); + } else { + view.addNodes(setting, node, -1, [], !!isSilent); + } + setting.treeObj.trigger(consts.event.ASYNC_SUCCESS, [setting.treeId, node, msg]); + tools.apply(callback); + }, + error: function (XMLHttpRequest, textStatus, errorThrown) { + if (_tmpV != data.getRoot(setting)._ver) { + return; + } + if (node) node.isAjaxing = null; + view.setNodeLineIcos(setting, node); + setting.treeObj.trigger(consts.event.ASYNC_ERROR, [setting.treeId, node, XMLHttpRequest, textStatus, errorThrown]); + } + }); + return true; + }, + cancelPreSelectedNode: function (setting, node, excludeNode) { + var list = data.getRoot(setting).curSelectedList, + i, n; + for (i = list.length - 1; i >= 0; i--) { + n = list[i]; + if (node === n || (!node && (!excludeNode || excludeNode !== n))) { + $$(n, consts.id.A, setting).removeClass(consts.node.CURSELECTED); + if (node) { + data.removeSelectedNode(setting, node); + break; + } else { + list.splice(i, 1); + setting.treeObj.trigger(consts.event.UNSELECTED, [setting.treeId, n]); + } + } + } + }, + createNodeCallback: function (setting) { + if (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) { + var root = data.getRoot(setting); + while (root.createdNodes.length > 0) { + var node = root.createdNodes.shift(); + tools.apply(setting.view.addDiyDom, [setting.treeId, node]); + if (!!setting.callback.onNodeCreated) { + setting.treeObj.trigger(consts.event.NODECREATED, [setting.treeId, node]); + } + } + } + }, + createNodes: function (setting, level, nodes, parentNode, index) { + if (!nodes || nodes.length == 0) return; + var root = data.getRoot(setting), + openFlag = !parentNode || parentNode.open || !!$$(data.nodeChildren(setting, parentNode)[0], setting).get(0); + root.createdNodes = []; + var zTreeHtml = view.appendNodes(setting, level, nodes, parentNode, index, true, openFlag), + parentObj, nextObj; + + if (!parentNode) { + parentObj = setting.treeObj; + //setting.treeObj.append(zTreeHtml.join('')); + } else { + var ulObj = $$(parentNode, consts.id.UL, setting); + if (ulObj.get(0)) { + parentObj = ulObj; + //ulObj.append(zTreeHtml.join('')); + } + } + if (parentObj) { + if (index >= 0) { + nextObj = parentObj.children()[index]; + } + if (index >= 0 && nextObj) { + $(nextObj).before(zTreeHtml.join('')); + } else { + parentObj.append(zTreeHtml.join('')); + } + } + + view.createNodeCallback(setting); + }, + destroy: function (setting) { + if (!setting) return; + data.initCache(setting); + data.initRoot(setting); + event.unbindTree(setting); + event.unbindEvent(setting); + setting.treeObj.empty(); + delete settings[setting.treeId]; + }, + expandCollapseNode: function (setting, node, expandFlag, animateFlag, callback) { + var root = data.getRoot(setting); + var tmpCb, _callback; + if (!node) { + tools.apply(callback, []); + return; + } + var children = data.nodeChildren(setting, node); + var isParent = data.nodeIsParent(setting, node); + if (root.expandTriggerFlag) { + _callback = callback; + tmpCb = function () { + if (_callback) _callback(); + if (node.open) { + setting.treeObj.trigger(consts.event.EXPAND, [setting.treeId, node]); + } else { + setting.treeObj.trigger(consts.event.COLLAPSE, [setting.treeId, node]); + } + }; + callback = tmpCb; + root.expandTriggerFlag = false; + } + if (!node.open && isParent && ((!$$(node, consts.id.UL, setting).get(0)) || (children && children.length > 0 && !$$(children[0], setting).get(0)))) { + view.appendParentULDom(setting, node); + view.createNodeCallback(setting); + } + if (node.open == expandFlag) { + tools.apply(callback, []); + return; + } + var ulObj = $$(node, consts.id.UL, setting), + switchObj = $$(node, consts.id.SWITCH, setting), + icoObj = $$(node, consts.id.ICON, setting); + + if (isParent) { + node.open = !node.open; + if (node.iconOpen && node.iconClose) { + icoObj.attr("style", view.makeNodeIcoStyle(setting, node)); + } + + if (node.open) { + view.replaceSwitchClass(node, switchObj, consts.folder.OPEN); + view.replaceIcoClass(node, icoObj, consts.folder.OPEN); + if (animateFlag == false || setting.view.expandSpeed == "") { + ulObj.show(); + tools.apply(callback, []); + } else { + if (children && children.length > 0) { + ulObj.slideDown(setting.view.expandSpeed, callback); + } else { + ulObj.show(); + tools.apply(callback, []); + } + } + } else { + view.replaceSwitchClass(node, switchObj, consts.folder.CLOSE); + view.replaceIcoClass(node, icoObj, consts.folder.CLOSE); + if (animateFlag == false || setting.view.expandSpeed == "" || !(children && children.length > 0)) { + ulObj.hide(); + tools.apply(callback, []); + } else { + ulObj.slideUp(setting.view.expandSpeed, callback); + } + } + } else { + tools.apply(callback, []); + } + }, + expandCollapseParentNode: function (setting, node, expandFlag, animateFlag, callback) { + if (!node) return; + if (!node.parentTId) { + view.expandCollapseNode(setting, node, expandFlag, animateFlag, callback); + return; + } else { + view.expandCollapseNode(setting, node, expandFlag, animateFlag); + } + if (node.parentTId) { + view.expandCollapseParentNode(setting, node.getParentNode(), expandFlag, animateFlag, callback); + } + }, + expandCollapseSonNode: function (setting, node, expandFlag, animateFlag, callback) { + var root = data.getRoot(setting), + treeNodes = (node) ? data.nodeChildren(setting, node) : data.nodeChildren(setting, root), + selfAnimateSign = (node) ? false : animateFlag, + expandTriggerFlag = data.getRoot(setting).expandTriggerFlag; + data.getRoot(setting).expandTriggerFlag = false; + if (treeNodes) { + for (var i = 0, l = treeNodes.length; i < l; i++) { + if (treeNodes[i]) view.expandCollapseSonNode(setting, treeNodes[i], expandFlag, selfAnimateSign); + } + } + data.getRoot(setting).expandTriggerFlag = expandTriggerFlag; + view.expandCollapseNode(setting, node, expandFlag, animateFlag, callback); + }, + isSelectedNode: function (setting, node) { + if (!node) { + return false; + } + var list = data.getRoot(setting).curSelectedList, + i; + for (i = list.length - 1; i >= 0; i--) { + if (node === list[i]) { + return true; + } + } + return false; + }, + makeDOMNodeIcon: function (html, setting, node) { + var nameStr = data.nodeName(setting, node), + name = setting.view.nameIsHTML ? nameStr : nameStr.replace(/&/g, '&').replace(//g, '>'); + html.push("", name, ""); + }, + makeDOMNodeLine: function (html, setting, node) { + html.push(""); + }, + makeDOMNodeMainAfter: function (html, setting, node) { + html.push("
    • "); + }, + makeDOMNodeMainBefore: function (html, setting, node) { + html.push("
    • "); + }, + makeDOMNodeNameAfter: function (html, setting, node) { + html.push(""); + }, + makeDOMNodeNameBefore: function (html, setting, node) { + var title = data.nodeTitle(setting, node), + url = view.makeNodeUrl(setting, node), + fontcss = view.makeNodeFontCss(setting, node), + nodeClasses = view.makeNodeClasses(setting, node), + fontStyle = []; + for (var f in fontcss) { + fontStyle.push(f, ":", fontcss[f], ";"); + } + html.push(" 0) ? " href='" + url + "'" : ""), " target='", view.makeNodeTarget(node), "' style='", fontStyle.join(''), + "'"); + if (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle) && title) { + html.push("title='", title.replace(/'/g, "'").replace(//g, '>'), "'"); + } + html.push(">"); + }, + makeNodeFontCss: function (setting, node) { + var fontCss = tools.apply(setting.view.fontCss, [setting.treeId, node], setting.view.fontCss); + return (fontCss && ((typeof fontCss) != "function")) ? fontCss : {}; + }, + makeNodeClasses: function (setting, node) { + var classes = tools.apply(setting.view.nodeClasses, [setting.treeId, node], setting.view.nodeClasses); + return (classes && (typeof classes !== "function")) ? classes : {add:[], remove:[]}; + }, + makeNodeIcoClass: function (setting, node) { + var icoCss = ["ico"]; + if (!node.isAjaxing) { + var isParent = data.nodeIsParent(setting, node); + icoCss[0] = (node.iconSkin ? node.iconSkin + "_" : "") + icoCss[0]; + if (isParent) { + icoCss.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE); + } else { + icoCss.push(consts.folder.DOCU); + } + } + return consts.className.BUTTON + " " + icoCss.join('_'); + }, + makeNodeIcoStyle: function (setting, node) { + var icoStyle = []; + if (!node.isAjaxing) { + var isParent = data.nodeIsParent(setting, node); + var icon = (isParent && node.iconOpen && node.iconClose) ? (node.open ? node.iconOpen : node.iconClose) : node[setting.data.key.icon]; + if (icon) icoStyle.push("background:url(", icon, ") 0 0 no-repeat;"); + if (setting.view.showIcon == false || !tools.apply(setting.view.showIcon, [setting.treeId, node], true)) { + icoStyle.push("display:none;"); + } + } + return icoStyle.join(''); + }, + makeNodeLineClass: function (setting, node) { + var lineClass = []; + if (setting.view.showLine) { + if (node.level == 0 && node.isFirstNode && node.isLastNode) { + lineClass.push(consts.line.ROOT); + } else if (node.level == 0 && node.isFirstNode) { + lineClass.push(consts.line.ROOTS); + } else if (node.isLastNode) { + lineClass.push(consts.line.BOTTOM); + } else { + lineClass.push(consts.line.CENTER); + } + } else { + lineClass.push(consts.line.NOLINE); + } + if (data.nodeIsParent(setting, node)) { + lineClass.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE); + } else { + lineClass.push(consts.folder.DOCU); + } + return view.makeNodeLineClassEx(node) + lineClass.join('_'); + }, + makeNodeLineClassEx: function (node) { + return consts.className.BUTTON + " " + consts.className.LEVEL + node.level + " " + consts.className.SWITCH + " "; + }, + makeNodeTarget: function (node) { + return (node.target || "_blank"); + }, + makeNodeUrl: function (setting, node) { + var urlKey = setting.data.key.url; + return node[urlKey] ? node[urlKey] : null; + }, + makeUlHtml: function (setting, node, html, content) { + html.push("
        "); + html.push(content); + html.push("
      "); + }, + makeUlLineClass: function (setting, node) { + return ((setting.view.showLine && !node.isLastNode) ? consts.line.LINE : ""); + }, + removeChildNodes: function (setting, node) { + if (!node) return; + var nodes = data.nodeChildren(setting, node); + if (!nodes) return; + + for (var i = 0, l = nodes.length; i < l; i++) { + data.removeNodeCache(setting, nodes[i]); + } + data.removeSelectedNode(setting); + delete node[setting.data.key.children]; + + if (!setting.data.keep.parent) { + data.nodeIsParent(setting, node, false); + node.open = false; + var tmp_switchObj = $$(node, consts.id.SWITCH, setting), + tmp_icoObj = $$(node, consts.id.ICON, setting); + view.replaceSwitchClass(node, tmp_switchObj, consts.folder.DOCU); + view.replaceIcoClass(node, tmp_icoObj, consts.folder.DOCU); + $$(node, consts.id.UL, setting).remove(); + } else { + $$(node, consts.id.UL, setting).empty(); + } + }, + scrollIntoView: function (setting, dom) { + if (!dom) { + return; + } + // support IE 7 / 8 + if (typeof Element === 'undefined' || typeof HTMLElement === 'undefined') { + var contRect = setting.treeObj.get(0).getBoundingClientRect(), + findMeRect = dom.getBoundingClientRect(); + if (findMeRect.top < contRect.top || findMeRect.bottom > contRect.bottom + || findMeRect.right > contRect.right || findMeRect.left < contRect.left) { + dom.scrollIntoView(); + } + return; + } + // CC-BY jocki84@googlemail.com, https://gist.github.com/jocki84/6ffafd003387179a988e + if (!Element.prototype.scrollIntoViewIfNeeded) { + Element.prototype.scrollIntoViewIfNeeded = function (centerIfNeeded) { + "use strict"; + + function makeRange(start, length) { + return {"start": start, "length": length, "end": start + length}; + } + + function coverRange(inner, outer) { + if ( + false === centerIfNeeded || + (outer.start < inner.end && inner.start < outer.end) + ) { + return Math.max( + inner.end - outer.length, + Math.min(outer.start, inner.start) + ); + } + return (inner.start + inner.end - outer.length) / 2; + } + + function makePoint(x, y) { + return { + "x": x, + "y": y, + "translate": function translate(dX, dY) { + return makePoint(x + dX, y + dY); + } + }; + } + + function absolute(elem, pt) { + while (elem) { + pt = pt.translate(elem.offsetLeft, elem.offsetTop); + elem = elem.offsetParent; + } + return pt; + } + + var target = absolute(this, makePoint(0, 0)), + extent = makePoint(this.offsetWidth, this.offsetHeight), + elem = this.parentNode, + origin; + + while (elem instanceof HTMLElement) { + // Apply desired scroll amount. + origin = absolute(elem, makePoint(elem.clientLeft, elem.clientTop)); + elem.scrollLeft = coverRange( + makeRange(target.x - origin.x, extent.x), + makeRange(elem.scrollLeft, elem.clientWidth) + ); + elem.scrollTop = coverRange( + makeRange(target.y - origin.y, extent.y), + makeRange(elem.scrollTop, elem.clientHeight) + ); + + // Determine actual scroll amount by reading back scroll properties. + target = target.translate(-elem.scrollLeft, -elem.scrollTop); + elem = elem.parentNode; + } + }; + } + dom.scrollIntoViewIfNeeded(); + }, + setFirstNode: function (setting, parentNode) { + var children = data.nodeChildren(setting, parentNode); + if (children.length > 0) { + children[0].isFirstNode = true; + } + }, + setLastNode: function (setting, parentNode) { + var children = data.nodeChildren(setting, parentNode); + if (children.length > 0) { + children[children.length - 1].isLastNode = true; + } + }, + removeNode: function (setting, node) { + var root = data.getRoot(setting), + parentNode = (node.parentTId) ? node.getParentNode() : root; + + node.isFirstNode = false; + node.isLastNode = false; + node.getPreNode = function () { + return null; + }; + node.getNextNode = function () { + return null; + }; + + if (!data.getNodeCache(setting, node.tId)) { + return; + } + + $$(node, setting).remove(); + data.removeNodeCache(setting, node); + data.removeSelectedNode(setting, node); + + var children = data.nodeChildren(setting, parentNode); + for (var i = 0, l = children.length; i < l; i++) { + if (children[i].tId == node.tId) { + children.splice(i, 1); + break; + } + } + view.setFirstNode(setting, parentNode); + view.setLastNode(setting, parentNode); + + var tmp_ulObj, tmp_switchObj, tmp_icoObj, + childLength = children.length; + + //repair nodes old parent + if (!setting.data.keep.parent && childLength == 0) { + //old parentNode has no child nodes + data.nodeIsParent(setting, parentNode, false); + parentNode.open = false; + delete parentNode[setting.data.key.children]; + tmp_ulObj = $$(parentNode, consts.id.UL, setting); + tmp_switchObj = $$(parentNode, consts.id.SWITCH, setting); + tmp_icoObj = $$(parentNode, consts.id.ICON, setting); + view.replaceSwitchClass(parentNode, tmp_switchObj, consts.folder.DOCU); + view.replaceIcoClass(parentNode, tmp_icoObj, consts.folder.DOCU); + tmp_ulObj.css("display", "none"); + + } else if (setting.view.showLine && childLength > 0) { + //old parentNode has child nodes + var newLast = children[childLength - 1]; + tmp_ulObj = $$(newLast, consts.id.UL, setting); + tmp_switchObj = $$(newLast, consts.id.SWITCH, setting); + tmp_icoObj = $$(newLast, consts.id.ICON, setting); + if (parentNode == root) { + if (children.length == 1) { + //node was root, and ztree has only one root after move node + view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.ROOT); + } else { + var tmp_first_switchObj = $$(children[0], consts.id.SWITCH, setting); + view.replaceSwitchClass(children[0], tmp_first_switchObj, consts.line.ROOTS); + view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM); + } + } else { + view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM); + } + tmp_ulObj.removeClass(consts.line.LINE); + } + }, + replaceIcoClass: function (node, obj, newName) { + if (!obj || node.isAjaxing) return; + var tmpName = obj.attr("class"); + if (tmpName == undefined) return; + var tmpList = tmpName.split("_"); + switch (newName) { + case consts.folder.OPEN: + case consts.folder.CLOSE: + case consts.folder.DOCU: + tmpList[tmpList.length - 1] = newName; + break; + } + obj.attr("class", tmpList.join("_")); + }, + replaceSwitchClass: function (node, obj, newName) { + if (!obj) return; + var tmpName = obj.attr("class"); + if (tmpName == undefined) return; + var tmpList = tmpName.split("_"); + switch (newName) { + case consts.line.ROOT: + case consts.line.ROOTS: + case consts.line.CENTER: + case consts.line.BOTTOM: + case consts.line.NOLINE: + tmpList[0] = view.makeNodeLineClassEx(node) + newName; + break; + case consts.folder.OPEN: + case consts.folder.CLOSE: + case consts.folder.DOCU: + tmpList[1] = newName; + break; + } + obj.attr("class", tmpList.join("_")); + if (newName !== consts.folder.DOCU) { + obj.removeAttr("disabled"); + } else { + obj.attr("disabled", "disabled"); + } + }, + selectNode: function (setting, node, addFlag) { + if (!addFlag) { + view.cancelPreSelectedNode(setting, null, node); + } + $$(node, consts.id.A, setting).addClass(consts.node.CURSELECTED); + data.addSelectedNode(setting, node); + setting.treeObj.trigger(consts.event.SELECTED, [setting.treeId, node]); + }, + setNodeFontCss: function (setting, treeNode) { + var aObj = $$(treeNode, consts.id.A, setting), + fontCss = view.makeNodeFontCss(setting, treeNode); + if (fontCss) { + aObj.css(fontCss); + } + }, + setNodeClasses: function (setting, treeNode) { + var aObj = $$(treeNode, consts.id.A, setting), + classes = view.makeNodeClasses(setting, treeNode); + if ('add' in classes && classes.add.length) { + aObj.addClass(classes.add.join(' ')); + } + if ('remove' in classes && classes.remove.length) { + aObj.removeClass(classes.remove.join(' ')); + } + }, + setNodeLineIcos: function (setting, node) { + if (!node) return; + var switchObj = $$(node, consts.id.SWITCH, setting), + ulObj = $$(node, consts.id.UL, setting), + icoObj = $$(node, consts.id.ICON, setting), + ulLine = view.makeUlLineClass(setting, node); + if (ulLine.length == 0) { + ulObj.removeClass(consts.line.LINE); + } else { + ulObj.addClass(ulLine); + } + switchObj.attr("class", view.makeNodeLineClass(setting, node)); + if (data.nodeIsParent(setting, node)) { + switchObj.removeAttr("disabled"); + } else { + switchObj.attr("disabled", "disabled"); + } + icoObj.removeAttr("style"); + icoObj.attr("style", view.makeNodeIcoStyle(setting, node)); + icoObj.attr("class", view.makeNodeIcoClass(setting, node)); + }, + setNodeName: function (setting, node) { + var title = data.nodeTitle(setting, node), + nObj = $$(node, consts.id.SPAN, setting); + nObj.empty(); + if (setting.view.nameIsHTML) { + nObj.html(data.nodeName(setting, node)); + } else { + nObj.text(data.nodeName(setting, node)); + } + if (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle)) { + var aObj = $$(node, consts.id.A, setting); + aObj.attr("title", !title ? "" : title); + } + }, + setNodeTarget: function (setting, node) { + var aObj = $$(node, consts.id.A, setting); + aObj.attr("target", view.makeNodeTarget(node)); + }, + setNodeUrl: function (setting, node) { + var aObj = $$(node, consts.id.A, setting), + url = view.makeNodeUrl(setting, node); + if (url == null || url.length == 0) { + aObj.removeAttr("href"); + } else { + aObj.attr("href", url); + } + }, + switchNode: function (setting, node) { + if (node.open || !tools.canAsync(setting, node)) { + view.expandCollapseNode(setting, node, !node.open); + } else if (setting.async.enable) { + if (!view.asyncNode(setting, node)) { + view.expandCollapseNode(setting, node, !node.open); + return; + } + } else if (node) { + view.expandCollapseNode(setting, node, !node.open); + } + } + }; + // zTree defind + $.fn.zTree = { + consts: _consts, + _z: { + tools: tools, + view: view, + event: event, + data: data + }, + getZTreeObj: function (treeId) { + var o = data.getZTreeTools(treeId); + return o ? o : null; + }, + destroy: function (treeId) { + if (!!treeId && treeId.length > 0) { + view.destroy(data.getSetting(treeId)); + } else { + for (var s in settings) { + view.destroy(settings[s]); + } + } + }, + init: function (obj, zSetting, zNodes) { + var setting = tools.clone(_setting); + $.extend(true, setting, zSetting); + setting.treeId = obj.attr("id"); + setting.treeObj = obj; + setting.treeObj.empty(); + settings[setting.treeId] = setting; + //For some older browser,(e.g., ie6) + if (typeof document.body.style.maxHeight === "undefined") { + setting.view.expandSpeed = ""; + } + data.initRoot(setting); + var root = data.getRoot(setting); + zNodes = zNodes ? tools.clone(tools.isArray(zNodes) ? zNodes : [zNodes]) : []; + if (setting.data.simpleData.enable) { + data.nodeChildren(setting, root, data.transformTozTreeFormat(setting, zNodes)); + } else { + data.nodeChildren(setting, root, zNodes); + } + + data.initCache(setting); + event.unbindTree(setting); + event.bindTree(setting); + event.unbindEvent(setting); + event.bindEvent(setting); + + var zTreeTools = { + setting: setting, + addNodes: function (parentNode, index, newNodes, isSilent) { + if (!parentNode) parentNode = null; + var isParent = data.nodeIsParent(setting, parentNode); + if (parentNode && !isParent && setting.data.keep.leaf) return null; + + var i = parseInt(index, 10); + if (isNaN(i)) { + isSilent = !!newNodes; + newNodes = index; + index = -1; + } else { + index = i; + } + if (!newNodes) return null; + + + var xNewNodes = tools.clone(tools.isArray(newNodes) ? newNodes : [newNodes]); + + function addCallback() { + view.addNodes(setting, parentNode, index, xNewNodes, (isSilent == true)); + } + + if (tools.canAsync(setting, parentNode)) { + view.asyncNode(setting, parentNode, isSilent, addCallback); + } else { + addCallback(); + } + return xNewNodes; + }, + cancelSelectedNode: function (node) { + view.cancelPreSelectedNode(setting, node); + }, + destroy: function () { + view.destroy(setting); + }, + expandAll: function (expandFlag) { + expandFlag = !!expandFlag; + view.expandCollapseSonNode(setting, null, expandFlag, true); + return expandFlag; + }, + expandNode: function (node, expandFlag, sonSign, focus, callbackFlag) { + if (!node || !data.nodeIsParent(setting, node)) return null; + if (expandFlag !== true && expandFlag !== false) { + expandFlag = !node.open; + } + callbackFlag = !!callbackFlag; + + if (callbackFlag && expandFlag && (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false)) { + return null; + } else if (callbackFlag && !expandFlag && (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false)) { + return null; + } + if (expandFlag && node.parentTId) { + view.expandCollapseParentNode(setting, node.getParentNode(), expandFlag, false); + } + if (expandFlag === node.open && !sonSign) { + return null; + } + + data.getRoot(setting).expandTriggerFlag = callbackFlag; + if (!tools.canAsync(setting, node) && sonSign) { + view.expandCollapseSonNode(setting, node, expandFlag, true, showNodeFocus); + } else { + node.open = !expandFlag; + view.switchNode(this.setting, node); + showNodeFocus(); + } + return expandFlag; + + function showNodeFocus() { + var a = $$(node, consts.id.A, setting).get(0); + if (a && focus !== false) { + view.scrollIntoView(setting, a); + } + } + }, + getNodes: function () { + return data.getNodes(setting); + }, + getNodeByParam: function (key, value, parentNode) { + if (!key) return null; + return data.getNodeByParam(setting, parentNode ? data.nodeChildren(setting, parentNode) : data.getNodes(setting), key, value); + }, + getNodeByTId: function (tId) { + return data.getNodeCache(setting, tId); + }, + getNodesByParam: function (key, value, parentNode) { + if (!key) return null; + return data.getNodesByParam(setting, parentNode ? data.nodeChildren(setting, parentNode) : data.getNodes(setting), key, value); + }, + getNodesByParamFuzzy: function (key, value, parentNode) { + if (!key) return null; + return data.getNodesByParamFuzzy(setting, parentNode ? data.nodeChildren(setting, parentNode) : data.getNodes(setting), key, value); + }, + getNodesByFilter: function (filter, isSingle, parentNode, invokeParam) { + isSingle = !!isSingle; + if (!filter || (typeof filter != "function")) return (isSingle ? null : []); + return data.getNodesByFilter(setting, parentNode ? data.nodeChildren(setting, parentNode) : data.getNodes(setting), filter, isSingle, invokeParam); + }, + getNodeIndex: function (node) { + if (!node) return null; + var parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting); + var children = data.nodeChildren(setting, parentNode); + for (var i = 0, l = children.length; i < l; i++) { + if (children[i] == node) return i; + } + return -1; + }, + getSelectedNodes: function () { + var r = [], list = data.getRoot(setting).curSelectedList; + for (var i = 0, l = list.length; i < l; i++) { + r.push(list[i]); + } + return r; + }, + isSelectedNode: function (node) { + return data.isSelectedNode(setting, node); + }, + reAsyncChildNodesPromise: function (parentNode, reloadType, isSilent) { + var promise = new Promise(function (resolve, reject) { + try { + zTreeTools.reAsyncChildNodes(parentNode, reloadType, isSilent, function () { + resolve(parentNode); + }); + } catch (e) { + reject(e); + } + }); + return promise; + }, + reAsyncChildNodes: function (parentNode, reloadType, isSilent, callback) { + if (!this.setting.async.enable) return; + var isRoot = !parentNode; + if (isRoot) { + parentNode = data.getRoot(setting); + } + if (reloadType == "refresh") { + var children = data.nodeChildren(setting, parentNode); + for (var i = 0, l = children ? children.length : 0; i < l; i++) { + data.removeNodeCache(setting, children[i]); + } + data.removeSelectedNode(setting); + data.nodeChildren(setting, parentNode, []); + if (isRoot) { + this.setting.treeObj.empty(); + } else { + var ulObj = $$(parentNode, consts.id.UL, setting); + ulObj.empty(); + } + } + view.asyncNode(this.setting, isRoot ? null : parentNode, !!isSilent, callback); + }, + refresh: function () { + this.setting.treeObj.empty(); + var root = data.getRoot(setting), + nodes = data.nodeChildren(setting, root); + data.initRoot(setting); + data.nodeChildren(setting, root, nodes); + data.initCache(setting); + view.createNodes(setting, 0, data.nodeChildren(setting, root), null, -1); + }, + removeChildNodes: function (node) { + if (!node) return null; + var nodes = data.nodeChildren(setting, node); + view.removeChildNodes(setting, node); + return nodes ? nodes : null; + }, + removeNode: function (node, callbackFlag) { + if (!node) return; + callbackFlag = !!callbackFlag; + if (callbackFlag && tools.apply(setting.callback.beforeRemove, [setting.treeId, node], true) == false) return; + view.removeNode(setting, node); + if (callbackFlag) { + this.setting.treeObj.trigger(consts.event.REMOVE, [setting.treeId, node]); + } + }, + selectNode: function (node, addFlag, isSilent) { + if (!node) return; + if (tools.uCanDo(setting)) { + addFlag = setting.view.selectedMulti && addFlag; + if (node.parentTId) { + view.expandCollapseParentNode(setting, node.getParentNode(), true, false, showNodeFocus); + } else if (!isSilent) { + try { + $$(node, setting).focus().blur(); + } catch (e) { + } + } + view.selectNode(setting, node, addFlag); + } + + function showNodeFocus() { + if (isSilent) { + return; + } + var a = $$(node, setting).get(0); + view.scrollIntoView(setting, a); + } + }, + transformTozTreeNodes: function (simpleNodes) { + return data.transformTozTreeFormat(setting, simpleNodes); + }, + transformToArray: function (nodes) { + return data.transformToArrayFormat(setting, nodes); + }, + updateNode: function (node, checkTypeFlag) { + if (!node) return; + var nObj = $$(node, setting); + if (nObj.get(0) && tools.uCanDo(setting)) { + view.setNodeName(setting, node); + view.setNodeTarget(setting, node); + view.setNodeUrl(setting, node); + view.setNodeLineIcos(setting, node); + view.setNodeFontCss(setting, node); + view.setNodeClasses(setting, node); + } + } + }; + root.treeTools = zTreeTools; + data.setZTreeTools(setting, zTreeTools); + var children = data.nodeChildren(setting, root); + if (children && children.length > 0) { + view.createNodes(setting, 0, children, null, -1); + } else if (setting.async.enable && setting.async.url && setting.async.url !== '') { + view.asyncNode(setting); + } + return zTreeTools; + } + }; + + var zt = $.fn.zTree, + $$ = tools.$, + consts = zt.consts; +})(jQuery); \ No newline at end of file diff --git a/public/self/ztree/js/jquery.ztree.excheck.js b/public/self/ztree/js/jquery.ztree.excheck.js new file mode 100644 index 000000000..44b533672 --- /dev/null +++ b/public/self/ztree/js/jquery.ztree.excheck.js @@ -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(""); + } + }, + //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); \ No newline at end of file diff --git a/public/self/ztree/js/jquery.ztree.exedit.js b/public/self/ztree/js/jquery.ztree.exedit.js new file mode 100644 index 000000000..cfa83baf2 --- /dev/null +++ b/public/self/ztree/js/jquery.ztree.exedit.js @@ -0,0 +1,1207 @@ +/* + * JQuery zTree exedit + * 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 exedit + var _consts = { + event: { + DRAG: "ztree_drag", + DROP: "ztree_drop", + RENAME: "ztree_rename", + DRAGMOVE: "ztree_dragmove" + }, + id: { + EDIT: "_edit", + INPUT: "_input", + REMOVE: "_remove" + }, + move: { + TYPE_INNER: "inner", + TYPE_PREV: "prev", + TYPE_NEXT: "next" + }, + node: { + CURSELECTED_EDIT: "curSelectedNode_Edit", + TMPTARGET_TREE: "tmpTargetzTree", + TMPTARGET_NODE: "tmpTargetNode" + } + }, + //default setting of exedit + _setting = { + edit: { + enable: false, + editNameSelectAll: false, + showRemoveBtn: true, + showRenameBtn: true, + removeTitle: "remove", + renameTitle: "rename", + drag: { + autoExpandTrigger: false, + isCopy: true, + isMove: true, + prev: true, + next: true, + inner: true, + minMoveSize: 5, + borderMax: 10, + borderMin: -5, + maxShowNodeNum: 5, + autoOpenTime: 500 + } + }, + view: { + addHoverDom: null, + removeHoverDom: null + }, + callback: { + beforeDrag: null, + beforeDragOpen: null, + beforeDrop: null, + beforeEditName: null, + beforeRename: null, + onDrag: null, + onDragMove: null, + onDrop: null, + onRename: null + } + }, + //default root of exedit + _initRoot = function (setting) { + var r = data.getRoot(setting), rs = data.getRoots(); + r.curEditNode = null; + r.curEditInput = null; + r.curHoverNode = null; + r.dragFlag = 0; + r.dragNodeShowBefore = []; + r.dragMaskList = new Array(); + rs.showHoverDom = true; + }, + //default cache of exedit + _initCache = function (treeId) { + }, + //default bind event of exedit + _bindEvent = function (setting) { + var o = setting.treeObj; + var c = consts.event; + o.bind(c.RENAME, function (event, treeId, treeNode, isCancel) { + tools.apply(setting.callback.onRename, [event, treeId, treeNode, isCancel]); + }); + + o.bind(c.DRAG, function (event, srcEvent, treeId, treeNodes) { + tools.apply(setting.callback.onDrag, [srcEvent, treeId, treeNodes]); + }); + + o.bind(c.DRAGMOVE, function (event, srcEvent, treeId, treeNodes) { + tools.apply(setting.callback.onDragMove, [srcEvent, treeId, treeNodes]); + }); + + o.bind(c.DROP, function (event, srcEvent, treeId, treeNodes, targetNode, moveType, isCopy) { + tools.apply(setting.callback.onDrop, [srcEvent, treeId, treeNodes, targetNode, moveType, isCopy]); + }); + }, + _unbindEvent = function (setting) { + var o = setting.treeObj; + var c = consts.event; + o.unbind(c.RENAME); + o.unbind(c.DRAG); + o.unbind(c.DRAGMOVE); + o.unbind(c.DROP); + }, + //default event proxy of exedit + _eventProxy = function (e) { + var target = e.target, + setting = data.getSetting(e.data.treeId), + relatedTarget = e.relatedTarget, + tId = "", node = null, + nodeEventType = "", treeEventType = "", + nodeEventCallback = null, treeEventCallback = null, + tmp = null; + + if (tools.eqs(e.type, "mouseover")) { + tmp = tools.getMDom(setting, target, [{tagName: "a", attrName: "treeNode" + consts.id.A}]); + if (tmp) { + tId = tools.getNodeMainDom(tmp).id; + nodeEventType = "hoverOverNode"; + } + } else if (tools.eqs(e.type, "mouseout")) { + tmp = tools.getMDom(setting, relatedTarget, [{tagName: "a", attrName: "treeNode" + consts.id.A}]); + if (!tmp) { + tId = "remove"; + nodeEventType = "hoverOutNode"; + } + } else if (tools.eqs(e.type, "mousedown")) { + tmp = tools.getMDom(setting, target, [{tagName: "a", attrName: "treeNode" + consts.id.A}]); + if (tmp) { + tId = tools.getNodeMainDom(tmp).id; + nodeEventType = "mousedownNode"; + } + } + if (tId.length > 0) { + node = data.getNodeCache(setting, tId); + switch (nodeEventType) { + case "mousedownNode" : + nodeEventCallback = _handler.onMousedownNode; + break; + case "hoverOverNode" : + nodeEventCallback = _handler.onHoverOverNode; + break; + case "hoverOutNode" : + nodeEventCallback = _handler.onHoverOutNode; + break; + } + } + var proxyResult = { + stop: false, + node: node, + nodeEventType: nodeEventType, + nodeEventCallback: nodeEventCallback, + treeEventType: treeEventType, + treeEventCallback: treeEventCallback + }; + return proxyResult + }, + //default init node of exedit + _initNode = function (setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) { + if (!n) return; + n.isHover = false; + n.editNameFlag = false; + }, + //update zTreeObj, add method of edit + _zTreeTools = function (setting, zTreeTools) { + zTreeTools.cancelEditName = function (newName) { + var root = data.getRoot(this.setting); + if (!root.curEditNode) return; + view.cancelCurEditNode(this.setting, newName ? newName : null, true); + } + zTreeTools.copyNode = function (targetNode, node, moveType, isSilent) { + if (!node) return null; + var isParent = data.nodeIsParent(setting, targetNode); + if (targetNode && !isParent && this.setting.data.keep.leaf && moveType === consts.move.TYPE_INNER) return null; + var _this = this, + newNode = tools.clone(node); + if (!targetNode) { + targetNode = null; + moveType = consts.move.TYPE_INNER; + } + if (moveType == consts.move.TYPE_INNER) { + function copyCallback() { + view.addNodes(_this.setting, targetNode, -1, [newNode], isSilent); + } + + if (tools.canAsync(this.setting, targetNode)) { + view.asyncNode(this.setting, targetNode, isSilent, copyCallback); + } else { + copyCallback(); + } + } else { + view.addNodes(this.setting, targetNode.parentNode, -1, [newNode], isSilent); + view.moveNode(this.setting, targetNode, newNode, moveType, false, isSilent); + } + return newNode; + } + zTreeTools.editName = function (node) { + if (!node || !node.tId || node !== data.getNodeCache(this.setting, node.tId)) return; + if (node.parentTId) view.expandCollapseParentNode(this.setting, node.getParentNode(), true); + view.editNode(this.setting, node) + } + zTreeTools.moveNode = function (targetNode, node, moveType, isSilent) { + if (!node) return node; + var isParent = data.nodeIsParent(setting, targetNode); + if (targetNode && !isParent && this.setting.data.keep.leaf && moveType === consts.move.TYPE_INNER) { + return null; + } else if (targetNode && ((node.parentTId == targetNode.tId && moveType == consts.move.TYPE_INNER) || $$(node, this.setting).find("#" + targetNode.tId).length > 0)) { + return null; + } else if (!targetNode) { + targetNode = null; + } + var _this = this; + + function moveCallback() { + view.moveNode(_this.setting, targetNode, node, moveType, false, isSilent); + } + + if (tools.canAsync(this.setting, targetNode) && moveType === consts.move.TYPE_INNER) { + view.asyncNode(this.setting, targetNode, isSilent, moveCallback); + } else { + moveCallback(); + } + return node; + } + zTreeTools.setEditable = function (editable) { + this.setting.edit.enable = editable; + return this.refresh(); + } + }, + //method of operate data + _data = { + setSonNodeLevel: function (setting, parentNode, node) { + if (!node) return; + var children = data.nodeChildren(setting, node); + var oldLevel = node.level; + node.level = (parentNode) ? parentNode.level + 1 : 0; + view.repairNodeLevelClass(setting, node, oldLevel); + + if (!children) return; + for (var i = 0, l = children.length; i < l; i++) { + if (children[i]) data.setSonNodeLevel(setting, node, children[i]); + } + } + }, + //method of event proxy + _event = {}, + //method of event handler + _handler = { + onHoverOverNode: function (event, node) { + var setting = data.getSetting(event.data.treeId), + root = data.getRoot(setting); + if (root.curHoverNode != node) { + _handler.onHoverOutNode(event); + } + root.curHoverNode = node; + view.addHoverDom(setting, node); + }, + onHoverOutNode: function (event, node) { + var setting = data.getSetting(event.data.treeId), + root = data.getRoot(setting); + if (root.curHoverNode && !data.isSelectedNode(setting, root.curHoverNode)) { + view.removeTreeDom(setting, root.curHoverNode); + root.curHoverNode = null; + } + }, + onMousedownNode: function (eventMouseDown, _node) { + var i, l, + setting = data.getSetting(eventMouseDown.data.treeId), + root = data.getRoot(setting), roots = data.getRoots(); + //right click can't drag & drop + if (eventMouseDown.button == 2 || !setting.edit.enable || (!setting.edit.drag.isCopy && !setting.edit.drag.isMove)) return true; + + //input of edit node name can't drag & drop + var target = eventMouseDown.target, + _nodes = data.getRoot(setting).curSelectedList, + nodes = []; + if (!data.isSelectedNode(setting, _node)) { + nodes = [_node]; + } else { + for (i = 0, l = _nodes.length; i < l; i++) { + if (_nodes[i].editNameFlag && tools.eqs(target.tagName, "input") && target.getAttribute("treeNode" + consts.id.INPUT) !== null) { + return true; + } + nodes.push(_nodes[i]); + if (nodes[0].parentTId !== _nodes[i].parentTId) { + nodes = [_node]; + break; + } + } + } + + view.editNodeBlur = true; + view.cancelCurEditNode(setting); + + var doc = $(setting.treeObj.get(0).ownerDocument), + body = $(setting.treeObj.get(0).ownerDocument.body), curNode, tmpArrow, tmpTarget, + isOtherTree = false, + targetSetting = setting, + sourceSetting = setting, + preNode, nextNode, + preTmpTargetNodeId = null, + preTmpMoveType = null, + tmpTargetNodeId = null, + moveType = consts.move.TYPE_INNER, + mouseDownX = eventMouseDown.clientX, + mouseDownY = eventMouseDown.clientY, + startTime = (new Date()).getTime(); + + if (tools.uCanDo(setting)) { + doc.bind("mousemove", _docMouseMove); + } + + function _docMouseMove(event) { + //avoid start drag after click node + if (root.dragFlag == 0 && Math.abs(mouseDownX - event.clientX) < setting.edit.drag.minMoveSize + && Math.abs(mouseDownY - event.clientY) < setting.edit.drag.minMoveSize) { + return true; + } + var i, l, tmpNode, tmpDom, tmpNodes; + body.css("cursor", "pointer"); + + if (root.dragFlag == 0) { + if (tools.apply(setting.callback.beforeDrag, [setting.treeId, nodes], true) == false) { + _docMouseUp(event); + return true; + } + + for (i = 0, l = nodes.length; i < l; i++) { + if (i == 0) { + root.dragNodeShowBefore = []; + } + tmpNode = nodes[i]; + if (data.nodeIsParent(setting, tmpNode) && tmpNode.open) { + view.expandCollapseNode(setting, tmpNode, !tmpNode.open); + root.dragNodeShowBefore[tmpNode.tId] = true; + } else { + root.dragNodeShowBefore[tmpNode.tId] = false; + } + } + + root.dragFlag = 1; + roots.showHoverDom = false; + tools.showIfameMask(setting, true); + + //sort + var isOrder = true, lastIndex = -1; + if (nodes.length > 1) { + var pNodes = nodes[0].parentTId ? data.nodeChildren(setting, nodes[0].getParentNode()) : data.getNodes(setting); + tmpNodes = []; + for (i = 0, l = pNodes.length; i < l; i++) { + if (root.dragNodeShowBefore[pNodes[i].tId] !== undefined) { + if (isOrder && lastIndex > -1 && (lastIndex + 1) !== i) { + isOrder = false; + } + tmpNodes.push(pNodes[i]); + lastIndex = i; + } + if (nodes.length === tmpNodes.length) { + nodes = tmpNodes; + break; + } + } + } + if (isOrder) { + preNode = nodes[0].getPreNode(); + nextNode = nodes[nodes.length - 1].getNextNode(); + } + + //set node in selected + curNode = $$("
        ", setting); + for (i = 0, l = nodes.length; i < l; i++) { + tmpNode = nodes[i]; + tmpNode.editNameFlag = false; + view.selectNode(setting, tmpNode, i > 0); + view.removeTreeDom(setting, tmpNode); + + if (i > setting.edit.drag.maxShowNodeNum - 1) { + continue; + } + + tmpDom = $$("
      • ", setting); + tmpDom.append($$(tmpNode, consts.id.A, setting).clone()); + tmpDom.css("padding", "0"); + tmpDom.children("#" + tmpNode.tId + consts.id.A).removeClass(consts.node.CURSELECTED); + curNode.append(tmpDom); + if (i == setting.edit.drag.maxShowNodeNum - 1) { + tmpDom = $$("
      • ...
      • ", setting); + curNode.append(tmpDom); + } + } + curNode.attr("id", nodes[0].tId + consts.id.UL + "_tmp"); + curNode.addClass(setting.treeObj.attr("class")); + curNode.appendTo(body); + + tmpArrow = $$("", setting); + tmpArrow.attr("id", "zTreeMove_arrow_tmp"); + tmpArrow.appendTo(body); + + setting.treeObj.trigger(consts.event.DRAG, [event, setting.treeId, nodes]); + } + + if (root.dragFlag == 1) { + if (tmpTarget && tmpArrow.attr("id") == event.target.id && tmpTargetNodeId && (event.clientX + doc.scrollLeft() + 2) > ($("#" + tmpTargetNodeId + consts.id.A, tmpTarget).offset().left)) { + var xT = $("#" + tmpTargetNodeId + consts.id.A, tmpTarget); + event.target = (xT.length > 0) ? xT.get(0) : event.target; + } else if (tmpTarget) { + tmpTarget.removeClass(consts.node.TMPTARGET_TREE); + if (tmpTargetNodeId) $("#" + tmpTargetNodeId + consts.id.A, tmpTarget).removeClass(consts.node.TMPTARGET_NODE + "_" + consts.move.TYPE_PREV) + .removeClass(consts.node.TMPTARGET_NODE + "_" + _consts.move.TYPE_NEXT).removeClass(consts.node.TMPTARGET_NODE + "_" + _consts.move.TYPE_INNER); + } + tmpTarget = null; + tmpTargetNodeId = null; + + //judge drag & drop in multi ztree + isOtherTree = false; + targetSetting = setting; + var settings = data.getSettings(); + for (var s in settings) { + if (settings[s].treeId && settings[s].edit.enable && settings[s].treeId != setting.treeId + && (event.target.id == settings[s].treeId || $(event.target).parents("#" + settings[s].treeId).length > 0)) { + isOtherTree = true; + targetSetting = settings[s]; + } + } + + var docScrollTop = doc.scrollTop(), + docScrollLeft = doc.scrollLeft(), + treeOffset = targetSetting.treeObj.offset(), + scrollHeight = targetSetting.treeObj.get(0).scrollHeight, + scrollWidth = targetSetting.treeObj.get(0).scrollWidth, + dTop = (event.clientY + docScrollTop - treeOffset.top), + dBottom = (targetSetting.treeObj.height() + treeOffset.top - event.clientY - docScrollTop), + dLeft = (event.clientX + docScrollLeft - treeOffset.left), + dRight = (targetSetting.treeObj.width() + treeOffset.left - event.clientX - docScrollLeft), + isTop = (dTop < setting.edit.drag.borderMax && dTop > setting.edit.drag.borderMin), + isBottom = (dBottom < setting.edit.drag.borderMax && dBottom > setting.edit.drag.borderMin), + isLeft = (dLeft < setting.edit.drag.borderMax && dLeft > setting.edit.drag.borderMin), + isRight = (dRight < setting.edit.drag.borderMax && dRight > setting.edit.drag.borderMin), + isTreeInner = dTop > setting.edit.drag.borderMin && dBottom > setting.edit.drag.borderMin && dLeft > setting.edit.drag.borderMin && dRight > setting.edit.drag.borderMin, + isTreeTop = (isTop && targetSetting.treeObj.scrollTop() <= 0), + isTreeBottom = (isBottom && (targetSetting.treeObj.scrollTop() + targetSetting.treeObj.height() + 10) >= scrollHeight), + isTreeLeft = (isLeft && targetSetting.treeObj.scrollLeft() <= 0), + isTreeRight = (isRight && (targetSetting.treeObj.scrollLeft() + targetSetting.treeObj.width() + 10) >= scrollWidth); + + if (event.target && tools.isChildOrSelf(event.target, targetSetting.treeId)) { + //get node
      • dom + var targetObj = event.target; + while (targetObj && targetObj.tagName && !tools.eqs(targetObj.tagName, "li") && targetObj.id != targetSetting.treeId) { + targetObj = targetObj.parentNode; + } + + var canMove = true; + //don't move to self or children of self + for (i = 0, l = nodes.length; i < l; i++) { + tmpNode = nodes[i]; + if (targetObj.id === tmpNode.tId) { + canMove = false; + break; + } else if ($$(tmpNode, setting).find("#" + targetObj.id).length > 0) { + canMove = false; + break; + } + } + if (canMove && event.target && tools.isChildOrSelf(event.target, targetObj.id + consts.id.A)) { + tmpTarget = $(targetObj); + tmpTargetNodeId = targetObj.id; + } + } + + //the mouse must be in zTree + tmpNode = nodes[0]; + if (isTreeInner && tools.isChildOrSelf(event.target, targetSetting.treeId)) { + //judge mouse move in root of ztree + if (!tmpTarget && (event.target.id == targetSetting.treeId || isTreeTop || isTreeBottom || isTreeLeft || isTreeRight) && (isOtherTree || (!isOtherTree && tmpNode.parentTId))) { + tmpTarget = targetSetting.treeObj; + } + //auto scroll top + if (isTop) { + targetSetting.treeObj.scrollTop(targetSetting.treeObj.scrollTop() - 10); + } else if (isBottom) { + targetSetting.treeObj.scrollTop(targetSetting.treeObj.scrollTop() + 10); + } + if (isLeft) { + targetSetting.treeObj.scrollLeft(targetSetting.treeObj.scrollLeft() - 10); + } else if (isRight) { + targetSetting.treeObj.scrollLeft(targetSetting.treeObj.scrollLeft() + 10); + } + //auto scroll left + if (tmpTarget && tmpTarget != targetSetting.treeObj && tmpTarget.offset().left < targetSetting.treeObj.offset().left) { + targetSetting.treeObj.scrollLeft(targetSetting.treeObj.scrollLeft() + tmpTarget.offset().left - targetSetting.treeObj.offset().left); + } + } + + curNode.css({ + "top": (event.clientY + docScrollTop + 3) + "px", + "left": (event.clientX + docScrollLeft + 3) + "px" + }); + + var dX = 0; + var dY = 0; + if (tmpTarget && tmpTarget.attr("id") != targetSetting.treeId) { + var tmpTargetNode = tmpTargetNodeId == null ? null : data.getNodeCache(targetSetting, tmpTargetNodeId), + isCopy = ((event.ctrlKey || event.metaKey) && setting.edit.drag.isMove && setting.edit.drag.isCopy) || (!setting.edit.drag.isMove && setting.edit.drag.isCopy), + isPrev = !!(preNode && tmpTargetNodeId === preNode.tId), + isNext = !!(nextNode && tmpTargetNodeId === nextNode.tId), + isInner = (tmpNode.parentTId && tmpNode.parentTId == tmpTargetNodeId), + canPrev = (isCopy || !isNext) && tools.apply(targetSetting.edit.drag.prev, [targetSetting.treeId, nodes, tmpTargetNode], !!targetSetting.edit.drag.prev), + canNext = (isCopy || !isPrev) && tools.apply(targetSetting.edit.drag.next, [targetSetting.treeId, nodes, tmpTargetNode], !!targetSetting.edit.drag.next), + canInner = (isCopy || !isInner) && !(targetSetting.data.keep.leaf && !data.nodeIsParent(setting, tmpTargetNode)) && tools.apply(targetSetting.edit.drag.inner, [targetSetting.treeId, nodes, tmpTargetNode], !!targetSetting.edit.drag.inner); + + function clearMove() { + tmpTarget = null; + tmpTargetNodeId = ""; + moveType = consts.move.TYPE_INNER; + tmpArrow.css({ + "display": "none" + }); + if (window.zTreeMoveTimer) { + clearTimeout(window.zTreeMoveTimer); + window.zTreeMoveTargetNodeTId = null + } + } + + if (!canPrev && !canNext && !canInner) { + clearMove(); + } else { + var tmpTargetA = $("#" + tmpTargetNodeId + consts.id.A, tmpTarget), + tmpNextA = tmpTargetNode.isLastNode ? null : $("#" + tmpTargetNode.getNextNode().tId + consts.id.A, tmpTarget.next()), + tmpTop = tmpTargetA.offset().top, + tmpLeft = tmpTargetA.offset().left, + prevPercent = canPrev ? (canInner ? 0.25 : (canNext ? 0.5 : 1)) : -1, + nextPercent = canNext ? (canInner ? 0.75 : (canPrev ? 0.5 : 0)) : -1, + dY_percent = (event.clientY + docScrollTop - tmpTop) / tmpTargetA.height(); + + if ((prevPercent == 1 || dY_percent <= prevPercent && dY_percent >= -.2) && canPrev) { + dX = 1 - tmpArrow.width(); + dY = tmpTop - tmpArrow.height() / 2; + moveType = consts.move.TYPE_PREV; + } else if ((nextPercent == 0 || dY_percent >= nextPercent && dY_percent <= 1.2) && canNext) { + dX = 1 - tmpArrow.width(); + dY = (tmpNextA == null || (data.nodeIsParent(setting, tmpTargetNode) && tmpTargetNode.open)) ? (tmpTop + tmpTargetA.height() - tmpArrow.height() / 2) : (tmpNextA.offset().top - tmpArrow.height() / 2); + moveType = consts.move.TYPE_NEXT; + } else if (canInner) { + dX = 5 - tmpArrow.width(); + dY = tmpTop; + moveType = consts.move.TYPE_INNER; + } else { + clearMove(); + } + + if (tmpTarget) { + tmpArrow.css({ + "display": "block", + "top": dY + "px", + "left": (tmpLeft + dX) + "px" + }); + tmpTargetA.addClass(consts.node.TMPTARGET_NODE + "_" + moveType); + + if (preTmpTargetNodeId != tmpTargetNodeId || preTmpMoveType != moveType) { + startTime = (new Date()).getTime(); + } + if (tmpTargetNode && data.nodeIsParent(setting, tmpTargetNode) && moveType == consts.move.TYPE_INNER) { + var startTimer = true; + if (window.zTreeMoveTimer && window.zTreeMoveTargetNodeTId !== tmpTargetNode.tId) { + clearTimeout(window.zTreeMoveTimer); + window.zTreeMoveTargetNodeTId = null; + } else if (window.zTreeMoveTimer && window.zTreeMoveTargetNodeTId === tmpTargetNode.tId) { + startTimer = false; + } + if (startTimer) { + window.zTreeMoveTimer = setTimeout(function () { + if (moveType != consts.move.TYPE_INNER) return; + if (tmpTargetNode && data.nodeIsParent(setting, tmpTargetNode) && !tmpTargetNode.open && (new Date()).getTime() - startTime > targetSetting.edit.drag.autoOpenTime + && tools.apply(targetSetting.callback.beforeDragOpen, [targetSetting.treeId, tmpTargetNode], true)) { + view.switchNode(targetSetting, tmpTargetNode); + if (targetSetting.edit.drag.autoExpandTrigger) { + targetSetting.treeObj.trigger(consts.event.EXPAND, [targetSetting.treeId, tmpTargetNode]); + } + } + }, targetSetting.edit.drag.autoOpenTime + 50); + window.zTreeMoveTargetNodeTId = tmpTargetNode.tId; + } + } + } + } + } else { + moveType = consts.move.TYPE_INNER; + if (tmpTarget && tools.apply(targetSetting.edit.drag.inner, [targetSetting.treeId, nodes, null], !!targetSetting.edit.drag.inner)) { + tmpTarget.addClass(consts.node.TMPTARGET_TREE); + } else { + tmpTarget = null; + } + tmpArrow.css({ + "display": "none" + }); + if (window.zTreeMoveTimer) { + clearTimeout(window.zTreeMoveTimer); + window.zTreeMoveTargetNodeTId = null; + } + } + preTmpTargetNodeId = tmpTargetNodeId; + preTmpMoveType = moveType; + + setting.treeObj.trigger(consts.event.DRAGMOVE, [event, setting.treeId, nodes]); + } + return false; + } + + doc.bind("mouseup", _docMouseUp); + + function _docMouseUp(event) { + if (window.zTreeMoveTimer) { + clearTimeout(window.zTreeMoveTimer); + window.zTreeMoveTargetNodeTId = null; + } + preTmpTargetNodeId = null; + preTmpMoveType = null; + doc.unbind("mousemove", _docMouseMove); + doc.unbind("mouseup", _docMouseUp); + doc.unbind("selectstart", _docSelect); + body.css("cursor", ""); + if (tmpTarget) { + tmpTarget.removeClass(consts.node.TMPTARGET_TREE); + if (tmpTargetNodeId) $("#" + tmpTargetNodeId + consts.id.A, tmpTarget).removeClass(consts.node.TMPTARGET_NODE + "_" + consts.move.TYPE_PREV) + .removeClass(consts.node.TMPTARGET_NODE + "_" + _consts.move.TYPE_NEXT).removeClass(consts.node.TMPTARGET_NODE + "_" + _consts.move.TYPE_INNER); + } + tools.showIfameMask(setting, false); + + roots.showHoverDom = true; + if (root.dragFlag == 0) return; + root.dragFlag = 0; + + var i, l, tmpNode; + for (i = 0, l = nodes.length; i < l; i++) { + tmpNode = nodes[i]; + if (data.nodeIsParent(setting, tmpNode) && root.dragNodeShowBefore[tmpNode.tId] && !tmpNode.open) { + view.expandCollapseNode(setting, tmpNode, !tmpNode.open); + delete root.dragNodeShowBefore[tmpNode.tId]; + } + } + + if (curNode) curNode.remove(); + if (tmpArrow) tmpArrow.remove(); + + var isCopy = ((event.ctrlKey || event.metaKey) && setting.edit.drag.isMove && setting.edit.drag.isCopy) || (!setting.edit.drag.isMove && setting.edit.drag.isCopy); + if (!isCopy && tmpTarget && tmpTargetNodeId && nodes[0].parentTId && tmpTargetNodeId == nodes[0].parentTId && moveType == consts.move.TYPE_INNER) { + tmpTarget = null; + } + if (tmpTarget) { + var dragTargetNode = tmpTargetNodeId == null ? null : data.getNodeCache(targetSetting, tmpTargetNodeId); + if (tools.apply(setting.callback.beforeDrop, [targetSetting.treeId, nodes, dragTargetNode, moveType, isCopy], true) == false) { + view.selectNodes(sourceSetting, nodes); + return; + } + var newNodes = isCopy ? tools.clone(nodes) : nodes; + + function dropCallback() { + if (isOtherTree) { + if (!isCopy) { + for (var i = 0, l = nodes.length; i < l; i++) { + view.removeNode(setting, nodes[i]); + } + } + if (moveType == consts.move.TYPE_INNER) { + view.addNodes(targetSetting, dragTargetNode, -1, newNodes); + } else { + view.addNodes(targetSetting, dragTargetNode.getParentNode(), moveType == consts.move.TYPE_PREV ? dragTargetNode.getIndex() : dragTargetNode.getIndex() + 1, newNodes); + } + } else { + if (isCopy && moveType == consts.move.TYPE_INNER) { + view.addNodes(targetSetting, dragTargetNode, -1, newNodes); + } else if (isCopy) { + view.addNodes(targetSetting, dragTargetNode.getParentNode(), moveType == consts.move.TYPE_PREV ? dragTargetNode.getIndex() : dragTargetNode.getIndex() + 1, newNodes); + } else { + if (moveType != consts.move.TYPE_NEXT) { + for (i = 0, l = newNodes.length; i < l; i++) { + view.moveNode(targetSetting, dragTargetNode, newNodes[i], moveType, false); + } + } else { + for (i = -1, l = newNodes.length - 1; i < l; l--) { + view.moveNode(targetSetting, dragTargetNode, newNodes[l], moveType, false); + } + } + } + } + view.selectNodes(targetSetting, newNodes); + + var a = $$(newNodes[0], setting).get(0); + view.scrollIntoView(setting, a); + + setting.treeObj.trigger(consts.event.DROP, [event, targetSetting.treeId, newNodes, dragTargetNode, moveType, isCopy]); + } + + if (moveType == consts.move.TYPE_INNER && tools.canAsync(targetSetting, dragTargetNode)) { + view.asyncNode(targetSetting, dragTargetNode, false, dropCallback); + } else { + dropCallback(); + } + + } else { + view.selectNodes(sourceSetting, nodes); + setting.treeObj.trigger(consts.event.DROP, [event, setting.treeId, nodes, null, null, null]); + } + } + + doc.bind("selectstart", _docSelect); + + function _docSelect() { + return false; + } + + // 2018-03-30 FireFox has fixed this issue. + //Avoid FireFox's Bug + //If zTree Div CSS set 'overflow', so drag node outside of zTree, and event.target is error. + // if(eventMouseDown.preventDefault) { + // eventMouseDown.preventDefault(); + // } + return true; + } + }, + //method of tools for zTree + _tools = { + getAbs: function (obj) { + var oRect = obj.getBoundingClientRect(), + scrollTop = document.body.scrollTop + document.documentElement.scrollTop, + scrollLeft = document.body.scrollLeft + document.documentElement.scrollLeft; + return [oRect.left + scrollLeft, oRect.top + scrollTop]; + }, + inputFocus: function (inputObj) { + if (inputObj.get(0)) { + inputObj.focus(); + tools.setCursorPosition(inputObj.get(0), inputObj.val().length); + } + }, + inputSelect: function (inputObj) { + if (inputObj.get(0)) { + inputObj.focus(); + inputObj.select(); + } + }, + setCursorPosition: function (obj, pos) { + if (obj.setSelectionRange) { + obj.focus(); + obj.setSelectionRange(pos, pos); + } else if (obj.createTextRange) { + var range = obj.createTextRange(); + range.collapse(true); + range.moveEnd('character', pos); + range.moveStart('character', pos); + range.select(); + } + }, + showIfameMask: function (setting, showSign) { + var root = data.getRoot(setting); + //clear full mask + while (root.dragMaskList.length > 0) { + root.dragMaskList[0].remove(); + root.dragMaskList.shift(); + } + if (showSign) { + //show mask + var iframeList = $$("iframe", setting); + for (var i = 0, l = iframeList.length; i < l; i++) { + var obj = iframeList.get(i), + r = tools.getAbs(obj), + dragMask = $$("
        ", setting); + dragMask.appendTo($$("body", setting)); + root.dragMaskList.push(dragMask); + } + } + } + }, + //method of operate ztree dom + _view = { + addEditBtn: function (setting, node) { + if (node.editNameFlag || $$(node, consts.id.EDIT, setting).length > 0) { + return; + } + if (!tools.apply(setting.edit.showRenameBtn, [setting.treeId, node], setting.edit.showRenameBtn)) { + return; + } + var aObj = $$(node, consts.id.A, setting), + editStr = ""; + aObj.append(editStr); + + $$(node, consts.id.EDIT, setting).bind('click', + function () { + if (!tools.uCanDo(setting) || tools.apply(setting.callback.beforeEditName, [setting.treeId, node], true) == false) return false; + view.editNode(setting, node); + return false; + } + ).show(); + }, + addRemoveBtn: function (setting, node) { + if (node.editNameFlag || $$(node, consts.id.REMOVE, setting).length > 0) { + return; + } + if (!tools.apply(setting.edit.showRemoveBtn, [setting.treeId, node], setting.edit.showRemoveBtn)) { + return; + } + var aObj = $$(node, consts.id.A, setting), + removeStr = ""; + aObj.append(removeStr); + + $$(node, consts.id.REMOVE, setting).bind('click', + function () { + if (!tools.uCanDo(setting) || tools.apply(setting.callback.beforeRemove, [setting.treeId, node], true) == false) return false; + view.removeNode(setting, node); + setting.treeObj.trigger(consts.event.REMOVE, [setting.treeId, node]); + return false; + } + ).bind('mousedown', + function (eventMouseDown) { + return true; + } + ).show(); + }, + addHoverDom: function (setting, node) { + if (data.getRoots().showHoverDom) { + node.isHover = true; + if (setting.edit.enable) { + view.addEditBtn(setting, node); + view.addRemoveBtn(setting, node); + } + tools.apply(setting.view.addHoverDom, [setting.treeId, node]); + } + }, + cancelCurEditNode: function (setting, forceName, isCancel) { + var root = data.getRoot(setting), + node = root.curEditNode; + + if (node) { + var inputObj = root.curEditInput, + newName = forceName ? forceName : (isCancel ? data.nodeName(setting, node) : inputObj.val()); + if (tools.apply(setting.callback.beforeRename, [setting.treeId, node, newName, isCancel], true) === false) { + return false; + } + data.nodeName(setting, node, newName); + var aObj = $$(node, consts.id.A, setting); + aObj.removeClass(consts.node.CURSELECTED_EDIT); + inputObj.unbind(); + view.setNodeName(setting, node); + node.editNameFlag = false; + root.curEditNode = null; + root.curEditInput = null; + view.selectNode(setting, node, false); + setting.treeObj.trigger(consts.event.RENAME, [setting.treeId, node, isCancel]); + } + root.noSelection = true; + return true; + }, + editNode: function (setting, node) { + var root = data.getRoot(setting); + view.editNodeBlur = false; + if (data.isSelectedNode(setting, node) && root.curEditNode == node && node.editNameFlag) { + setTimeout(function () { + tools.inputFocus(root.curEditInput); + }, 0); + return; + } + node.editNameFlag = true; + view.removeTreeDom(setting, node); + view.cancelCurEditNode(setting); + view.selectNode(setting, node, false); + $$(node, consts.id.SPAN, setting).html(""); + var inputObj = $$(node, consts.id.INPUT, setting); + inputObj.attr("value", data.nodeName(setting, node)); + if (setting.edit.editNameSelectAll) { + tools.inputSelect(inputObj); + } else { + tools.inputFocus(inputObj); + } + + inputObj.bind('blur', function (event) { + if (!view.editNodeBlur) { + view.cancelCurEditNode(setting); + } + }).bind('keydown', function (event) { + if (event.keyCode == "13") { + view.editNodeBlur = true; + view.cancelCurEditNode(setting); + } else if (event.keyCode == "27") { + view.cancelCurEditNode(setting, null, true); + } + }).bind('click', function (event) { + return false; + }).bind('dblclick', function (event) { + return false; + }); + + $$(node, consts.id.A, setting).addClass(consts.node.CURSELECTED_EDIT); + root.curEditInput = inputObj; + root.noSelection = false; + root.curEditNode = node; + }, + moveNode: function (setting, targetNode, node, moveType, animateFlag, isSilent) { + var root = data.getRoot(setting); + if (targetNode == node) return; + if (setting.data.keep.leaf && targetNode && !data.nodeIsParent(setting, targetNode) && moveType == consts.move.TYPE_INNER) return; + var oldParentNode = (node.parentTId ? node.getParentNode() : root), + targetNodeIsRoot = (targetNode === null || targetNode == root); + if (targetNodeIsRoot && targetNode === null) targetNode = root; + if (targetNodeIsRoot) moveType = consts.move.TYPE_INNER; + var targetParentNode = (targetNode.parentTId ? targetNode.getParentNode() : root); + + if (moveType != consts.move.TYPE_PREV && moveType != consts.move.TYPE_NEXT) { + moveType = consts.move.TYPE_INNER; + } + + if (moveType == consts.move.TYPE_INNER) { + if (targetNodeIsRoot) { + //parentTId of root node is null + node.parentTId = null; + } else { + if (!data.nodeIsParent(setting, targetNode)) { + data.nodeIsParent(setting, targetNode, true); + targetNode.open = !!targetNode.open; + view.setNodeLineIcos(setting, targetNode); + } + node.parentTId = targetNode.tId; + } + } + + //move node Dom + var targetObj, target_ulObj; + if (targetNodeIsRoot) { + targetObj = setting.treeObj; + target_ulObj = targetObj; + } else { + if (!isSilent && moveType == consts.move.TYPE_INNER) { + view.expandCollapseNode(setting, targetNode, true, false); + } else if (!isSilent) { + view.expandCollapseNode(setting, targetNode.getParentNode(), true, false); + } + targetObj = $$(targetNode, setting); + target_ulObj = $$(targetNode, consts.id.UL, setting); + if (!!targetObj.get(0) && !target_ulObj.get(0)) { + var ulstr = []; + view.makeUlHtml(setting, targetNode, ulstr, ''); + targetObj.append(ulstr.join('')); + } + target_ulObj = $$(targetNode, consts.id.UL, setting); + } + var nodeDom = $$(node, setting); + if (!nodeDom.get(0)) { + nodeDom = view.appendNodes(setting, node.level, [node], null, -1, false, true).join(''); + } else if (!targetObj.get(0)) { + nodeDom.remove(); + } + if (target_ulObj.get(0) && moveType == consts.move.TYPE_INNER) { + target_ulObj.append(nodeDom); + } else if (targetObj.get(0) && moveType == consts.move.TYPE_PREV) { + targetObj.before(nodeDom); + } else if (targetObj.get(0) && moveType == consts.move.TYPE_NEXT) { + targetObj.after(nodeDom); + } + + //repair the data after move + var i, l, + tmpSrcIndex = -1, + tmpTargetIndex = 0, + oldNeighbor = null, + newNeighbor = null, + oldLevel = node.level; + var oldChildren = data.nodeChildren(setting, oldParentNode); + var targetParentChildren = data.nodeChildren(setting, targetParentNode); + var targetChildren = data.nodeChildren(setting, targetNode); + if (node.isFirstNode) { + tmpSrcIndex = 0; + if (oldChildren.length > 1) { + oldNeighbor = oldChildren[1]; + oldNeighbor.isFirstNode = true; + } + } else if (node.isLastNode) { + tmpSrcIndex = oldChildren.length - 1; + oldNeighbor = oldChildren[tmpSrcIndex - 1]; + oldNeighbor.isLastNode = true; + } else { + for (i = 0, l = oldChildren.length; i < l; i++) { + if (oldChildren[i].tId == node.tId) { + tmpSrcIndex = i; + break; + } + } + } + if (tmpSrcIndex >= 0) { + oldChildren.splice(tmpSrcIndex, 1); + } + if (moveType != consts.move.TYPE_INNER) { + for (i = 0, l = targetParentChildren.length; i < l; i++) { + if (targetParentChildren[i].tId == targetNode.tId) tmpTargetIndex = i; + } + } + if (moveType == consts.move.TYPE_INNER) { + if (!targetChildren) { + targetChildren = data.nodeChildren(setting, targetNode, []); + } + if (targetChildren.length > 0) { + newNeighbor = targetChildren[targetChildren.length - 1]; + newNeighbor.isLastNode = false; + } + targetChildren.splice(targetChildren.length, 0, node); + node.isLastNode = true; + node.isFirstNode = (targetChildren.length == 1); + } else if (targetNode.isFirstNode && moveType == consts.move.TYPE_PREV) { + targetParentChildren.splice(tmpTargetIndex, 0, node); + newNeighbor = targetNode; + newNeighbor.isFirstNode = false; + node.parentTId = targetNode.parentTId; + node.isFirstNode = true; + node.isLastNode = false; + + } else if (targetNode.isLastNode && moveType == consts.move.TYPE_NEXT) { + targetParentChildren.splice(tmpTargetIndex + 1, 0, node); + newNeighbor = targetNode; + newNeighbor.isLastNode = false; + node.parentTId = targetNode.parentTId; + node.isFirstNode = false; + node.isLastNode = true; + + } else { + if (moveType == consts.move.TYPE_PREV) { + targetParentChildren.splice(tmpTargetIndex, 0, node); + } else { + targetParentChildren.splice(tmpTargetIndex + 1, 0, node); + } + node.parentTId = targetNode.parentTId; + node.isFirstNode = false; + node.isLastNode = false; + } + data.fixPIdKeyValue(setting, node); + data.setSonNodeLevel(setting, node.getParentNode(), node); + + //repair node what been moved + view.setNodeLineIcos(setting, node); + view.repairNodeLevelClass(setting, node, oldLevel); + + //repair node's old parentNode dom + if (!setting.data.keep.parent && oldChildren.length < 1) { + //old parentNode has no child nodes + data.nodeIsParent(setting, oldParentNode, false); + oldParentNode.open = false; + var tmp_ulObj = $$(oldParentNode, consts.id.UL, setting), + tmp_switchObj = $$(oldParentNode, consts.id.SWITCH, setting), + tmp_icoObj = $$(oldParentNode, consts.id.ICON, setting); + view.replaceSwitchClass(oldParentNode, tmp_switchObj, consts.folder.DOCU); + view.replaceIcoClass(oldParentNode, tmp_icoObj, consts.folder.DOCU); + tmp_ulObj.css("display", "none"); + + } else if (oldNeighbor) { + //old neighbor node + view.setNodeLineIcos(setting, oldNeighbor); + } + + //new neighbor node + if (newNeighbor) { + view.setNodeLineIcos(setting, newNeighbor); + } + + //repair checkbox / radio + if (!!setting.check && setting.check.enable && view.repairChkClass) { + view.repairChkClass(setting, oldParentNode); + view.repairParentChkClassWithSelf(setting, oldParentNode); + if (oldParentNode != node.parent) + view.repairParentChkClassWithSelf(setting, node); + } + + //expand parents after move + if (!isSilent) { + view.expandCollapseParentNode(setting, node.getParentNode(), true, animateFlag); + } + }, + removeEditBtn: function (setting, node) { + $$(node, consts.id.EDIT, setting).unbind().remove(); + }, + removeRemoveBtn: function (setting, node) { + $$(node, consts.id.REMOVE, setting).unbind().remove(); + }, + removeTreeDom: function (setting, node) { + node.isHover = false; + view.removeEditBtn(setting, node); + view.removeRemoveBtn(setting, node); + tools.apply(setting.view.removeHoverDom, [setting.treeId, node]); + }, + repairNodeLevelClass: function (setting, node, oldLevel) { + if (oldLevel === node.level) return; + var liObj = $$(node, setting), + aObj = $$(node, consts.id.A, setting), + ulObj = $$(node, consts.id.UL, setting), + oldClass = consts.className.LEVEL + oldLevel, + newClass = consts.className.LEVEL + node.level; + liObj.removeClass(oldClass); + liObj.addClass(newClass); + aObj.removeClass(oldClass); + aObj.addClass(newClass); + ulObj.removeClass(oldClass); + ulObj.addClass(newClass); + }, + selectNodes: function (setting, nodes) { + for (var i = 0, l = nodes.length; i < l; i++) { + view.selectNode(setting, nodes[i], i > 0); + } + } + }, + + _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.exSetting(_setting); + data.addInitBind(_bindEvent); + data.addInitUnBind(_unbindEvent); + data.addInitCache(_initCache); + data.addInitNode(_initNode); + data.addInitProxy(_eventProxy); + data.addInitRoot(_initRoot); + data.addZTreeTools(_zTreeTools); + + var _cancelPreSelectedNode = view.cancelPreSelectedNode; + view.cancelPreSelectedNode = function (setting, node) { + var list = data.getRoot(setting).curSelectedList; + for (var i = 0, j = list.length; i < j; i++) { + if (!node || node === list[i]) { + view.removeTreeDom(setting, list[i]); + if (node) break; + } + } + if (_cancelPreSelectedNode) _cancelPreSelectedNode.apply(view, arguments); + } + + var _createNodes = view.createNodes; + view.createNodes = function (setting, level, nodes, parentNode, index) { + if (_createNodes) { + _createNodes.apply(view, arguments); + } + if (!nodes) return; + if (view.repairParentChkClassWithSelf) { + view.repairParentChkClassWithSelf(setting, parentNode); + } + } + + var _makeNodeUrl = view.makeNodeUrl; + view.makeNodeUrl = function (setting, node) { + return setting.edit.enable ? null : (_makeNodeUrl.apply(view, arguments)); + } + + var _removeNode = view.removeNode; + view.removeNode = function (setting, node) { + var root = data.getRoot(setting); + if (root.curEditNode === node) root.curEditNode = null; + if (_removeNode) { + _removeNode.apply(view, arguments); + } + } + + var _selectNode = view.selectNode; + view.selectNode = function (setting, node, addFlag) { + var root = data.getRoot(setting); + if (data.isSelectedNode(setting, node) && root.curEditNode == node && node.editNameFlag) { + return false; + } + if (_selectNode) _selectNode.apply(view, arguments); + view.addHoverDom(setting, node); + return true; + } + + var _uCanDo = tools.uCanDo; + tools.uCanDo = function (setting, e) { + var root = data.getRoot(setting); + if (e && (tools.eqs(e.type, "mouseover") || tools.eqs(e.type, "mouseout") || tools.eqs(e.type, "mousedown") || tools.eqs(e.type, "mouseup"))) { + return true; + } + if (root.curEditNode) { + view.editNodeBlur = false; + root.curEditInput.focus(); + } + return (!root.curEditNode) && (_uCanDo ? _uCanDo.apply(view, arguments) : true); + } +})(jQuery); \ No newline at end of file diff --git a/public/self/ztree/js/jquery.ztree.exhide.js b/public/self/ztree/js/jquery.ztree.exhide.js new file mode 100644 index 000000000..8cfe174bb --- /dev/null +++ b/public/self/ztree/js/jquery.ztree.exhide.js @@ -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("
      • "); + }, + 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); \ No newline at end of file diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index e6c572e73..3d9452f93 100755 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -570,6 +570,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/query_user_last_month", operationReq, repo_ext.QueryUserStaticLastMonth) m.Get("/query_user_yesterday", operationReq, repo_ext.QueryUserStaticYesterday) m.Get("/query_user_all", operationReq, repo_ext.QueryUserStaticAll) + m.Get("/query_user_activity", operationReq, repo_ext.QueryUserActivity) //cloudbrain board m.Group("/cloudbrainboard", func() { m.Get("/downloadAll", repo.DownloadCloudBrainBoard) @@ -921,7 +922,20 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/stop_version", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo_ext.CloudBrainStop) }) }) + m.Group("/inference-job", func() { + m.Group("/:jobid", func() { + m.Get("", repo.GetCloudBrainInferenceJob) + m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo.DelCloudBrainJob) + m.Get("/result_list", repo.InferencJobResultList) + }) + }) }, 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("/notebook", func() { //m.Get("/:jobid", repo.GetModelArtsNotebook) @@ -1056,6 +1070,8 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/prd/event", authentication.AcceptWechatEvent) }) m.Get("/wechat/material", authentication.GetMaterial) + m.Get("/cloudbrain/get_newest_job", repo.GetNewestJobs) + m.Get("/cloudbrain/get_center_info", repo.GetAICenterInfo) }, securityHeaders(), context.APIContexter(), sudo()) } diff --git a/routers/api/v1/repo/cloudbrain.go b/routers/api/v1/repo/cloudbrain.go index a81263823..d291024f9 100755 --- a/routers/api/v1/repo/cloudbrain.go +++ b/routers/api/v1/repo/cloudbrain.go @@ -12,10 +12,13 @@ import ( "strings" "time" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/cloudbrain" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/modelarts" "code.gitea.io/gitea/modules/storage" routerRepo "code.gitea.io/gitea/routers/repo" ) @@ -100,21 +103,203 @@ func GetCloudbrainTask(ctx *context.APIContext) { } -func CloudbrainGetLog(ctx *context.Context) { +func GetCloudBrainInferenceJob(ctx *context.APIContext) { + + jobID := ctx.Params(":jobid") + job, err := models.GetCloudbrainByJobID(jobID) + if err != nil { + ctx.NotFound(err) + return + } + jobResult, err := cloudbrain.GetJob(job.JobID) + if err != nil { + ctx.NotFound(err) + log.Error("GetJob failed:", err) + return + } + result, err := models.ConvertToJobResultPayload(jobResult.Payload) + if err != nil { + ctx.NotFound(err) + log.Error("ConvertToJobResultPayload failed:", err) + return + } + + job.Status = result.JobStatus.State + if result.JobStatus.State != string(models.JobWaiting) && result.JobStatus.State != string(models.JobFailed) { + taskRoles := result.TaskRoles + taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) + + 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.ParseAndSetDurationFromCloudBrainOne(result, job) + err = models.UpdateJob(job) + if err != nil { + log.Error("UpdateJob failed:", err) + } + } + + ctx.JSON(http.StatusOK, map[string]interface{}{ + "JobID": jobID, + "JobStatus": job.Status, + "JobDuration": job.TrainJobDuration, + }) + +} + +func DelCloudBrainJob(ctx *context.APIContext) { + jobID := ctx.Params(":jobid") + + errStr := cloudbrain.DelCloudBrainJob(jobID) + + if errStr != "" { + ctx.JSON(http.StatusOK, map[string]interface{}{ + "Message": ctx.Tr(errStr), + "VersionName": "1", + "Code": 1, + }) + } else { + ctx.JSON(http.StatusOK, map[string]interface{}{ + "Message": "", + "VersionName": "1", + "Code": 0, + }) + } + +} + +func InferencJobResultList(ctx *context.APIContext) { + jobID := ctx.Params(":jobid") + parentDir := ctx.Query("parentDir") + dirArray := strings.Split(parentDir, "/") + + task, err := models.GetCloudbrainByJobID(jobID) + if err != nil { + log.Error("get cloud brain err:", err) + ctx.ServerError("get cloud brain information failed:", err) + + } + + //get dirs + dirs, err := routerRepo.GetResultDirs(task.JobName, 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": jobID, + "StatusOK": 0, + "Path": dirArray, + "Dirs": fileInfos, + "task": task, + "PageIsCloudBrain": true, + }) + +} + +func GetCloudbrainModelConvertTask(ctx *context.APIContext) { + var ( + err error + ) ID := ctx.Params(":id") - job, err := models.GetCloudbrainByID(ID) + job, err := models.QueryModelConvertById(ID) 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 } + 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 - result, err := cloudbrain.GetJobLog(job.JobID) + result, err := cloudbrain.GetJobLog(jobId) 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 @@ -123,7 +308,7 @@ func CloudbrainGetLog(ctx *context.Context) { for { resultNext, err := cloudbrain.GetJobAllLog(result.ScrollID) if err != nil { - log.Error("GetJobAllLog failed: %v", err, ctx.Data["MsgID"]) + log.Error("GetJobAllLog failed: %v", err) } else { for _, hit := range resultNext.Hits.Hits { hits = append(hits, hit) @@ -148,12 +333,122 @@ func CloudbrainGetLog(ctx *context.Context) { content += log.Source.Message + "\n" } - ctx.JSON(http.StatusOK, map[string]interface{}{ - "JobName": job.JobName, + return map[string]interface{}{ + "JobName": jobName, "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) { @@ -207,3 +502,94 @@ func CloudBrainModelList(ctx *context.APIContext) { "PageIsCloudBrain": true, }) } + +type JobInfo struct { + JobName string `json:"job_name"` + AiCenterId int `json:"ai_center_id"` +} + +func GetNewestJobs(ctx *context.APIContext) { + idsC2Net, err := models.GetNewestJobsByAiCenter() + if err != nil { + log.Error("GetNewestJobsByAiCenter(%s) failed:%v", err.Error()) + return + } + + idsCloudbrain, err := models.GetNewestJobsByType() + if err != nil { + log.Error("GetNewestJobsByType(%s) failed:%v", err.Error()) + return + } + + ids := make([]int64, len(idsC2Net), cap(idsC2Net)*2) + copy(ids, idsC2Net) + for _, id := range idsCloudbrain { + ids = append(ids, id) + } + + jobs, err := models.GetCloudbrainByIDs(ids) + if err != nil { + log.Error("GetCloudbrainByIDs(%s) failed:%v", err.Error()) + return + } + + jobInfos := make([]JobInfo, 0) + for _, job := range jobs { + var id int + var content string + switch job.Type { + case models.TypeCloudBrainOne: + id, content = getAICenterID("cloudbrain_one") + if content == "" { + log.Error("job(%s) has no match config info", job.DisplayJobName) + continue + } + case models.TypeCloudBrainTwo: + id, content = getAICenterID("cloudbrain_two") + if content == "" { + log.Error("job(%s) has no match config info", job.DisplayJobName) + continue + } + case models.TypeC2Net: + centerInfo := strings.Split(job.AiCenter, "+") + if len(centerInfo) != 2 { + log.Error("job(%s):ai_center(%s) is wrong", job.DisplayJobName, job.AiCenter) + continue + } + id, content = getAICenterID(centerInfo[0]) + if content == "" { + log.Error("job(%s) has no match config info", job.DisplayJobName) + continue + } + default: + log.Error("no match info") + continue + } + + jobInfos = append(jobInfos, JobInfo{ + JobName: job.DisplayJobName, + AiCenterId: id, + }) + } + + ctx.JSON(http.StatusOK, jobInfos) +} + +func GetAICenterInfo(ctx *context.APIContext) { + if setting.C2NetInfos == nil { + log.Error("C2NET_SEQUENCE is incorrect") + return + } + + ctx.JSON(http.StatusOK, setting.C2NetInfos.C2NetSqInfo) +} + +func getAICenterID(name string) (int, string) { + for _, info := range setting.C2NetInfos.C2NetSqInfo { + if name == info.Name { + return info.ID, info.Content + } + } + + return 0, "" +} diff --git a/routers/api/v1/repo/cloudbrain_dashboard.go b/routers/api/v1/repo/cloudbrain_dashboard.go index cc125c97f..eb86a8293 100755 --- a/routers/api/v1/repo/cloudbrain_dashboard.go +++ b/routers/api/v1/repo/cloudbrain_dashboard.go @@ -752,10 +752,26 @@ func GetCloudbrainsDetailData(ctx *context.Context) { taskDetail.RepoAlias = ciTasks[i].Repo.OwnerName + "/" + ciTasks[i].Repo.Alias } if ciTasks[i].Cloudbrain.Status == string(models.JobWaiting) { - WaitTimeInt := time.Now().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix() - taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt) - if WaitTimeInt < 0 { - taskDetail.WaitTime = "00:00:00" + if ciTasks[i].Cloudbrain.DeletedAt != nilTime { + WaitTimeInt := ciTasks[i].Cloudbrain.UpdatedUnix.AsTime().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix() + taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt) + if WaitTimeInt < 0 { + taskDetail.WaitTime = "00:00:00" + } + } else { + if ciTasks[i].Cloudbrain.StartTime.AsTime().Unix() == 0 { + WaitTimeInt := time.Now().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix() + taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt) + if WaitTimeInt < 0 { + taskDetail.WaitTime = "00:00:00" + } + } else { + WaitTimeInt := ciTasks[i].Cloudbrain.StartTime.AsTime().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix() + taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt) + if WaitTimeInt < 0 { + taskDetail.WaitTime = "00:00:00" + } + } } } else if ciTasks[i].Cloudbrain.Status == string(models.JobStopped) && ciTasks[i].Cloudbrain.StartTime.AsTime().Unix() == 0 { WaitTimeInt := ciTasks[i].Cloudbrain.EndTime.AsTime().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix() diff --git a/routers/api/v1/repo/modelarts.go b/routers/api/v1/repo/modelarts.go index 2a0ce19db..187c16c50 100755 --- a/routers/api/v1/repo/modelarts.go +++ b/routers/api/v1/repo/modelarts.go @@ -6,12 +6,15 @@ package repo import ( - "code.gitea.io/gitea/modules/grampus" "encoding/json" "net/http" + "path" "strconv" "strings" + "code.gitea.io/gitea/modules/grampus" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/cloudbrain" "code.gitea.io/gitea/modules/context" @@ -240,13 +243,12 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) { } -func TrainJobGetLog(ctx *context.APIContext) { +func TrainJobForModelConvertGetLog(ctx *context.APIContext) { var ( err error ) - var jobID = ctx.Params(":jobid") - var versionName = ctx.Query("version_name") + var jobID = ctx.Params(":id") var baseLine = ctx.Query("base_line") var order = ctx.Query("order") var lines = ctx.Query("lines") @@ -263,10 +265,18 @@ func TrainJobGetLog(ctx *context.APIContext) { return } - resultLogFile, result, err := trainJobGetLogContent(jobID, versionName, baseLine, order, lines_int) + 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 } @@ -282,20 +292,92 @@ func TrainJobGetLog(ctx *context.APIContext) { }) } -func trainJobGetLogContent(jobID string, versionName string, baseLine string, order string, lines int) (*models.GetTrainJobLogFileNamesResult, *models.GetTrainJobLogResult, error) { - task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) +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 + } - resultLogFile, err := modelarts.GetTrainJobLogFileNames(jobID, strconv.FormatInt(task.VersionID, 10)) + return resultLogFile, result, err +} + +func TrainJobGetLog(ctx *context.APIContext) { + var ( + err error + ) + + var jobID = ctx.Params(":jobid") + var versionName = ctx.Query("version_name") + 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 + } + + task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) + if err != nil { + log.Error("GetCloudbrainByJobID(%s) failed:%v", jobID, err.Error()) + return + } + resultLogFile, result, err := trainJobGetLogContent(jobID, task.VersionID, baseLine, order, lines_int) + if err != nil { + log.Error("trainJobGetLog(%s) failed:%v", jobID, err.Error()) + // ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) + return + } + + prefix := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, task.JobName, modelarts.LogPath, versionName), "/") + "/job" + _, err = storage.GetObsLogFileName(prefix) + var canLogDownload bool + if err != nil { + canLogDownload = false + } else { + canLogDownload = true + } + + 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, + "CanLogDownload": canLogDownload, + }) +} + +func trainJobGetLogContent(jobID string, versionID int64, baseLine string, order string, lines int) (*models.GetTrainJobLogFileNamesResult, *models.GetTrainJobLogResult, error) { + + resultLogFile, err := modelarts.GetTrainJobLogFileNames(jobID, strconv.FormatInt(versionID, 10)) if err != nil { log.Error("GetTrainJobLogFileNames(%s) failed:%v", jobID, err.Error()) return nil, nil, err } - result, err := modelarts.GetTrainJobLog(jobID, strconv.FormatInt(task.VersionID, 10), baseLine, resultLogFile.LogFileList[0], order, lines) + result, err := modelarts.GetTrainJobLog(jobID, strconv.FormatInt(versionID, 10), baseLine, resultLogFile.LogFileList[0], order, lines) if err != nil { log.Error("GetTrainJobLog(%s) failed:%v", jobID, err.Error()) return nil, nil, err diff --git a/routers/home.go b/routers/home.go index 2b852533a..85057c3a1 100755 --- a/routers/home.go +++ b/routers/home.go @@ -40,6 +40,7 @@ const ( tplExploreImages base.TplName = "explore/images" tplExploreExploreDataAnalysis base.TplName = "explore/data_analysis" tplHomeTerm base.TplName = "terms" + tplHomePrivacy base.TplName = "privacy" ) // Home render home page @@ -117,6 +118,10 @@ func Dashboard(ctx *context.Context) { ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password" ctx.SetCookie("redirect_to", setting.AppSubURL+ctx.Req.URL.RequestURI(), 0, setting.AppSubURL) ctx.Redirect(setting.AppSubURL + "/user/settings/change_password") + } else if setting.PhoneService.Enabled && ctx.User.IsActive && ctx.User.PhoneNumber == "" { + ctx.Data["Title"] = ctx.Tr("phone.bind_phone") + ctx.HTML(200, "user/auth/bind_phone") + return } else { user.Dashboard(ctx) } @@ -804,3 +809,7 @@ func RecommendHomeInfo(ctx *context.Context) { func HomeTerm(ctx *context.Context) { ctx.HTML(200, tplHomeTerm) } + +func HomePrivacy(ctx *context.Context) { + ctx.HTML(200, tplHomePrivacy) +} diff --git a/routers/init.go b/routers/init.go index eab513c78..7470b1922 100755 --- a/routers/init.go +++ b/routers/init.go @@ -10,6 +10,8 @@ import ( "strings" "time" + "code.gitea.io/gitea/modules/slideimage" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/migrations" "code.gitea.io/gitea/modules/auth/sso" @@ -57,6 +59,7 @@ func checkRunMode() { // NewServices init new services func NewServices() { setting.NewServices() + slideimage.InitSlideImage() if err := storage.Init(); err != nil { log.Fatal("storage init failed: %v", err) } diff --git a/routers/repo/ai_model_convert.go b/routers/repo/ai_model_convert.go new file mode 100644 index 000000000..9a5874956 --- /dev/null +++ b/routers/repo/ai_model_convert.go @@ -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) + } + } + +} diff --git a/routers/repo/ai_model_manage.go b/routers/repo/ai_model_manage.go index 2c24527ce..0aef1a70c 100644 --- a/routers/repo/ai_model_manage.go +++ b/routers/repo/ai_model_manage.go @@ -26,6 +26,7 @@ const ( tplModelInfo = "repo/modelmanage/showinfo" MODEL_LATEST = 1 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 { @@ -58,14 +59,16 @@ func saveModelByParameters(jobId string, versionName string, name string, versio } } cloudType := aiTask.Type + modelSelectedFile := ctx.Query("modelSelectedFile") //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 { log.Info("download model from CloudBrainTwo faild." + err.Error()) return err } - } else if cloudType == models.TypeCloudBrainOne { + cloudType = models.TypeCloudBrainTwo + } else if aiTask.ComputeResource == models.GPUResource { var ResourceSpecs *models.ResourceSpecs json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs) for _, tmp := range ResourceSpecs.ResourceSpec { @@ -74,12 +77,24 @@ func saveModelByParameters(jobId string, versionName string, name string, versio 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 { log.Info("download model from CloudBrainOne faild." + err.Error()) 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["F1"] = "" accuracy["Recall"] = "" @@ -163,7 +178,8 @@ func SaveModel(ctx *context.Context) { description := ctx.Query("Description") engine := ctx.QueryInt("Engine") 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 !ctx.Repo.CanWrite(models.UnitTypeModelManage) { //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.")) return } + if modelSelectedFile == "" { + ctx.Error(500, fmt.Sprintf("Not selected model file.")) + return + } if name == "" || version == "" { ctx.Error(500, fmt.Sprintf("name or version is null.")) @@ -193,11 +213,22 @@ func SaveModel(ctx *context.Context) { 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), "/") if trainUrl != "" { 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, "") log.Info("bucket=" + setting.Bucket + " objectkey=" + objectkey) @@ -206,26 +237,33 @@ func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir return "", 0, err } 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) + "/" - - 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 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/") log.Info("modelActualPath=" + modelActualPath) modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/" destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" bucketName := setting.Attachment.Minio.Bucket 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 { dataActualPath := bucketName + "/" + destKeyNamePrefix 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) { log.Info("DownloadSingleModelFile start.") id := ctx.Params(":ID") @@ -766,7 +833,7 @@ func QueryModelListForPredict(ctx *context.Context) { PageSize: -1, }, RepoID: repoId, - Type: -1, + Type: ctx.QueryInt("type"), New: -1, }) if err != nil { diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index 5a3d0a6f8..0d20f83f0 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -2,7 +2,6 @@ package repo import ( "bufio" - "code.gitea.io/gitea/modules/grampus" "encoding/json" "errors" "fmt" @@ -16,6 +15,8 @@ import ( "time" "unicode/utf8" + "code.gitea.io/gitea/modules/grampus" + "code.gitea.io/gitea/modules/timeutil" "github.com/unknwon/i18n" @@ -46,6 +47,9 @@ const ( tplCloudBrainTrainJobNew base.TplName = "repo/cloudbrain/trainjob/new" tplCloudBrainTrainJobShow base.TplName = "repo/cloudbrain/trainjob/show" + + tplCloudBrainInferenceJobNew base.TplName = "repo/cloudbrain/inference/new" + tplCloudBrainInferenceJobShow base.TplName = "repo/cloudbrain/inference/show" ) var ( @@ -55,6 +59,7 @@ var ( benchmarkGpuInfos *models.GpuInfos benchmarkResourceSpecs *models.ResourceSpecs trainGpuInfos *models.GpuInfos + inferenceGpuInfos *models.GpuInfos ) const BENCHMARK_TYPE_CODE = "repo.cloudbrain.benchmark.types" @@ -96,46 +101,7 @@ func cloudBrainNewDataPrepare(ctx *context.Context) error { var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] ctx.Data["display_job_name"] = displayJobName - result, err := cloudbrain.GetImages() - if err != nil { - ctx.Data["error"] = err.Error() - log.Error("cloudbrain.GetImages failed:", err.Error(), ctx.Data["MsgID"]) - } - - for i, payload := range result.Payload.ImageInfo { - if strings.HasPrefix(result.Payload.ImageInfo[i].Place, "192.168") { - result.Payload.ImageInfo[i].PlaceView = payload.Place[strings.Index(payload.Place, "/"):len(payload.Place)] - } else { - result.Payload.ImageInfo[i].PlaceView = payload.Place - } - } - - ctx.Data["images"] = result.Payload.ImageInfo - - resultPublic, err := cloudbrain.GetPublicImages() - if err != nil { - ctx.Data["error"] = err.Error() - log.Error("cloudbrain.GetPublicImages failed:", err.Error(), ctx.Data["MsgID"]) - } - - for i, payload := range resultPublic.Payload.ImageInfo { - if strings.HasPrefix(resultPublic.Payload.ImageInfo[i].Place, "192.168") { - resultPublic.Payload.ImageInfo[i].PlaceView = payload.Place[strings.Index(payload.Place, "/"):len(payload.Place)] - } else { - resultPublic.Payload.ImageInfo[i].PlaceView = payload.Place - } - } - - ctx.Data["public_images"] = resultPublic.Payload.ImageInfo - - attachs, err := models.GetAllUserAttachments(ctx.User.ID) - if err != nil { - log.Error("GetAllUserAttachments failed: %v", err, ctx.Data["MsgID"]) - return err - } - - ctx.Data["attachments"] = attachs - ctx.Data["command"] = cloudbrain.Command + ctx.Data["command"] = cloudbrain.GetCloudbrainDebugCommand() ctx.Data["code_path"] = cloudbrain.CodeMountPath ctx.Data["dataset_path"] = cloudbrain.DataSetMountPath ctx.Data["model_path"] = cloudbrain.ModelMountPath @@ -148,6 +114,12 @@ func cloudBrainNewDataPrepare(ctx *context.Context) error { ctx.Data["benchmark_categories"] = categories.Category ctx.Data["benchmark_types"] = GetBenchmarkTypes(ctx).BenchmarkType + queuesDetail, _ := cloudbrain.GetQueuesDetail() + if queuesDetail != nil { + ctx.Data["QueuesDetail"] = queuesDetail + } + + cloudbrain.InitSpecialPool() if gpuInfos == nil { json.Unmarshal([]byte(setting.GpuTypes), &gpuInfos) @@ -159,6 +131,13 @@ func cloudBrainNewDataPrepare(ctx *context.Context) error { } ctx.Data["train_gpu_types"] = trainGpuInfos.GpuInfo + if inferenceGpuInfos == nil && setting.InferenceGpuTypes != "" { + json.Unmarshal([]byte(setting.InferenceGpuTypes), &inferenceGpuInfos) + } + if inferenceGpuInfos != nil { + ctx.Data["inference_gpu_types"] = inferenceGpuInfos.GpuInfo + } + if benchmarkGpuInfos == nil { json.Unmarshal([]byte(setting.BenchmarkGpuTypes), &benchmarkGpuInfos) } @@ -178,6 +157,52 @@ func cloudBrainNewDataPrepare(ctx *context.Context) error { json.Unmarshal([]byte(setting.TrainResourceSpecs), &cloudbrain.TrainResourceSpecs) } ctx.Data["train_resource_specs"] = cloudbrain.TrainResourceSpecs.ResourceSpec + + if cloudbrain.InferenceResourceSpecs == nil && setting.InferenceResourceSpecs != "" { + json.Unmarshal([]byte(setting.InferenceResourceSpecs), &cloudbrain.InferenceResourceSpecs) + } + if cloudbrain.InferenceResourceSpecs != nil { + ctx.Data["inference_resource_specs"] = cloudbrain.InferenceResourceSpecs.ResourceSpec + } + + if cloudbrain.SpecialPools != nil { + var debugGpuTypes []*models.GpuInfo + var trainGpuTypes []*models.GpuInfo + + for _, pool := range cloudbrain.SpecialPools.Pools { + org, _ := models.GetOrgByName(pool.Org) + if org != nil { + isOrgMember, _ := models.IsOrganizationMember(org.ID, ctx.User.ID) + if isOrgMember { + for _, jobType := range pool.JobType { + if jobType == string(models.JobTypeDebug) { + debugGpuTypes = append(debugGpuTypes, pool.Pool...) + if pool.ResourceSpec != nil { + ctx.Data["resource_specs"] = pool.ResourceSpec + } + } else if jobType == string(models.JobTypeTrain) { + trainGpuTypes = append(trainGpuTypes, pool.Pool...) + if pool.ResourceSpec != nil { + ctx.Data["train_resource_specs"] = pool.ResourceSpec + } + } + } + break + } + } + + } + + if len(debugGpuTypes) > 0 { + ctx.Data["gpu_types"] = debugGpuTypes + } + + if len(trainGpuTypes) > 0 { + ctx.Data["train_gpu_types"] = trainGpuTypes + } + + } + ctx.Data["params"] = "" ctx.Data["branchName"] = ctx.Repo.BranchName @@ -217,6 +242,10 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { repo := ctx.Repo.Repository tpl := tplCloudBrainNew + if jobType == string(models.JobTypeTrain) { + tpl = tplCloudBrainTrainJobNew + } + tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, jobType, displayJobName) if err == nil { if len(tasks) != 0 { @@ -235,6 +264,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { } if !jobNamePattern.MatchString(displayJobName) { + cloudBrainNewDataPrepare(ctx) ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tpl, &form) return } @@ -269,7 +299,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { return } - command := cloudbrain.Command + command := cloudbrain.GetCloudbrainDebugCommand() if jobType == string(models.JobTypeTrain) { tpl = tplCloudBrainTrainJobNew commandTrain, err := getTrainJobCommand(form) @@ -282,6 +312,14 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { command = commandTrain } + errStr := checkCloudBrainSpecialPool(ctx, jobType, gpuQueue, resourceSpecId) + + if errStr != "" { + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr(errStr, tpl, &form) + return + } + if branchName == "" { branchName = cloudbrain.DefaultBranchName } @@ -318,6 +356,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { BenchmarkTypeID: 0, BenchmarkChildTypeID: 0, ResourceSpecId: resourceSpecId, + ResultPath: storage.GetMinioPath(jobName, cloudbrain.ResultPath+"/"), } err = cloudbrain.GenerateTask(req) @@ -334,6 +373,163 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { } } + +func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBrainInferencForm) { + ctx.Data["PageIsCloudBrain"] = true + displayJobName := form.DisplayJobName + jobName := util.ConvertDisplayJobNameToJobName(displayJobName) + image := strings.TrimSpace(form.Image) + uuid := form.Attachment + jobType := string(models.JobTypeInference) + gpuQueue := form.GpuType + codePath := setting.JobPath + jobName + cloudbrain.CodeMountPath + resourceSpecId := form.ResourceSpecId + branchName := form.BranchName + labelName := form.LabelName + repo := ctx.Repo.Repository + + ckptUrl := setting.Attachment.Minio.RealPath + form.TrainUrl + form.CkptName + log.Info("ckpt url:" + ckptUrl) + tpl := tplCloudBrainInferenceJobNew + command, err := getInferenceJobCommand(form) + if err != nil { + log.Error("getTrainJobCommand failed: %v", err) + ctx.RenderWithErr(err.Error(), tpl, &form) + return + } + + tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, jobType, displayJobName) + if err == nil { + if len(tasks) != 0 { + log.Error("the job name did already exist", ctx.Data["MsgID"]) + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr("the job name did already exist", tpl, &form) + return + } + } else { + if !models.IsErrJobNotExist(err) { + log.Error("system error, %v", err, ctx.Data["MsgID"]) + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr("system error", tpl, &form) + return + } + } + + if !jobNamePattern.MatchString(displayJobName) { + ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tpl, &form) + return + } + + count, err := models.GetCloudbrainCountByUserID(ctx.User.ID, jobType) + if err != nil { + log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"]) + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr("system error", tpl, &form) + return + } else { + if count >= 1 { + log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr(ctx.Tr("repo.cloudbrain.morethanonejob"), tpl, &form) + return + } + } + + if branchName == "" { + branchName = cloudbrain.DefaultBranchName + } + downloadCode(repo, codePath, branchName) + uploadCodeToMinio(codePath+"/", jobName, cloudbrain.CodeMountPath+"/") + resultPath := setting.JobPath + jobName + cloudbrain.ResultPath + "/" + mkResultPath(resultPath) + uploadCodeToMinio(resultPath, jobName, cloudbrain.ResultPath+"/") + + commitID, _ := ctx.Repo.GitRepo.GetBranchCommitID(branchName) + + datasetInfos, datasetNames, err := models.GetDatasetInfo(uuid) + if err != nil { + log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"]) + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr(ctx.Tr("cloudbrain.error.dataset_select"), tpl, &form) + return + } + + req := cloudbrain.GenerateCloudBrainTaskReq{ + Ctx: ctx, + DisplayJobName: displayJobName, + JobName: jobName, + Image: image, + Command: command, + Uuids: uuid, + DatasetNames: datasetNames, + DatasetInfos: datasetInfos, + CodePath: storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"), + ModelPath: setting.Attachment.Minio.RealPath + form.TrainUrl, + BenchmarkPath: storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), + Snn4ImageNetPath: storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), + BrainScorePath: storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), + JobType: jobType, + GpuQueue: gpuQueue, + Description: form.Description, + BranchName: branchName, + BootFile: form.BootFile, + Params: form.Params, + CommitID: commitID, + ResourceSpecId: resourceSpecId, + ResultPath: storage.GetMinioPath(jobName, cloudbrain.ResultPath+"/"), + ModelName: form.ModelName, + ModelVersion: form.ModelVersion, + CkptName: form.CkptName, + TrainUrl: form.TrainUrl, + LabelName: labelName, + } + + err = cloudbrain.GenerateTask(req) + if err != nil { + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr(err.Error(), tpl, &form) + return + } + + ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/inference-job") + +} +/** + 检查用户传输的参数是否符合专属资源池 +*/ +func checkCloudBrainSpecialPool(ctx *context.Context, jobType string, queue string, resourceSpecId int) string { + if cloudbrain.SpecialPools != nil { + + var isInPoolOrg = false + var matchSpecialPool = false + + for _, specialPool := range cloudbrain.SpecialPools.Pools { + + if cloudbrain.IsElementExist(specialPool.JobType, jobType) && cloudbrain.IsQueueInSpecialtPool(specialPool.Pool, queue) { + if cloudbrain.IsResourceSpecInSpecialPool(specialPool.ResourceSpec, resourceSpecId) { + matchSpecialPool = true + org, _ := models.GetOrgByName(specialPool.Org) + if org != nil { + isInPoolOrg, _ = models.IsOrganizationMember(org.ID, ctx.User.ID) + if isInPoolOrg { + break //传入参数,和专属资源池匹配上了,检查通过 + } + } + } + + } + + } + //资源池有匹配上,但是用户不在相应的组织中,返回错误信息。界面已经过滤了选择,界面操作不会到这个逻辑 + if matchSpecialPool && !isInPoolOrg { + return ctx.Tr("repo.grampus.no_operate_right") + } + + } + //没有匹配到资源池或者没有设置专属资源池,检查通过; 获取和资源池完全匹配检查通过 + return "" +} + func CloudBrainRestart(ctx *context.Context) { var ID = ctx.Params(":id") var resultCode = "0" @@ -369,7 +565,18 @@ func CloudBrainRestart(ctx *context.Context) { for _, resourceType := range gpuInfos.GpuInfo { if resourceType.Queue == task.GpuQueue { hasSameResource = true - continue + break + } + } + if !hasSameResource && cloudbrain.SpecialPools != nil { + + for _, specialPool := range cloudbrain.SpecialPools.Pools { + cloudbrain.IsElementExist(specialPool.JobType, string(models.JobTypeDebug)) + for _, pool := range specialPool.Pool { + if pool.Queue == task.GpuQueue { + hasSameResource = true + } + } } } @@ -432,7 +639,7 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo var task *models.Cloudbrain var err error - if jobType == models.JobTypeTrain { + if jobType == models.JobTypeTrain || jobType == models.JobTypeInference { task, err = models.GetCloudbrainByJobID(ctx.Params(":jobid")) } else { task, err = models.GetCloudbrainByIDWithDeleted(ctx.Params(":id")) @@ -455,8 +662,41 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo if cloudbrain.TrainResourceSpecs == nil { json.Unmarshal([]byte(setting.TrainResourceSpecs), &cloudbrain.TrainResourceSpecs) } + hasSpec := false for _, tmp := range cloudbrain.TrainResourceSpecs.ResourceSpec { if tmp.Id == task.ResourceSpecId { + hasSpec = true + ctx.Data["GpuNum"] = tmp.GpuNum + ctx.Data["CpuNum"] = tmp.CpuNum + ctx.Data["MemMiB"] = tmp.MemMiB + ctx.Data["ShareMemMiB"] = tmp.ShareMemMiB + } + } + + if !hasSpec && cloudbrain.SpecialPools != nil { + for _, specialPool := range cloudbrain.SpecialPools.Pools { + + if specialPool.ResourceSpec != nil { + + for _, spec := range specialPool.ResourceSpec { + if task.ResourceSpecId == spec.Id { + ctx.Data["GpuNum"] = spec.GpuNum + ctx.Data["CpuNum"] = spec.CpuNum + ctx.Data["MemMiB"] = spec.MemMiB + ctx.Data["ShareMemMiB"] = spec.ShareMemMiB + break + } + } + } + } + } + + } else if task.JobType == string(models.JobTypeInference) { + if cloudbrain.InferenceResourceSpecs == nil { + json.Unmarshal([]byte(setting.InferenceResourceSpecs), &cloudbrain.InferenceResourceSpecs) + } + for _, tmp := range cloudbrain.InferenceResourceSpecs.ResourceSpec { + if tmp.Id == task.ResourceSpecId { ctx.Data["GpuNum"] = tmp.GpuNum ctx.Data["CpuNum"] = tmp.CpuNum ctx.Data["MemMiB"] = tmp.MemMiB @@ -491,6 +731,24 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo ctx.Data["resource_type"] = resourceType.Value } } + for _, specialPool := range cloudbrain.SpecialPools.Pools { + + for _, resourceType := range specialPool.Pool { + if resourceType.Queue == jobRes.Config.GpuType { + ctx.Data["resource_type"] = resourceType.Value + } + } + } + + } else if task.JobType == string(models.JobTypeInference) { + if inferenceGpuInfos == nil { + json.Unmarshal([]byte(setting.InferenceGpuTypes), &inferenceGpuInfos) + } + for _, resourceType := range inferenceGpuInfos.GpuInfo { + if resourceType.Queue == jobRes.Config.GpuType { + ctx.Data["resource_type"] = resourceType.Value + } + } } else if cloudbrain.IsBenchmarkJob(task.JobType) { if benchmarkGpuInfos == nil { json.Unmarshal([]byte(setting.BenchmarkGpuTypes), &benchmarkGpuInfos) @@ -573,7 +831,9 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo if task.TrainJobDuration == "" { if task.Duration == 0 { var duration int64 - if task.Status == string(models.JobRunning) { + if task.Status == string(models.JobWaiting) { + duration = 0 + } else if task.Status == string(models.JobRunning) { duration = time.Now().Unix() - int64(task.CreatedUnix) } else { duration = int64(task.UpdatedUnix) - int64(task.CreatedUnix) @@ -607,6 +867,8 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo } ctx.Data["task"] = task + labelName := strings.Fields(task.LabelName) + ctx.Data["LabelName"] = labelName ctx.Data["jobName"] = task.JobName ctx.Data["displayJobName"] = task.DisplayJobName version_list_task := make([]*models.Cloudbrain, 0) @@ -846,7 +1108,7 @@ func CloudBrainStop(ctx *context.Context) { if task.Status == string(models.JobStopped) || task.Status == string(models.JobFailed) || task.Status == string(models.JobSucceeded) { log.Error("the job(%s) has been stopped", task.JobName, ctx.Data["msgID"]) resultCode = "-1" - errorMsg = "system error" + errorMsg = "cloudbrain.Already_stopped" break } @@ -854,7 +1116,7 @@ func CloudBrainStop(ctx *context.Context) { if err != nil { log.Error("StopJob(%s) failed:%v", task.JobName, err, ctx.Data["msgID"]) resultCode = "-1" - errorMsg = "system error" + errorMsg = "cloudbrain.Stopped_failed" break } @@ -867,7 +1129,7 @@ func CloudBrainStop(ctx *context.Context) { if err != nil { log.Error("UpdateJob(%s) failed:%v", task.JobName, err, ctx.Data["msgID"]) resultCode = "-1" - errorMsg = "system error" + errorMsg = "cloudbrain.Stopped_success_update_status_fail" break } @@ -877,7 +1139,7 @@ func CloudBrainStop(ctx *context.Context) { ctx.JSON(200, map[string]interface{}{ "result_code": resultCode, - "error_msg": errorMsg, + "error_msg": ctx.Tr(errorMsg), "status": status, "id": ID, "StatusOK": 0, @@ -1167,6 +1429,18 @@ func GetModelDirs(jobName string, parentDir string) (string, error) { return getDirs(req) } +func GetResultDirs(jobName string, parentDir string) (string, error) { + var req string + modelActualPath := storage.GetMinioPath(jobName, cloudbrain.ResultPath+"/") + if parentDir == "" { + req = "baseDir=" + modelActualPath + } else { + req = "baseDir=" + modelActualPath + "&parentDir=" + parentDir + } + + return getDirs(req) +} + func CloudBrainDownloadModel(ctx *context.Context) { parentDir := ctx.Query("parentDir") fileName := ctx.Query("fileName") @@ -1181,6 +1455,20 @@ func CloudBrainDownloadModel(ctx *context.Context) { ctx.Resp.Header().Set("Cache-Control", "max-age=0") http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) } +func CloudBrainDownloadInferenceResult(ctx *context.Context) { + parentDir := ctx.Query("parentDir") + fileName := ctx.Query("fileName") + jobName := ctx.Query("jobName") + filePath := "jobs/" + jobName + "/result/" + 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.Resp.Header().Set("Cache-Control", "max-age=0") + http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) +} func GetRate(ctx *context.Context) { isObjectDetcionAll := ctx.QueryBool("isObjectDetcionAll") @@ -1334,13 +1622,21 @@ func uploadCodeToMinio(codePath, jobName, parentDir string) error { } func mkModelPath(modelPath string) error { - err := os.MkdirAll(modelPath, os.ModePerm) + return mkPathAndReadMeFile(modelPath, "You can put the model file into this directory and download it by the web page.") +} + +func mkResultPath(resultPath string) error { + return mkPathAndReadMeFile(resultPath, "You can put the result file into this directory and download it by the web page.") +} + +func mkPathAndReadMeFile(path string, text string) error { + err := os.MkdirAll(path, os.ModePerm) if err != nil { - log.Error("MkdirAll(%s) failed:%v", modelPath, err) + log.Error("MkdirAll(%s) failed:%v", path, err) return err } - fileName := modelPath + "README" + fileName := path + "README" f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) if err != nil { log.Error("OpenFile failed", err.Error()) @@ -1349,7 +1645,7 @@ func mkModelPath(modelPath string) error { defer f.Close() - _, err = f.WriteString("You can put the model file into this directory and download it by the web page.") + _, err = f.WriteString(text) if err != nil { log.Error("WriteString failed", err.Error()) return err @@ -2068,6 +2364,7 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo BenchmarkTypeID: benchmarkTypeID, BenchmarkChildTypeID: benchmarkChildTypeID, ResourceSpecId: resourceSpecId, + ResultPath: storage.GetMinioPath(jobName, cloudbrain.ResultPath+"/"), } err = cloudbrain.GenerateTask(req) @@ -2094,7 +2391,7 @@ func ModelBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm) repo := ctx.Repo.Repository tpl := tplCloudBrainBenchmarkNew - command := cloudbrain.Command + command := cloudbrain.GetCloudbrainDebugCommand() tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, jobType, displayJobName) if err == nil { @@ -2196,6 +2493,7 @@ func ModelBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm) BenchmarkTypeID: 0, BenchmarkChildTypeID: benchmarkChildTypeID, ResourceSpecId: resourceSpecId, + ResultPath: storage.GetMinioPath(jobName, cloudbrain.ResultPath+"/"), } err = cloudbrain.GenerateTask(req) @@ -2246,6 +2544,64 @@ func CloudBrainTrainJobNew(ctx *context.Context) { ctx.HTML(http.StatusOK, tplCloudBrainTrainJobNew) } +func InferenceCloudBrainJobNew(ctx *context.Context) { + err := cloudBrainNewDataPrepare(ctx) + if err != nil { + ctx.ServerError("get new train-job info failed", err) + return + } + ctx.HTML(http.StatusOK, tplCloudBrainInferenceJobNew) +} + +func InferenceCloudBrainJobShow(ctx *context.Context) { + cloudBrainShow(ctx, tplCloudBrainInferenceJobShow, models.JobTypeInference) +} + +func DownloadInferenceResultFile(ctx *context.Context) { + var jobID = ctx.Params(":jobid") + var versionName = ctx.Query("version_name") + task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) + if err != nil { + log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) + return + } + + allFile, err := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, task.ResultUrl) + returnFileName := task.DisplayJobName + ".zip" + MinioDownloadManyFile(task.ResultUrl, ctx, returnFileName, allFile) +} + +func getInferenceJobCommand(form auth.CreateCloudBrainInferencForm) (string, error) { + var command string + bootFile := strings.TrimSpace(form.BootFile) + params := form.Params + + if !strings.HasSuffix(bootFile, ".py") { + log.Error("bootFile(%s) format error", bootFile) + return command, errors.New("bootFile format error") + } + + var parameters models.Parameters + var param string + if len(params) != 0 { + err := json.Unmarshal([]byte(params), ¶meters) + if err != nil { + log.Error("Failed to Unmarshal params: %s (%v)", params, err) + return command, err + } + + for _, parameter := range parameters.Parameter { + param += " --" + parameter.Label + "=" + parameter.Value + } + } + + param += " --modelname" + "=" + form.CkptName + + command += "python /code/" + bootFile + param + " > " + cloudbrain.ResultPath + "/" + form.DisplayJobName + "-" + cloudbrain.LogFile + + return command, nil +} + func getTrainJobCommand(form auth.CreateCloudBrainForm) (string, error) { var command string bootFile := strings.TrimSpace(form.BootFile) diff --git a/routers/repo/grampus.go b/routers/repo/grampus.go index 99ef847fe..978b7462d 100755 --- a/routers/repo/grampus.go +++ b/routers/repo/grampus.go @@ -43,6 +43,8 @@ func GrampusTrainJobGPUNew(ctx *context.Context) { ctx.ServerError("get new train-job info failed", err) return } + waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeC2Net, models.GPUResource, models.JobTypeTrain) + ctx.Data["WaitCount"] = waitCount ctx.HTML(http.StatusOK, tplGrampusTrainJobGPUNew) } @@ -53,6 +55,8 @@ func GrampusTrainJobNPUNew(ctx *context.Context) { ctx.ServerError("get new train-job info failed", err) return } + waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeC2Net, models.NPUResource, models.JobTypeTrain) + ctx.Data["WaitCount"] = waitCount ctx.HTML(200, tplGrampusTrainJobNPUNew) } @@ -75,27 +79,42 @@ func grampusTrainJobNewDataPrepare(ctx *context.Context, processType string) err ctx.Data["GPUEnabled"] = true ctx.Data["NPUEnabled"] = true - + includeCenters := make(map[string]struct{}) + excludeCenters := make(map[string]struct{}) if grampus.SpecialPools != nil { for _, pool := range grampus.SpecialPools.Pools { if pool.IsExclusive { - org, _ := models.GetOrgByName(pool.Org) - if org != nil { - isOrgMember, _ := models.IsOrganizationMember(org.ID, ctx.User.ID) - if !isOrgMember { - ctx.Data[pool.Type+"Enabled"] = false + if !IsUserInOrgPool(ctx.User.ID, pool) { + ctx.Data[pool.Type+"Enabled"] = false + } + } else { + if strings.Contains(strings.ToLower(processType), strings.ToLower(pool.Type)) { + if IsUserInOrgPool(ctx.User.ID, pool) { + for _, center := range pool.Pool { + includeCenters[center.Queue] = struct{}{} + } + } else { + for _, center := range pool.Pool { + excludeCenters[center.Queue] = struct{}{} + } + } + } + } } } //get valid resource specs specs, err := grampus.GetResourceSpecs(processType) + + grampusSpecs := getFilterSpecBySpecialPool(specs, includeCenters, excludeCenters) + if err != nil { log.Error("GetResourceSpecs failed:", err.Error()) } else { - ctx.Data["flavor_infos"] = specs.Infos + ctx.Data["flavor_infos"] = grampusSpecs } //get branches @@ -117,6 +136,46 @@ func grampusTrainJobNewDataPrepare(ctx *context.Context, processType string) err return nil } +func getFilterSpecBySpecialPool(specs *models.GetGrampusResourceSpecsResult, includeCenters map[string]struct{}, excludeCenters map[string]struct{}) []models.GrampusSpec { + if len(includeCenters) == 0 && len(excludeCenters) == 0 { + return specs.Infos + } + var grampusSpecs []models.GrampusSpec + for _, info := range specs.Infos { + if isInIncludeCenters(info, includeCenters) || (len(excludeCenters) != 0 && isNotAllInExcludeCenters(info, excludeCenters)) { + grampusSpecs = append(grampusSpecs, info) + } + + } + return grampusSpecs +} + +func isInIncludeCenters(grampusSpec models.GrampusSpec, centers map[string]struct{}) bool { + for _, center := range grampusSpec.Centers { + if _, ok := centers[center.ID]; ok { + return true + } + } + return false +} +func isNotAllInExcludeCenters(grampusSpec models.GrampusSpec, centers map[string]struct{}) bool { + for _, center := range grampusSpec.Centers { + if _, ok := centers[center.ID]; !ok { + return true + } + } + return false +} + +func IsUserInOrgPool(userId int64, pool *models.SpecialPool) bool { + org, _ := models.GetOrgByName(pool.Org) + if org != nil { + isOrgMember, _ := models.IsOrganizationMember(org.ID, userId) + return isOrgMember + } + return false +} + func grampusParamCheckCreateTrainJob(form auth.CreateGrampusTrainJobForm) error { if !strings.HasSuffix(strings.TrimSpace(form.BootFile), ".py") { log.Error("the boot file(%s) must be a python file", form.BootFile) @@ -263,6 +322,7 @@ func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrain JobName: jobName, DisplayJobName: displayJobName, ComputeResource: models.GPUResource, + ProcessType: grampus.ProcessorTypeGPU, Command: command, ResourceSpecId: form.FlavorID, ImageUrl: image, @@ -436,6 +496,7 @@ func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain JobName: jobName, DisplayJobName: displayJobName, ComputeResource: models.NPUResource, + ProcessType: grampus.ProcessorTypeNPU, Command: command, ResourceSpecId: form.FlavorID, ImageId: form.ImageID, diff --git a/routers/repo/modelarts.go b/routers/repo/modelarts.go index d1d00d095..b5afa4713 100755 --- a/routers/repo/modelarts.go +++ b/routers/repo/modelarts.go @@ -119,7 +119,8 @@ func MustEnableModelArts(ctx *context.Context) { func NotebookNew(ctx *context.Context) { notebookNewDataPrepare(ctx) - + waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "") + ctx.Data["WaitCount"] = waitCount ctx.HTML(200, tplModelArtsNotebookNew) } @@ -630,6 +631,8 @@ func TrainJobNew(ctx *context.Context) { ctx.ServerError("get new train-job info failed", err) return } + waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "") + ctx.Data["WaitCount"] = waitCount ctx.HTML(200, tplModelArtsTrainJobNew) } @@ -782,6 +785,8 @@ func TrainJobNewVersion(ctx *context.Context) { ctx.ServerError("get new train-job info failed", err) return } + waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "") + ctx.Data["WaitCount"] = waitCount ctx.HTML(200, tplModelArtsTrainJobVersionNew) } @@ -979,7 +984,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) flavorCode := form.Flavor params := form.Params poolID := form.PoolID - isSaveParam := form.IsSaveParam + //isSaveParam := form.IsSaveParam repo := ctx.Repo.Repository codeLocalPath := setting.JobPath + jobName + modelarts.CodePath codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath @@ -1124,45 +1129,45 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) } //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{ JobName: jobName, @@ -1190,6 +1195,9 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) TotalVersionCount: modelarts.TotalVersionCount, DatasetName: datasetNames, } + userCommand, userImageUrl := getUserCommand(engineID, req) + req.UserCommand = userCommand + req.UserImageUrl = userImageUrl //将params转换Parameters.Parameter,出错时返回给前端 var Parameters modelarts.Parameters @@ -1208,6 +1216,36 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") } +func getUserCommand(engineId int, req *modelarts.GenerateTrainJobReq) (string, string) { + userImageUrl := "" + userCommand := "" + if engineId < 0 { + tmpCodeObsPath := strings.Trim(req.CodeObsPath, "/") + tmpCodeObsPaths := strings.Split(tmpCodeObsPath, "/") + lastCodeDir := "code" + if len(tmpCodeObsPaths) > 0 { + lastCodeDir = tmpCodeObsPaths[len(tmpCodeObsPaths)-1] + } + userCommand = "/bin/bash /home/work/run_train.sh 's3://" + req.CodeObsPath + "' '" + lastCodeDir + "/" + 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) { ctx.Data["PageIsTrainJob"] = true var jobID = ctx.Params(":jobid") @@ -1244,7 +1282,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ flavorCode := form.Flavor params := form.Params poolID := form.PoolID - isSaveParam := form.IsSaveParam + //isSaveParam := form.IsSaveParam repo := ctx.Repo.Repository codeLocalPath := setting.JobPath + jobName + modelarts.CodePath codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath + VersionOutputPath + "/" @@ -1364,46 +1402,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) if err != nil { @@ -1438,6 +1476,9 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ TotalVersionCount: latestTask.TotalVersionCount + 1, DatasetName: datasetNames, } + userCommand, userImageUrl := getUserCommand(engineID, req) + req.UserCommand = userCommand + req.UserImageUrl = userImageUrl err = modelarts.GenerateTrainJobVersion(ctx, req, jobID) if err != nil { @@ -1876,8 +1917,8 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference modelName := form.ModelName modelVersion := form.ModelVersion ckptName := form.CkptName - - ckptUrl := form.TrainUrl + form.CkptName + ckptUrl := "/" + form.TrainUrl + form.CkptName + log.Info("ckpt url:" + ckptUrl) count, err := models.GetCloudbrainInferenceJobCountByUserID(ctx.User.ID) if err != nil { @@ -2044,6 +2085,13 @@ func InferenceJobIndex(ctx *context.Context) { page = 1 } + listType := ctx.Query("listType") + ctx.Data["ListType"] = listType + + if listType == models.AllResource { + listType = "" + } + var jobTypes []string jobTypes = append(jobTypes, string(models.JobTypeInference)) tasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{ @@ -2051,9 +2099,10 @@ func InferenceJobIndex(ctx *context.Context) { Page: page, PageSize: setting.UI.IssuePagingNum, }, - RepoID: repo.ID, - Type: models.TypeCloudBrainTwo, - JobTypes: jobTypes, + RepoID: repo.ID, + ComputeResource: listType, + JobTypes: jobTypes, + Type: models.TypeCloudBrainAll, }) if err != nil { ctx.ServerError("Cloudbrain", err) @@ -2063,7 +2112,9 @@ func InferenceJobIndex(ctx *context.Context) { for i, task := range tasks { tasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain) tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain) - tasks[i].ComputeResource = models.NPUResource + if tasks[i].ComputeResource == "" { + tasks[i].ComputeResource = models.NPUResource + } } repoId := ctx.Repo.Repository.ID @@ -2095,6 +2146,8 @@ func InferenceJobNew(ctx *context.Context) { ctx.ServerError("get new inference-job info failed", err) return } + waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "") + ctx.Data["WaitCount"] = waitCount ctx.HTML(200, tplModelArtsInferenceJobNew) } func inferenceJobNewDataPrepare(ctx *context.Context) error { diff --git a/routers/repo/repo.go b/routers/repo/repo.go index c0803ed06..03d2d832a 100644 --- a/routers/repo/repo.go +++ b/routers/repo/repo.go @@ -195,8 +195,11 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) { } ctx.Data["ContextUser"] = ctxUser if !form.AutoAgree { + ctx.Data["CheckedAutoAgree"] = "" ctx.RenderWithErr(ctx.Tr("repo.template.one_promise"), tplCreate, form) return + } else { + ctx.Data["CheckedAutoAgree"] = "checked" } if ctx.HasError() { ctx.HTML(200, tplCreate) diff --git a/routers/repo/user_data_analysis.go b/routers/repo/user_data_analysis.go index 207727af1..ac1265d04 100755 --- a/routers/repo/user_data_analysis.go +++ b/routers/repo/user_data_analysis.go @@ -112,6 +112,7 @@ func getExcelHeader(ctx *context.Context) map[string]string { excelHeader = append(excelHeader, ctx.Tr("user.static.RecommendImage")) excelHeader = append(excelHeader, ctx.Tr("user.static.email")) + excelHeader = append(excelHeader, ctx.Tr("user.static.phone")) excelHeader = append(excelHeader, ctx.Tr("user.static.location")) excelHeader = append(excelHeader, ctx.Tr("user.static.registdate")) @@ -193,6 +194,9 @@ func writeExcel(row int, xlsx *excelize.File, sheetName string, userRecord *mode xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Email) tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Phone) + tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.UserLocation) tmp = tmp + 1 @@ -268,6 +272,9 @@ func writeExcelPage(row int, xlsx *excelize.File, sheetName string, userRecord * xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Email) tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Phone) + tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.UserLocation) tmp = tmp + 1 @@ -601,7 +608,7 @@ func QueryUserStaticDataPage(ctx *context.Context) { filename := sheetName + "_" + startDate + "_" + endDate + ".xlsx" os.Remove(setting.AppDataPath + Excel_File_Path + filename) go writeFileToDisk(ctx, count, re, filename) - ctx.JSON(http.StatusOK, ctx.Tr("user.static.downloadinfo")+setting.AppURL+"api/v1/download_user_define_file?filename="+filename) + ctx.JSON(http.StatusOK, ctx.Tr("user.static.downloadinfo")+"/api/v1/download_user_define_file?filename="+filename) } else { mapInterface := make(map[string]interface{}) re, count := models.QueryUserStaticDataPage(pageOpts) @@ -721,3 +728,114 @@ func TimingCountData() { startTime := currentTimeNow.AddDate(0, 0, -1).Format("2006-01-02") TimingCountDataByDateAndReCount(startTime, false) } + +func QueryUserActivity(ctx *context.Context) { + startDate := ctx.Query("beginTime") + endDate := ctx.Query("endTime") + + t, _ := time.Parse("2006-01-02", startDate) + startTime := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) + startTime = startTime.UTC() + + t, _ = time.Parse("2006-01-02", endDate) + endTime := time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, t.Location()) + endTime = endTime.UTC() + + sheetName := ctx.Tr("user.static.sheetname") + filename := sheetName + "_" + startDate + "_" + endDate + ".xlsx" + filePath := setting.AppDataPath + Excel_File_Path + filename + os.Remove(setting.AppDataPath + Excel_File_Path + filename) + + go writeUserActivityToExcel(startTime, endTime, filePath, ctx) + + ctx.JSON(http.StatusOK, ctx.Tr("user.static.downloadinfo")+"/api/v1/download_user_define_file?filename="+filename) + +} + +func writeUserActivityToExcel(startTime time.Time, endTime time.Time, filePath string, ctx *context.Context) { + re := models.QueryDataForActivity(startTime, endTime) + log.Info("return count=" + fmt.Sprint(len(re))) + //writer exec file. + xlsx := excelize.NewFile() + sheetName := ctx.Tr("user.static.sheetname") + index := xlsx.NewSheet(sheetName) + xlsx.DeleteSheet("Sheet1") + + excelHeader := make([]string, 0) + excelHeader = append(excelHeader, ctx.Tr("user.static.id")) + excelHeader = append(excelHeader, ctx.Tr("user.static.name")) + excelHeader = append(excelHeader, ctx.Tr("user.static.codemergecount")) + excelHeader = append(excelHeader, ctx.Tr("user.static.commitcount")) + excelHeader = append(excelHeader, ctx.Tr("user.static.issuecount")) + excelHeader = append(excelHeader, ctx.Tr("user.static.commentcount")) + excelHeader = append(excelHeader, ctx.Tr("user.static.watchedcount")) + excelHeader = append(excelHeader, ctx.Tr("user.static.commitcodesize")) + excelHeader = append(excelHeader, ctx.Tr("user.static.solveissuecount")) + + excelHeader = append(excelHeader, ctx.Tr("user.static.CommitDatasetNum")) + excelHeader = append(excelHeader, ctx.Tr("user.static.CommitModelCount")) + excelHeader = append(excelHeader, ctx.Tr("user.static.email")) + excelHeader = append(excelHeader, ctx.Tr("user.static.phone")) + excelHeader = append(excelHeader, ctx.Tr("user.static.registdate")) + + excelHeaderMap := make(map[string]string, 0) + var j byte + j = 0 + for _, value := range excelHeader { + excelColumn := getColumn(j) + fmt.Sprint(1) + log.Info("excelColumn=" + excelColumn) + excelHeaderMap[excelColumn] = value + j++ + } + + for k, v := range excelHeaderMap { + //设置单元格的值 + xlsx.SetCellValue(sheetName, k, v) + } + + for i, userRecord := range re { + row := i + 2 + rows := fmt.Sprint(row) + var tmp byte + tmp = 0 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.ID) + tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Name) + tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.CodeMergeCount) + tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.CommitCount) + tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.IssueCount) + tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.CommentCount) + tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.WatchedCount) + tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.CommitCodeSize) + tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.SolveIssueCount) + tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.CommitDatasetNum) + tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.CommitModelCount) + tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Email) + tmp = tmp + 1 + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Phone) + tmp = tmp + 1 + formatTime := userRecord.RegistDate.Format("2006-01-02 15:04:05") + xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, formatTime[0:len(formatTime)-3]) + tmp = tmp + 1 + } + + //设置默认打开的表单 + xlsx.SetActiveSheet(index) + + os.Mkdir(setting.AppDataPath+Excel_File_Path, 0755) + if err := xlsx.SaveAs(filePath); err != nil { + log.Info("writer exel error." + err.Error()) + } else { + log.Info("write to file succeed, filepath=" + filePath) + } +} diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 5c90f13fb..35a26f585 100755 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -12,6 +12,8 @@ import ( "text/template" "time" + "code.gitea.io/gitea/modules/slideimage" + "code.gitea.io/gitea/routers/image" "code.gitea.io/gitea/routers/authentication" @@ -233,6 +235,10 @@ func NewMacaron() *macaron.Macaron { m.Use(captcha.Captchaer(captcha.Options{ SubURL: setting.AppSubURL, })) + m.Use(slideimage.SlideImager(slideimage.Options{ + SubURL: setting.AppSubURL, + SampleImages: setting.SlideImagesCount, + })) m.Use(session.Sessioner(session.Options{ Provider: setting.SessionConfig.Provider, ProviderConfig: setting.SessionConfig.ProviderConfig, @@ -333,6 +339,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/all/dosearch/", routers.SearchApi) m.Post("/user/login/kanban", user.SignInPostAPI) m.Get("/home/term", routers.HomeTerm) + m.Get("/home/privacy", routers.HomePrivacy) m.Group("/explore", func() { m.Get("", func(ctx *context.Context) { ctx.Redirect(setting.AppSubURL + "/explore/repos") @@ -366,8 +373,11 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/user", func() { m.Get("/login", user.SignIn) m.Get("/login/cloud_brain", user.SignInCloudBrain) - + m.Post("/login/cloud_brain", bindIgnErr(auth.SignInForm{}), user.SignInCloudBrainPost) m.Post("/login", bindIgnErr(auth.SignInForm{}), user.SignInPost) + + m.Get("/login/phone", user.SignInPhone) + m.Post("/login/phone", bindIgnErr(auth.PhoneNumberCodeForm{}), user.SignInPhonePost) m.Group("", func() { m.Combo("/login/openid"). Get(user.SignInOpenID). @@ -407,6 +417,10 @@ func RegisterRoutes(m *macaron.Macaron) { }, reqSignOut) m.Any("/user/events", reqSignIn, events.Events) + m.Get("/slideImage", user.CreateSlideImageInfo) + m.Post("/verifySlideImage", bindIgnErr(auth.SlideImageForm{}), user.VerifySlideImage) + m.Post("/sendVerifyCode", bindIgnErr(auth.PhoneNumberForm{}), user.SendVerifyCode) + m.Post("/bindPhone", reqSignIn, bindIgnErr(auth.PhoneNumberCodeForm{}), user.BindPhone) m.Group("/login/oauth", func() { m.Get("/authorize", bindIgnErr(auth.AuthorizationForm{}), user.AuthorizeOAuth) @@ -486,6 +500,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/email2user", user.Email2User) m.Get("/recover_account", user.ResetPasswd) m.Post("/recover_account", user.ResetPasswdPost) + m.Post("/recover_account_by_phone", bindIgnErr(auth.ResetPassWordByPhoneForm{}), user.ResetPasswdByPhonePost) m.Get("/forgot_password", user.ForgotPasswd) m.Post("/forgot_password", user.ForgotPasswdPost) m.Post("/logout", user.SignOut) @@ -1090,6 +1105,16 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, repo.CloudBrainTrainJobNew) m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate) }) + m.Group("/inference-job", func() { + m.Group("/:jobid", func() { + m.Get("", reqRepoCloudBrainReader, repo.InferenceCloudBrainJobShow) + m.Get("/result_download", cloudbrain.AdminOrJobCreaterRightForTrain, repo.CloudBrainDownloadInferenceResult) + + m.Get("/downloadall", repo.DownloadInferenceResultFile) + }) + m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, repo.InferenceCloudBrainJobNew) + m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainInferencForm{}), repo.CloudBrainInferenceJobCreate) + }) }, context.RepoRef()) m.Group("/grampus", func() { m.Group("/train-job", func() { @@ -1111,19 +1136,26 @@ func RegisterRoutes(m *macaron.Macaron) { }, context.RepoRef()) m.Group("/modelmanage", func() { m.Post("/create_model", reqRepoModelManageWriter, repo.SaveModel) + m.Post("/create_model_convert", reqRepoModelManageWriter, repo.SaveModelConvert) m.Post("/create_new_model", repo.SaveNewNameModel) 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.Get("/show_model", reqRepoModelManageReader, repo.ShowModelTemplate) + m.Get("/convert_model", reqRepoModelManageReader, repo.ConvertModelTemplate) 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_api", repo.ShowModelPageInfo) m.Get("/show_model_child_api", repo.ShowOneVersionOtherModel) 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_model_for_predict", reqRepoModelManageReader, repo.QueryModelListForPredict) m.Get("/query_modelfile_for_predict", reqRepoModelManageReader, repo.QueryModelFileForPredict) m.Get("/query_onelevel_modelfile", reqRepoModelManageReader, repo.QueryOneLevelModelFile) + m.Get("/download_model_convert/:id", reqRepoModelManageReader, repo.ModelConvertDownloadModel) m.Group("/:ID", func() { m.Get("", repo.ShowSingleModel) m.Get("/downloadsingle", repo.DownloadSingleModelFile) diff --git a/routers/user/auth.go b/routers/user/auth.go index 1edc5a0dd..7cd6472ff 100755 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -8,9 +8,19 @@ package user import ( "errors" "fmt" + "github.com/gomodule/redigo/redis" "net/http" + "strconv" "strings" + "code.gitea.io/gitea/modules/slideimage" + + phoneService "code.gitea.io/gitea/services/phone" + + "code.gitea.io/gitea/modules/labelmsg" + + "code.gitea.io/gitea/modules/phone" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/auth/oauth2" @@ -38,16 +48,18 @@ const ( tplSignIn base.TplName = "user/auth/signin" // tplSignIn template for sign in page tplSignInCloudBrain base.TplName = "user/auth/signin_cloud_brain" + tplSignInPhone base.TplName = "user/auth/signin_phone" // tplSignUp template path for sign up page tplSignUp base.TplName = "user/auth/signup" // TplActivate template path for activate user - TplActivate base.TplName = "user/auth/activate" - tplForgotPassword base.TplName = "user/auth/forgot_passwd" - tplResetPassword base.TplName = "user/auth/reset_passwd" - tplTwofa base.TplName = "user/auth/twofa" - tplTwofaScratch base.TplName = "user/auth/twofa_scratch" - tplLinkAccount base.TplName = "user/auth/link_account" - tplU2F base.TplName = "user/auth/u2f" + TplActivate base.TplName = "user/auth/activate" + tplForgotPassword base.TplName = "user/auth/forgot_passwd" + tplForgotPasswordPhone base.TplName = "user/auth/forgot_passwd_phone" + tplResetPassword base.TplName = "user/auth/reset_passwd" + tplTwofa base.TplName = "user/auth/twofa" + tplTwofaScratch base.TplName = "user/auth/twofa_scratch" + tplLinkAccount base.TplName = "user/auth/link_account" + tplU2F base.TplName = "user/auth/u2f" ) // AutoSignIn reads cookie and try to auto-login. @@ -168,7 +180,7 @@ func SignInCloudBrain(ctx *context.Context) { return } - ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login" + ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login/cloud_brain" ctx.Data["PageIsSignIn"] = true ctx.Data["PageIsCloudBrainLogin"] = true ctx.Data["EnableCloudBrain"] = true @@ -176,6 +188,50 @@ func SignInCloudBrain(ctx *context.Context) { ctx.HTML(200, tplSignInCloudBrain) } +func SignInPhone(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("sign_in") + // Check auto-login. + if checkAutoLogin(ctx) { + return + } + + ctx.Data["PageIsPhoneLogin"] = true + + ctx.HTML(200, tplSignInPhone) +} + +func SignInPhonePost(ctx *context.Context, form auth.PhoneNumberCodeForm) { + ctx.Data["Title"] = ctx.Tr("sign_in") + ctx.Data["PageIsPhoneLogin"] = true + ctx.Data["IsCourse"] = ctx.QueryBool("course") + ctx.Data["EnableCloudBrain"] = true + + if ctx.HasError() { + ctx.HTML(200, tplSignInPhone) + return + } + + if !phoneService.IsVerifyCodeRight(strings.TrimSpace(form.PhoneNumber), strings.TrimSpace(form.VerifyCode)) { + ctx.RenderWithErr(ctx.Tr("phone.verify_code_fail"), tplSignInPhone, &form) + return + } + + u, err := models.GetUserByPhoneNumber(strings.TrimSpace(form.PhoneNumber)) + + if err != nil { + if models.IsErrUserNotExist(err) { + ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignInPhone, &form) + log.Info("Failed authentication attempt for %s from %s", form.PhoneNumber, ctx.RemoteAddr()) + } else { + ctx.ServerError("UserSignIn", err) + } + return + } + models.SaveLoginInfoToDb(ctx.Req.Request, u) + + handleSignIn(ctx, u, form.Remember) +} + func SignInPostAPI(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("sign_in") UserName := ctx.Query("UserName") @@ -211,8 +267,7 @@ func SignInPostAPI(ctx *context.Context) { handleSignInFullNotRedirect(ctx, u, true, false) } -// SignInPost response for sign in request -func SignInPost(ctx *context.Context, form auth.SignInForm) { +func SignInPostCommon(ctx *context.Context, form auth.SignInForm) { ctx.Data["Title"] = ctx.Tr("sign_in") orderedOAuth2Names, oauth2Providers, err := models.GetActiveOAuth2Providers() @@ -223,11 +278,12 @@ func SignInPost(ctx *context.Context, form auth.SignInForm) { ctx.Data["OrderedOAuth2Names"] = orderedOAuth2Names ctx.Data["OAuth2Providers"] = oauth2Providers ctx.Data["Title"] = ctx.Tr("sign_in") - ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login" + ctx.Data["PageIsSignIn"] = true - ctx.Data["PageIsLogin"] = true + ctx.Data["IsCourse"] = ctx.QueryBool("course") ctx.Data["EnableSSPI"] = models.IsSSPIEnabled() + ctx.Data["EnableCloudBrain"] = true if ctx.HasError() { ctx.HTML(200, tplSignIn) @@ -256,7 +312,9 @@ func SignInPost(ctx *context.Context, form auth.SignInForm) { ctx.HTML(200, "user/auth/prohibit_login") } } else { - ctx.ServerError("UserSignIn", err) + log.Warn("UserSignIn", err) + ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form) + log.Info("Failed authentication attempt for %s from %s", form.UserName, ctx.RemoteAddr()) } return } @@ -294,6 +352,20 @@ func SignInPost(ctx *context.Context, form auth.SignInForm) { ctx.Redirect(setting.AppSubURL + "/user/two_factor") } + +func SignInCloudBrainPost(ctx *context.Context, form auth.SignInForm) { + ctx.Data["PageIsCloudBrainLogin"] = true + ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login/cloud_brain" + SignInPostCommon(ctx,form) +} + +// SignInPost response for sign in request +func SignInPost(ctx *context.Context, form auth.SignInForm) { + ctx.Data["PageIsLogin"] = true + ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login" + SignInPostCommon(ctx,form) +} + // TwoFactor shows the user a two-factor authentication page. func TwoFactor(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("twofa") @@ -1252,11 +1324,26 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo return } + if setting.PhoneService.Enabled { + phoneNumber := strings.TrimSpace(form.PhoneNumber) + verifyCode := strings.TrimSpace(form.VerifyCode) + if !phoneService.IsVerifyCodeRight(phoneNumber, verifyCode) { + ctx.RenderWithErr(ctx.Tr("phone.verify_code_fail"), tplSignUp, &form) + return + } + } + + if !form.Agree { + ctx.RenderWithErr(ctx.Tr("sign_up_agree_tips"), tplSignUp, &form) + return + } + u := &models.User{ - Name: form.UserName, - Email: form.Email, - Passwd: form.Password, - IsActive: !setting.Service.RegisterEmailConfirm, + Name: form.UserName, + Email: form.Email, + Passwd: form.Password, + PhoneNumber: strings.TrimSpace(form.PhoneNumber), + IsActive: !setting.Service.RegisterEmailConfirm, } if err := models.CreateUser(u); err != nil { switch { @@ -1427,18 +1514,30 @@ func ActivateEmail(ctx *context.Context) { // ForgotPasswd render the forget pasword page func ForgotPasswd(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("auth.forgot_password_title") + forgetType := ctx.Query("type") - if setting.MailService == nil { - ctx.Data["IsResetDisable"] = true - ctx.HTML(200, tplForgotPassword) - return - } + if forgetType == "phone" { + if !setting.PhoneService.Enabled { + ctx.Data["IsResetDisable"] = true + ctx.HTML(200, tplForgotPasswordPhone) + return + } + ctx.Data["IsResetRequest"] = true + ctx.HTML(200, tplForgotPasswordPhone) + } else { - email := ctx.Query("email") - ctx.Data["Email"] = email + if setting.MailService == nil { + ctx.Data["IsResetDisable"] = true + ctx.HTML(200, tplForgotPassword) + return + } - ctx.Data["IsResetRequest"] = true - ctx.HTML(200, tplForgotPassword) + email := ctx.Query("email") + ctx.Data["Email"] = email + + ctx.Data["IsResetRequest"] = true + ctx.HTML(200, tplForgotPassword) + } } // ForgotPasswdPost response for forget password request @@ -1454,12 +1553,16 @@ func ForgotPasswdPost(ctx *context.Context) { email := ctx.Query("email") ctx.Data["Email"] = email - u, err := models.GetUserByEmail(email) + u, err := models.GetUserByMainEmail(email) if err != nil { if models.IsErrUserNotExist(err) { ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale.Language()) - ctx.Data["IsResetSent"] = true - ctx.HTML(200, tplForgotPassword) + ctx.Data["IsResetSent"] = false + if used, _ := models.IsEmailUsed(email); used { + ctx.RenderWithErr(ctx.Tr("auth.email_not_main"), tplForgotPassword, nil) + } else { + ctx.RenderWithErr(ctx.Tr("auth.email_not_right"), tplForgotPassword, nil) + } return } @@ -1647,6 +1750,55 @@ func ResetPasswdPost(ctx *context.Context) { handleSignInFull(ctx, u, remember, true) } +func ResetPasswdByPhonePost(ctx *context.Context, form auth.ResetPassWordByPhoneForm) { + phoneNumber := strings.TrimSpace(form.PhoneNumber) + verifyCode := strings.TrimSpace(form.VerifyCode) + isRight := phoneService.IsVerifyCodeRight(phoneNumber, verifyCode) + if !isRight { + ctx.RenderWithErr(ctx.Tr("phone.verify_code_fail"), tplForgotPasswordPhone, form) + return + } + + passwd := strings.TrimSpace(form.Password) + if len(passwd) < setting.MinPasswordLength { + ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplForgotPasswordPhone, form) + return + } else if !password.IsComplexEnough(passwd) { + ctx.RenderWithErr(password.BuildComplexityError(ctx), tplForgotPasswordPhone, form) + return + } + + u, err := models.GetUserByPhoneNumber(phoneNumber) + if err != nil { + log.Error("fail to query by phone number", err) + ctx.RenderWithErr(ctx.Tr("phone.query_err", setting.MinPasswordLength), tplForgotPasswordPhone, form) + return + } + + if nil != ctx.User && u.ID != ctx.User.ID { + ctx.RenderWithErr(ctx.Tr("auth.reset_password_wrong_user", ctx.User.Email, u.Email), tplForgotPasswordPhone, form) + return + } + + if u.Rands, err = models.GetUserSalt(); err != nil { + ctx.ServerError("UpdateUser", err) + return + } + if u.Salt, err = models.GetUserSalt(); err != nil { + ctx.ServerError("UpdateUser", err) + return + } + u.HashPassword(passwd) + u.MustChangePassword = false + if err := models.UpdateUserCols(u, "must_change_password", "passwd", "rands", "salt"); err != nil { + ctx.ServerError("UpdateUser", err) + return + } + + handleSignInFull(ctx, u, form.Remember, true) + +} + // MustChangePassword renders the page to change a user's password func MustChangePassword(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("auth.must_change_password") @@ -1709,3 +1861,135 @@ func MustChangePasswordPost(ctx *context.Context, cpt *captcha.Captcha, form aut ctx.Redirect(setting.AppSubURL + "/") } + +func CreateSlideImageInfo(ctx *context.Context, slideImage *slideimage.SlideImage) { + id, _, _ := slideImage.CreateCode() + ctx.JSON(http.StatusOK, models.BaseMessage{0, id}) +} + +func VerifySlideImage(ctx *context.Context, slideImage *slideimage.SlideImage, form auth.SlideImageForm) { + if slideImage.Verify(form.SlideID, form.X) { + ctx.JSON(http.StatusOK, models.BaseOKMessage) + } else { + ctx.JSON(http.StatusOK, models.BaseErrorMessage("")) + } +} + +func BindPhone(ctx *context.Context, form auth.PhoneNumberCodeForm) { + if strings.TrimSpace(form.PhoneNumber) != "" && strings.TrimSpace(form.VerifyCode) != "" && phoneService.IsVerifyCodeRight(strings.TrimSpace(form.PhoneNumber), strings.TrimSpace(form.VerifyCode)) { + + ctx.User.PhoneNumber = strings.TrimSpace(form.PhoneNumber) + if err := models.UpdateUserSetting(ctx.User); err != nil { + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.bind_phone_fail"))) + return + } + ctx.JSON(http.StatusOK, models.BaseOKMessage) + return + } + + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.verify_code_fail"))) + +} + +func SendVerifyCode(ctx *context.Context, slideImage *slideimage.SlideImage, form auth.PhoneNumberForm) { + phoneNumber := strings.TrimSpace(form.PhoneNumber) + + if !phone.IsValidPhoneNumber(phoneNumber) { + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.format_err"))) + return + } + + hasManual, err := slideImage.VerifyManual(form.SlideID) + if err != nil { + log.Warn("redis err", err) + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.query_err"))) + return + + } + if !hasManual { + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.query_err"))) + return + } + + if form.Mode != 2 { + has, err := models.IsUserByPhoneNumberExist(phoneNumber) + if err != nil { + log.Warn("sql err", err) + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.query_err"))) + return + } + + if form.Mode==0 { //注册 + + if has { + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.already_register"))) + return + } + } else { //手机号验证码登录 mode=1 忘记密码 mode=3 + if !has { + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.not_register"))) + return + } + + } + + } else { + //修改手机号 mode=2 绑定手机 + u, err := models.GetUserByPhoneNumber(phoneNumber) + if err != nil && !models.IsErrUserNotExist(err) { + log.Warn("sql err", err) + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.query_err"))) + return + } + + if u != nil { + + if u.ID == ctx.User.ID { //没有修改手机号 + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.not_modify"))) + return + } else { //修改的手机已经被别的用户注册 + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.already_register"))) + return + } + + } + } + + + redisConn := labelmsg.Get() + defer redisConn.Close() + + sendTimes, err := phoneService.GetPhoneNumberSendTimes(redisConn, phoneNumber) + if err != nil && err!=redis.ErrNil { + log.Warn("redis err", err) + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.query_err"))) + return + + } + if sendTimes >= setting.PhoneService.MaxRetryTimes { + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.max_times", strconv.Itoa(setting.PhoneService.MaxRetryTimes)))) + return + + } + + ttl, err := phoneService.GetPhoneCodeTTL(redisConn, phoneNumber) + if err != nil { + log.Warn("redis err", err) + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.query_err"))) + return + + } + if setting.PhoneService.CodeTimeout-ttl < setting.PhoneService.RetryInterval { + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.too_fast"))) + return + } + err = phoneService.SendVerifyCode(redisConn, phoneNumber) + if err != nil { + log.Warn("send code or redis err", err) + ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.query_err"))) + return + } + + ctx.JSON(http.StatusOK, models.BaseOKMessage) + +} diff --git a/routers/user/setting/profile.go b/routers/user/setting/profile.go index 3333a8cc4..de1ba3144 100755 --- a/routers/user/setting/profile.go +++ b/routers/user/setting/profile.go @@ -11,6 +11,8 @@ import ( "io/ioutil" "strings" + phoneService "code.gitea.io/gitea/services/phone" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/base" @@ -89,6 +91,18 @@ func ProfilePost(ctx *context.Context, form auth.UpdateProfileForm) { return } + if setting.PhoneService.Enabled && strings.TrimSpace(form.PhoneNumber) != "" { + if strings.TrimSpace(form.PhoneNumber) != ctx.User.PhoneNumber { + if phoneService.IsVerifyCodeRight(strings.TrimSpace(form.PhoneNumber), strings.TrimSpace(form.VerifyCode)) { + ctx.User.PhoneNumber = strings.TrimSpace(form.PhoneNumber) + } else { + ctx.Flash.Error(ctx.Tr("phone.verify_code_fail")) + ctx.Redirect(setting.AppSubURL + "/user/settings") + return + } + } + } + ctx.User.FullName = form.FullName ctx.User.KeepEmailPrivate = form.KeepEmailPrivate diff --git a/services/phone/phone.go b/services/phone/phone.go new file mode 100644 index 000000000..cc0cf1976 --- /dev/null +++ b/services/phone/phone.go @@ -0,0 +1,93 @@ +package phone + +import ( + "fmt" + "time" + + "code.gitea.io/gitea/modules/log" + + "code.gitea.io/gitea/modules/phone" + "code.gitea.io/gitea/modules/redis/redis_client" + "code.gitea.io/gitea/modules/setting" + + "github.com/gomodule/redigo/redis" +) + +//验证码存储前缀 使用时%s用手机号替代 +const CODE_PREFIX = "P_C:%s" + +//手机号发送验证码次数Hkey,%s对应日期, 存储在hset中,值是hashet,记录手机号和发送次数 +const TIMES_PREFIX = "P_T:%s" + +func GetPhoneNumberSendTimes(conn redis.Conn, phoneNumber string) (int, error) { + i, err := redis_client.HGET(conn, GetPhoneTimesHKey(), phoneNumber) + + return redis.Int(i, err) +} + +func GetPhoneCodeTTL(conn redis.Conn, phoneNumber string) (int, error) { + return redis_client.Ttl(conn, GetPhoneCodeKey(phoneNumber)) + +} +func SendVerifyCode(conn redis.Conn, phoneNumber string) error { + timesKey := GetPhoneTimesHKey() + exists, err := redis_client.EXISTS(conn, timesKey) + if err != nil { + return err + } + code := phone.GenerateVerifyCode(setting.PhoneService.VerifyCodeLength) + err = phone.SendVerifyCode(phoneNumber, code) + if err != nil { + return err + } + redis_client.SET(conn, GetPhoneCodeKey(phoneNumber), code, setting.PhoneService.CodeTimeout) + if !exists { + err = redis_client.HSETNX(conn, timesKey, phoneNumber, 1) + if err != nil { + return err + } + err = redis_client.Expire(conn, timesKey, getRemainSecondOfDay(time.Now())) + if err != nil { + return err + } + + } else { + err = redis_client.HINCRBY(conn, timesKey, phoneNumber, 1) + + if err != nil { + return err + } + + } + return nil + +} + +func IsVerifyCodeRight(phoneNumer string, verifyCode string) bool { + if phoneNumer == "" { + return false + } + value, err := redis_client.Get(GetPhoneCodeKey(phoneNumer)) + if err != nil { + log.Warn("redis err", err) + return false + } else { + if value == "" { + return false + } + return value == verifyCode + } +} + +func GetPhoneCodeKey(phoneNumber string) string { + return fmt.Sprintf(CODE_PREFIX, phoneNumber) +} + +func GetPhoneTimesHKey() string { + today := time.Now().Format("2006-01-02") + return fmt.Sprintf(TIMES_PREFIX, today) +} + +func getRemainSecondOfDay(t time.Time) int { + return 86400 - 60*60*t.Hour() - 60*t.Minute() - t.Second() +} diff --git a/templates/admin/cloudbrain/list.tmpl b/templates/admin/cloudbrain/list.tmpl index 347b5658d..e66f40e84 100755 --- a/templates/admin/cloudbrain/list.tmpl +++ b/templates/admin/cloudbrain/list.tmpl @@ -204,7 +204,7 @@ {{else}} {{$.i18n.Tr "repo.stop"}} @@ -212,7 +212,7 @@
      • {{$.CsrfTokenHtml}} {{.i18n.Tr "admin.users.name"}}
        + @@ -35,6 +36,7 @@ + diff --git a/templates/base/footer.tmpl b/templates/base/footer.tmpl index 802854716..53f78dc1a 100755 --- a/templates/base/footer.tmpl +++ b/templates/base/footer.tmpl @@ -51,23 +51,63 @@ {{end}} diff --git a/templates/custom/select_dataset_train.tmpl b/templates/custom/select_dataset_train.tmpl index a6ad0d873..27730cf16 100755 --- a/templates/custom/select_dataset_train.tmpl +++ b/templates/custom/select_dataset_train.tmpl @@ -1,19 +1,20 @@
        - {{if or (.benchmarkMode) (.newInference)}} + + {{if .benchmarkMode}}{{.i18n.Tr "repo.modelarts.infer_job.select_model"}}{{else}}{{.i18n.Tr "dataset.select_dataset"}}{{end}} {{if .benchmarkMode}} - 说明:先使用数据集功能上传模型,然后从数据集列表选模型。 + 说明:先使用数据集功能上传模型,然后从数据集列表选模型。 {{end}}
        diff --git a/templates/custom/wait_count.tmpl b/templates/custom/wait_count.tmpl new file mode 100644 index 000000000..bef8f1327 --- /dev/null +++ b/templates/custom/wait_count.tmpl @@ -0,0 +1,27 @@ +
        + {{$queue := ""}} + {{$gpuQueue := 0}} + {{range $k,$v :=.gpu_types}} + {{if eq $k 0}} + {{ $queue = $v.Queue }} + {{ end }} + {{ end }} + {{ range $k,$v :=.QueuesDetail }} + {{if eq $k $queue}} + {{$gpuQueue =$v}} + {{ end }} + {{ end }} + + {{.i18n.Tr "repo.wait_count_start"}} + {{if .QueuesDetail}} + {{ $gpuQueue }} + {{else}} + {{.WaitCount}} + {{ end }} + {{.i18n.Tr "repo.wait_count_end"}} +
        diff --git a/templates/custom/wait_count_train.tmpl b/templates/custom/wait_count_train.tmpl new file mode 100644 index 000000000..fcfadc5be --- /dev/null +++ b/templates/custom/wait_count_train.tmpl @@ -0,0 +1,28 @@ +
        + {{$queue := ""}} + {{$gpuQueue := 0}} + {{range $k,$v :=.type}} + {{if eq $k 0}} + {{ $queue = $v.Queue }} + {{ end }} + {{ end }} + + {{ range $k,$v :=.ctx.QueuesDetail }} + {{if eq $k $queue}} + {{$gpuQueue =$v}} + {{ end }} + {{ end }} + + {{.ctx.i18n.Tr "repo.wait_count_start"}} + {{if .type}} + {{ $gpuQueue }} + {{else}} + {{.ctx.WaitCount}} + {{ end }} + {{.ctx.i18n.Tr "repo.wait_count_end"}} +
        diff --git a/templates/home.tmpl b/templates/home.tmpl index 36210d336..b90b20a28 100755 --- a/templates/home.tmpl +++ b/templates/home.tmpl @@ -94,12 +94,6 @@
        -
        @@ -129,13 +123,13 @@ -
        +
        -
        +
        diff --git a/templates/privacy.tmpl b/templates/privacy.tmpl new file mode 100644 index 000000000..81ecb199a --- /dev/null +++ b/templates/privacy.tmpl @@ -0,0 +1,92 @@ +{{template "base/head_home" .}} + +
        +

        OpenI启智社区AI协作平台隐私协议

        +
        +

        + OpenI启智社区AI协作平台作为新一代人工智能领域开源开放开发协作平台,不仅为用户提供代码托管与数据集管理等服务,同时提供开发者所需的计算算力资源,一个良好的开发环境对用户、组织和项目都尤为重要。 +

        +

        + 为切实保护平台用户隐私权,优化用户体验,OpenI启智社区根据现行法规及政策,制定本《OpenI启智社区AI协作平台隐私协议》。本协议将详细说明OpenI启智社区AI协作平台在获取、管理及保护用户个人信息方面的政策及措施。本协议适用于OpenI启智社区AI协作平台向您提供的所有服务,无论您是通过计算机设备、移动终端或其他设备获得本平台的服务。 +

        +

        + 一、个人信息的收集 +

        +

        + 您已知悉且同意,在您注册本平台帐号或使用平台提供的服务时,本平台将记录您提供的相关个人信息,如:账号ID、密码、邮箱、手机号码等,上述个人信息是您获得平台提供服务的基础。 +

        +

        + 在您使用本平台前,我们会引导您阅读本协议,并在您接受本协议的基础上,获得您的相关个人信息。如果您不同意提供个人信息,您将无法使用本平台的全部或部分功能和服务。 +

        +

        + 二、个人信息的存储 +

        +

        + 本平台会采取合适的安全措施和技术手段存储及保护您的个人信息,以防止丢失、被误用、受到未授权访问或泄漏、被篡改或毁坏。您的个人信息存放在有密码控制的位于中国境内的服务器中,访问均是受到限制的。 +

        +

        + 根据本条款的规定,我们仅允许有必要知晓这些信息的平台员工等第三方访问个人信息,并要求他们履行相应的保密义务。 +

        +

        + 三、个人信息的管理 +

        +

        + 在完成平台账号注册并进行身份验证后,您可以查阅、修改、删除所提交的个人信息。一般情况下,您可随时浏览、修改、删除自己提交的信息,但出于安全性和身份识别的考虑,您可能无法修改注册时提供的某些初始注册信息及验证信息。 +

        +

        + 您有权自主更新或更正您的个人信息,或授权本平台工作人员进行信息更新、更正。在您进行信息更新或更正之前,我们会首先验证您的身份。 +

        +

        + 您可以自主注销本平台账号,注销后本平台不再收集您的个人信息,注销账号是不可逆的行为,一旦完成注销,本平台将删除有关您账户的一切信息。 +

        +

        + 四、个人信息的保护 +

        +

        + 本平台将尽一切合理努力保护其获得的用户个人信息。为防止用户个人信息在意外的、未经授权的情况下被非法访问、复制、修改、传送、遗失、破坏、处理或使用,本平台已经并将继续采取以下措施保护您的个人信息:
        +

        +
          +
        1. 以适当的方式对用户的个人信息进行加密护理,并通过隔离技术进行隔离;
        2. +
        3. 在适当的位置使用密码对用户个人信息进行保护;
        4. +
        5. 设立严格的数据使用和访问制度,采用严格的数据访问权限控制保护个人信息;
        6. +
        7. 其他合理措施。
        8. +
        +

        + 尽管已经采取了上述合理有效措施,并遵守相关法律规定要求的标准,但本平台仍然无法保证您的个人信息通过不安全途径进行交流时的安全性。因此,用户个人应采取积极措施保证个人信息的安全,如:定期修改账号密码,不将自己的账号密码等个人信息透露给他人。 +

        +

        + 您知悉,本平台提供的个人信息保护措施仅适用于OpenI启智社区AI协作平台,一旦您离开本平台,浏览或使用其他网站、服务及内容资源,本平台即没有能力及义务保护您在本平台以外的网站提交的任何个人信息,无论您登录或浏览上述网站是否基于本平台的链接或引导。 +

        +

        + 五、个人信息的使用和对外提供 +

        +

        + 未经您本人允许,平台不会向任何第三方公开您的个人信息,下列情形除外: +

        +
          +
        1. 本平台已经取得您或您监护人的授权或同意;
        2. +
        3. 司法机关或行政机关基于法定程序要求平台披露的;
        4. +
        5. 本平台为维护自身合法权益而向用户提起诉讼或仲裁时;
        6. +
        7. 根据您与本平台相关服务条款、应用许可使用协议的约定;
        8. +
        9. 在法律允许的范围内,为保障本平台、平台用户以及社会公共利益免受损害时;
        10. +
        11. 法律法规规定的其他情形。
        12. +
        +

        + 六、对未成年人个人信息的特别保护 +

        +

        + 本平台非常重视对未成年人个人信息的保护。若您是18周岁以下的未成年人,在使用本平台的服务前,应确保事先取得监护人的同意,如您在平台上申请注册账号,本平台将默认为您已得到前述同意。本平台将根据国家相关法律法规及本协议的规定保护未成年人的个人信息。 +

        +

        + 七、隐私协议的修改 +

        +

        + 平台有权随时修改《OpenI启智社区AI协作平台隐私协议》的任何条款,一旦《OpenI启智社区AI协作平台隐私协议》内容发生变动,本平台将会在OpenI启智社区网站首页公告上公布修改后的政策,该公布行为视为本平台已经通知您修改内容。如果您不同意本平台对《OpenI启智社区AI协作平台隐私协议》相关条款所做的修改,您有权停止使用平台服务。如果您继续使用平台服务,则视为您接受平台对协议相关条款所做的修改。 +

        + +
        +{{template "base/footer" .}} diff --git a/templates/repo/cloudbrain/benchmark/index.tmpl b/templates/repo/cloudbrain/benchmark/index.tmpl index 8ded073b0..c6283e2e1 100755 --- a/templates/repo/cloudbrain/benchmark/index.tmpl +++ b/templates/repo/cloudbrain/benchmark/index.tmpl @@ -64,7 +64,7 @@
        -
        +
        {{$.i18n.Tr "repo.cloudbrain_task"}} diff --git a/templates/repo/cloudbrain/benchmark/new.tmpl b/templates/repo/cloudbrain/benchmark/new.tmpl index 76a4e5f0c..fb1296d27 100755 --- a/templates/repo/cloudbrain/benchmark/new.tmpl +++ b/templates/repo/cloudbrain/benchmark/new.tmpl @@ -10,11 +10,9 @@ padding-left: 3rem !important; } - .min_title { + .min_title{ font-size: 14px !important; - padding-left: 6rem !important; margin-bottom: 2rem !important; - } .width81 { @@ -56,25 +54,26 @@ {{.CsrfTokenHtml}} -
        - +
        -
        - +
        + - {{.i18n.Tr "cloudbrain.job_name_rule"}} + {{.i18n.Tr "cloudbrain.job_name_rule"}}
        -
        -
        -
        - +
        +
        -
        +
        - +   @@ -136,7 +135,8 @@ {{end}}
        -
        +
        + @@ -149,27 +149,28 @@ {{.CsrfTokenHtml}} -
        - +
        + + {{template "custom/wait_count_train" Dict "ctx" $ "type" .benchmark_gpu_types}}
        -
        - +
        + - {{.i18n.Tr "cloudbrain.job_name_rule"}} + {{.i18n.Tr "cloudbrain.job_name_rule"}}
        -
        - +
        +
        -
        - +
        +
        -
        - {{else}} - {{$.i18n.Tr "repo.modelarts.status"}}: diff --git a/templates/repo/cloudbrain/inference/new.tmpl b/templates/repo/cloudbrain/inference/new.tmpl new file mode 100644 index 000000000..223fcfe1c --- /dev/null +++ b/templates/repo/cloudbrain/inference/new.tmpl @@ -0,0 +1,480 @@ +{{template "base/head" .}} + +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        + {{template "repo/header" .}} +
        + {{template "base/alert" .}} + +

        + {{.i18n.Tr "repo.modelarts.train_job.new_infer"}} +

        +
        + + + {{.CsrfTokenHtml}} + + + + {{if $.model_version}} + + {{else}} + + {{end}} + {{if $.label_names}} + + {{else}} + + {{end}} +

        {{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:

        +
        + + + {{template "custom/wait_count_train" Dict "ctx" $ "type" .inference_gpu_types}} +
        +
        + + + {{.i18n.Tr "cloudbrain.job_name_rule"}} +
        + +
        + + +
        +
        + + +

        {{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}:

        +
        +
        + + +
        +
        + +
        +
        + + +
        + +
        + +
        + +
        + +
        + + +
        + +
        + + +
        + + {{template "custom/select_dataset_train" .}} + +
        + + {{if .bootFile}} + + {{else}} + + {{end}} + + + + {{.i18n.Tr "cloudbrain.view_sample"}} +
        + + +
        + + {{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}} + +
        + {{if ne 0 (len .params)}} + {{range $k ,$v := .params}} +
        +
        + +
        +
        + +
        + + + + +
        + {{end}} + {{end}} +
        +
        + + + +
        + + +
        + + +
        + + + {{.i18n.Tr "repo.cloudbrain.cancel"}} +
        + + +
        +
        +
        +{{template "base/footer" .}} + + diff --git a/templates/repo/cloudbrain/inference/show.tmpl b/templates/repo/cloudbrain/inference/show.tmpl new file mode 100644 index 000000000..00ad25644 --- /dev/null +++ b/templates/repo/cloudbrain/inference/show.tmpl @@ -0,0 +1,604 @@ +{{template "base/head" .}} + +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        + {{template "repo/header" .}} +
        +

        + +

        + {{with .task}} +
        + +
        +
        +
        + + + +
        + {{TimeSinceUnix1 .CreatedUnix}} + + {{$.i18n.Tr "repo.modelarts.status"}}: + {{.Status}} + + {{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}: + {{$.duration}} + + +
        +
        +
        +
        +
        +
        +
        {{.i18n.Tr "email"}} {{.i18n.Tr "admin.users.activated"}}{{.i18n.Tr "admin.users.bind_phone"}} {{.i18n.Tr "admin.users.admin"}} {{.i18n.Tr "admin.users.restricted"}} {{.i18n.Tr "admin.users.repos"}}{{.Name}} {{.NumRepos}}{{TimeSinceUnix1 .StartTime}}{{TimeSinceUnix1 .CreatedUnix}} - - {{end}} + {{TimeSinceUnix1 .CreatedUnix}}
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + {{$.i18n.Tr "repo.cloudbrain_task"}} + +
        + {{.DisplayJobName}} +
        +
        + {{$.i18n.Tr "repo.modelarts.status"}} + +
        + {{.Status}} +
        +
        + {{$.i18n.Tr "repo.modelarts.train_job.start_time"}} + +
        + + {{if not (eq .StartTime 0)}} + {{TimeSinceUnix1 .StartTime}} + {{else}} + -- + {{end}} + +
        +
        + {{$.i18n.Tr "repo.modelarts.train_job.dura_time"}} + +
        + {{.TrainJobDuration}} +
        +
        + {{$.i18n.Tr "repo.modelarts.train_job.resource_type"}} + +
        + {{$.resource_type}} +
        +
        + {{$.i18n.Tr "repo.model.manage.description"}} + +
        + {{if .Description}} + {{.Description}} + {{else}} + -- + {{end}} +
        +
        + 创建人 + +
        + {{.User.Name}} +
        +
        + {{$.i18n.Tr "cloudbrain.mirror"}} + +
        + {{.Image}} +
        +
        +
        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + {{$.i18n.Tr "repo.modelarts.infer_job_model"}} + +
        + {{.ModelName}}   + {{$.i18n.Tr "repo.modelarts.version"}}:{{.ModelVersion}}   + +
        +
        + {{$.i18n.Tr "repo.modelarts.infer_job_model_file"}} + +
        + {{.CkptName}} +
        +
        + {{$.i18n.Tr "repo.modelarts.model_label"}} + +
        + {{if .LabelName}} + {{range $.LabelName}} + {{.}} + {{end}} + {{else}} + -- + {{end}} +
        +
        + {{$.i18n.Tr "repo.modelarts.code_version"}} + +
        + {{.BranchName}} +
        +
        + {{$.i18n.Tr "repo.modelarts.train_job.start_file"}} + +
        + {{.BootFile}} +
        +
        + {{$.i18n.Tr "repo.modelarts.infer_dataset"}} + +
        + {{.DatasetName}} +
        +
        + {{$.i18n.Tr "repo.modelarts.train_job.run_parameter"}} + +
        + {{if .Parameters}} + {{.Parameters}} + {{else}} + -- + {{end}} +
        +
        + {{$.i18n.Tr "repo.modelarts.train_job.standard"}} + +
        + {{$.i18n.Tr "cloudbrain.gpu_num"}}:{{$.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{$.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{$.MemMiB}},{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{$.ShareMemMiB}} +
        +
        +
        + + + + + + +
        +
        + +
        + + + + + +
        + +
        + +
        + + + +
        + + + +
        + +
        +
        + + + + + + {{end}} + + + +{{template "base/footer" .}} + + \ No newline at end of file diff --git a/templates/repo/cloudbrain/new.tmpl b/templates/repo/cloudbrain/new.tmpl index 295fe0435..f0538261d 100755 --- a/templates/repo/cloudbrain/new.tmpl +++ b/templates/repo/cloudbrain/new.tmpl @@ -121,7 +121,7 @@ {{template "repo/header" .}}
        - + {{template "base/alert" .}}

        @@ -154,6 +154,7 @@ Ascend NPU
        + {{template "custom/wait_count" .}}
        @@ -208,7 +209,7 @@
        - {{range .train_gpu_types}} @@ -211,10 +212,6 @@
        - - - - 训练脚本存储在/code中,数据集存储在/dataset中,训练输出请存储在/model中以供后续下载。
        @@ -274,8 +271,6 @@ {{template "base/footer" .}} + + \ No newline at end of file diff --git a/templates/repo/modelarts/inferencejob/index.tmpl b/templates/repo/modelarts/inferencejob/index.tmpl index dc474ed7a..dac873e3d 100644 --- a/templates/repo/modelarts/inferencejob/index.tmpl +++ b/templates/repo/modelarts/inferencejob/index.tmpl @@ -39,8 +39,18 @@
        + {{if .Permission.CanWrite $.UnitTypeCloudBrain}} - {{$.i18n.Tr "repo.modelarts.train_job.new_infer"}} + {{$.i18n.Tr "repo.modelarts.train_job.new_infer"}} {{else}} {{$.i18n.Tr "repo.modelarts.train_job.new_infer"}} {{end}} @@ -72,28 +82,28 @@
        -
        +
        {{$.i18n.Tr "repo.cloudbrain_task"}}
        -
        +
        {{$.i18n.Tr "repo.modelarts.infer_job.model_version"}}
        -
        +
        {{$.i18n.Tr "repo.modelarts.status"}}
        -
        +
        {{$.i18n.Tr "repo.modelarts.createtime"}}
        -
        +
        {{$.i18n.Tr "repo.cloudbrain_status_runtime"}}
        - -
        +
        +
        {{$.i18n.Tr "repo.cloudbrain_creator"}}
        -
        +
        {{$.i18n.Tr "repo.cloudbrain_operate"}}
        @@ -104,37 +114,37 @@
        -
        - + -
        +
        {{.ModelName}}  {{.ModelVersion}}
        -
        - +
        + {{.Status}}
        -
        +
        {{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}
        -
        +
        {{.TrainJobDuration}}
        - +
        -
        +
        {{if .User.Name}} {{else}} @@ -142,8 +152,27 @@ {{end}}
        -
        +
        + {{if eq .Cloudbrain.Type 0 }} +
        +
        + {{$.CsrfTokenHtml}} + {{if .CanDel}} + + {{$.i18n.Tr "repo.stop"}} + + {{else}} + + {{$.i18n.Tr "repo.stop"}} + + {{end}} +
        +
        + {{else}}
        {{$.CsrfTokenHtml}} {{if .CanDel}} @@ -157,11 +186,12 @@ {{end}}
        + {{end}}
        {{$.CsrfTokenHtml}} {{if .CanModify}} - + {{$.i18n.Tr "repo.model_download"}} {{else}} @@ -174,9 +204,16 @@
        {{$.CsrfTokenHtml}} {{if .CanDel}} + {{if eq .Cloudbrain.Type 0 }} + + {{$.i18n.Tr "repo.delete"}} + + {{else}} {{$.i18n.Tr "repo.delete"}} + {{end}} + {{else}} {{$.i18n.Tr "repo.delete"}} @@ -237,3 +274,27 @@
        {{template "base/footer" .}} + + diff --git a/templates/repo/modelarts/inferencejob/new.tmpl b/templates/repo/modelarts/inferencejob/new.tmpl index 90a7c900d..89f4180c0 100644 --- a/templates/repo/modelarts/inferencejob/new.tmpl +++ b/templates/repo/modelarts/inferencejob/new.tmpl @@ -11,16 +11,18 @@ } .min_title{ font-size: 14px !important; - padding-left: 6rem !important; margin-bottom: 2rem !important; - } .width80{ width: 80.7% !important; } -.width84{ - width: 84% !important; - margin-left: 5.1rem !important; +.width{ + width:100% !important; +} +.width85 { + width: 85% !important; + margin-left: 10.5rem !important; + align-items: center; } .width35{ width: 35.5% !important; @@ -67,23 +69,46 @@ {{end}}

        {{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:

        -
        - + +
        + - {{.i18n.Tr "cloudbrain.job_name_rule"}} + {{.i18n.Tr "cloudbrain.job_name_rule"}}
        -
        -    +
        +   

        {{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}:

        -
        +
        -    + -
        -
        -       - {{range .engines}} - - {{end}} - -
        -
        - -
        +
        + +
        + + +
        +
        -
        -   +
        + {{else}} @@ -187,14 +215,14 @@
        -
        -    - {{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}} +
        + + {{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}
        {{if ne 0 (len .params)}} {{range $k ,$v := .params}} -
        +
        @@ -220,8 +248,8 @@
        -
        -         +
        +
        -
        - +
        +
        - {{.i18n.Tr "cloudbrain.inference_output_path_rule"}} + {{.i18n.Tr "cloudbrain.inference_output_path_rule"}}
        -
        +
        + @@ -252,13 +281,14 @@ {{template "base/footer" .}} diff --git a/templates/repo/modelarts/notebook/new.tmpl b/templates/repo/modelarts/notebook/new.tmpl index 4e2b3951d..6ab16f941 100755 --- a/templates/repo/modelarts/notebook/new.tmpl +++ b/templates/repo/modelarts/notebook/new.tmpl @@ -46,6 +46,7 @@ Ascend NPU
        + {{template "custom/wait_count" .}}
        diff --git a/templates/repo/modelarts/notebook/show.tmpl b/templates/repo/modelarts/notebook/show.tmpl index c36a5b104..7d49ace86 100755 --- a/templates/repo/modelarts/notebook/show.tmpl +++ b/templates/repo/modelarts/notebook/show.tmpl @@ -246,14 +246,8 @@
        - {{if not (eq .StartTime 0)}} - {{TimeSinceUnix1 .StartTime}} - {{else}} - {{TimeSinceUnix1 .CreatedUnix}} - - {{end}} + {{TimeSinceUnix1 .CreatedUnix}} - {{$.i18n.Tr "repo.modelarts.status"}}: - + {{$.i18n.Tr "repo.modelarts.train_job.dura_time"}} diff --git a/templates/repo/modelarts/trainjob/new.tmpl b/templates/repo/modelarts/trainjob/new.tmpl index 5022bd41b..e89482dc2 100755 --- a/templates/repo/modelarts/trainjob/new.tmpl +++ b/templates/repo/modelarts/trainjob/new.tmpl @@ -96,6 +96,7 @@
        +
        + {{template "custom/wait_count_train" Dict "ctx" $}}
        diff --git a/templates/repo/modelarts/trainjob/show.tmpl b/templates/repo/modelarts/trainjob/show.tmpl index 615fc3030..7a727cf4c 100755 --- a/templates/repo/modelarts/trainjob/show.tmpl +++ b/templates/repo/modelarts/trainjob/show.tmpl @@ -1,4 +1,5 @@ {{template "base/head" .}} +
        @@ -256,12 +270,14 @@ {{end}} {{if .CanDel}} - {{$.i18n.Tr "repo.stop"}} + data-jobid="{{.JobID}}" + data-repopath="{{$.RepoRelPath}}/modelarts/train-job" + data-version = "{{.VersionName}}" + >{{$.i18n.Tr "repo.stop"}} {{else}} - {{$.i18n.Tr "repo.stop"}} + {{$.i18n.Tr "repo.stop"}} {{end}} @@ -276,11 +292,8 @@
        - {{if not (eq .Cloudbrain.StartTime 0)}} - {{TimeSinceUnix1 .Cloudbrain.StartTime}} - {{else}} {{TimeSinceUnix1 .Cloudbrain.CreatedUnix}} - {{end}} + {{$.i18n.Tr "repo.modelarts.current_version"}}:{{.VersionName}} @@ -294,10 +307,9 @@ class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}: {{.TrainJobDuration}} - - + + +
        @@ -313,8 +325,7 @@ {{$.i18n.Tr "repo.modelarts.log"}} 资源占用情况 - {{$.i18n.Tr "repo.model_download"}} + {{$.i18n.Tr "repo.model_download"}}
        @@ -366,7 +377,7 @@ {{if not (eq .Cloudbrain.StartTime 0)}} {{TimeSinceUnix1 .Cloudbrain.StartTime}} {{else}} - {{TimeSinceUnix1 .Cloudbrain.CreatedUnix}} + -- {{end}}
        @@ -488,7 +499,7 @@
        +
        +
        +
        + +
        +
        + + +
        +
        {{template "base/footer" .}} + + + \ No newline at end of file diff --git a/templates/repo/modelarts/trainjob/version_new.tmpl b/templates/repo/modelarts/trainjob/version_new.tmpl index b7fcd36ad..886469d4c 100644 --- a/templates/repo/modelarts/trainjob/version_new.tmpl +++ b/templates/repo/modelarts/trainjob/version_new.tmpl @@ -446,24 +446,6 @@ ] }, - work_server_number: { - identifier : 'work_server_number', - rules: [ - { - type : 'integer[1..25]', - prompt : '计算节点需要在1-25之间,请您键入正确的值' - } - ] - }, - run_para_list:{ - identifier : 'run_para_list', - rules: [ - { - type: 'maxLength[255]', - prompt : '所有字符最长不超过255个字符。' - } - ] - }, }, }) @@ -512,24 +494,6 @@ ] }, - work_server_number: { - identifier : 'work_server_number', - rules: [ - { - type : 'integer[1..25]', - prompt : '计算节点需要在1-25之间,请您键入正确的值' - } - ] - }, - run_para_list:{ - identifier : 'run_para_list', - rules: [ - { - type: 'maxLength[255]', - prompt : '所有字符最长不超过255个字符。' - } - ] - }, }, onSuccess: function(){ // $('.ui.page.dimmer').dimmer('show') diff --git a/templates/repo/modelmanage/convertIndex.tmpl b/templates/repo/modelmanage/convertIndex.tmpl new file mode 100644 index 000000000..3dc3652c5 --- /dev/null +++ b/templates/repo/modelmanage/convertIndex.tmpl @@ -0,0 +1,586 @@ + +{{template "base/head" .}} + + +
        +
        +
        +
        +
        +
        +
        +
        +
        +{{$repository := .Repository.ID}} + +
        + +
        + {{template "repo/header" .}} + +
        + {{template "base/alert" .}} + + {{if eq .MODEL_CONVERT_COUNT 0}} +
        +
        +
        未创建过模型转换任务
        +
        + {{if eq .MODEL_COUNT 0}} +
        请您先导入模型,然后再对其进行转换。
        + {{end}} +
        使用说明:可以参考启智AI协作平台小白训练营课程。
        + +
        +
        + {{else}} + +
        +
        +
        + +
        + +
        +
        +
        + 任务名称 +
        +
        + 状态 +
        +
        + 原模型框架 +
        +
        + 转换后格式 +
        +
        + 创建时间 +
        +
        + {{$.i18n.Tr "repo.cloudbrain_creator"}} +
        +
        + {{$.i18n.Tr "repo.cloudbrain_operate"}} +
        +
        +
        + {{range .Tasks}} +
        +
        + +
        + + {{.Status}} + +
        +
        + {{if eq .SrcEngine 0}}PyTorch {{else if eq .SrcEngine 1}}TensorFlow{{else if eq .SrcEngine 2}}MindSpore {{end}} +
        +
        + {{if eq .DestFormat 0}}ONNX {{else if eq .DestFormat 1}}TensorRT {{end}} +
        +
        + {{TimeSinceUnix .CreatedUnix $.Lang}} +
        +
        + +
        +
        +
        + +
        + {{$.CsrfTokenHtml}} + {{if .IsCanDelete}} + + {{$.i18n.Tr "repo.stop"}} + + {{else}} + {{$.i18n.Tr "repo.stop"}} + {{end}} +
        + + +
        + {{$.CsrfTokenHtml}} + {{if .IsCanDelete}} + + {{$.i18n.Tr "repo.delete"}} + + {{else}} + {{$.i18n.Tr "repo.delete"}} + {{end}} +
        + + {{if .IsCanOper}} + + 下载 + + {{else}} + 下载 + {{end}} +
        +
        +
        +
        + {{end}} +
        +
        + + +
        +
        +
        +
        +
        +
        + {{end}} +
        + +
        + +
        + + +
        + +
        +
        + + +
        + + +{{template "base/footer" .}} + + + diff --git a/templates/repo/modelmanage/convertshowinfo.tmpl b/templates/repo/modelmanage/convertshowinfo.tmpl new file mode 100644 index 000000000..984b5944f --- /dev/null +++ b/templates/repo/modelmanage/convertshowinfo.tmpl @@ -0,0 +1,854 @@ +{{template "base/head" .}} + +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +{{template "repo/header" .}} +
        +

        + +

        + {{with .task}} +
        + +
        +
        +
        + + + +
        + {{TimeSinceUnix1 .CreatedUnix}} + + {{$.i18n.Tr "repo.modelarts.status"}}: + {{.Status}} + + {{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}: + {{.TrainJobDuration}} + +
        +
        +
        +
        +
        +
        +
        +
        + +
        +
        +
        +
        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + {{$.i18n.Tr "repo.cloudbrain_task"}} + +
        + {{.Name}} +
        +
        + {{$.i18n.Tr "repo.modelarts.status"}} + +
        + {{.Status}} +
        +
        + 输入张量形状 + +
        + {{.InputShape}} +
        +
        + 输入数据格式 + +
        + {{.InputDataFormat}} +
        +
        + {{$.i18n.Tr "repo.modelarts.train_job.start_time"}} + +
        + {{TimeSinceUnix1 .CreatedUnix}} +
        +
        + {{$.i18n.Tr "repo.modelarts.train_job.dura_time"}} + +
        + {{.TrainJobDuration}} +
        +
        + 网络输出数据类型 + +
        + {{if eq .NetOutputFormat 0}}FP32 {{else if eq .NetOutputFormat 1}}FP16 {{end}} +
        +
        +
        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + 模型名称 + +
        + {{.ModelName}} +
        +
        + 模型版本 + +
        + {{.ModelVersion}} +
        +
        + 模型文件 + +
        + {{.ModelPath}} +
        +
        + 原模型框架 + +
        + {{if eq .SrcEngine 0}}PyTorch {{else if eq .SrcEngine 1}}Tensorflow{{else if eq .SrcEngine 2}}MindSpore {{end}} +
        +
        + 转换后格式 + +
        + {{if eq .DestFormat 0}}ONNX {{else if eq .DestFormat 1}}TensorRT {{end}} +
        +
        + {{$.i18n.Tr "repo.modelarts.train_job.description"}} + +
        + {{.Description}} +
        +
        + {{$.i18n.Tr "repo.cloudbrain_creator"}} + +
        + {{.UserName}} +
        +
        +
        +
        +
        + +
        +
        + +
        +
        + +
        + + + + + +
        + +
        + +
        + +
        +
        + +
        + + +
        
        +                            
        + +
        + +
        + +
        +
        + + + + + + + +
        + + +
        
        +                            
        +
        +
        + +
        + + + +
        + +
        +
        + + + +
        +
        +
        + {{end}} {{template "base/paginate" .}} +
        + + + + +
        +{{template "base/footer" .}} + + \ No newline at end of file diff --git a/templates/repo/modelmanage/index.tmpl b/templates/repo/modelmanage/index.tmpl index d42cf1c86..b54fa5cfa 100644 --- a/templates/repo/modelmanage/index.tmpl +++ b/templates/repo/modelmanage/index.tmpl @@ -1,10 +1,33 @@ {{template "base/head" .}} + + +
        @@ -25,7 +48,12 @@
        {{template "base/alert" .}} +