init
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
package business
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"anytunnel/at-common"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"anytunnel/at-web/app/utils"
|
||||
)
|
||||
|
||||
type BusinessBase struct {
|
||||
|
||||
}
|
||||
|
||||
func NewBase() *BusinessBase {
|
||||
return &BusinessBase{}
|
||||
}
|
||||
|
||||
//Get Request Api
|
||||
func (this *BusinessBase) GetRequest(confKey string, urlQuerys map[string]string) (data interface{}, err error) {
|
||||
uri := beego.AppConfig.String(confKey)
|
||||
if(uri == "") {
|
||||
return data, fmt.Errorf("%s", "uri conf error")
|
||||
}
|
||||
query := utils.NewUrls().HttpQueryBuild(urlQuerys)
|
||||
body, code, err := at_common.HttpGet(uri + "?" + query)
|
||||
if(code != 200) {
|
||||
return data, fmt.Errorf("%s", "get httpcode error")
|
||||
}
|
||||
if(err != nil) {
|
||||
return data, err
|
||||
}
|
||||
var results map[string]interface{}
|
||||
json.Unmarshal(body, &results)
|
||||
if(results["code"].(float64) != 1) {
|
||||
return data, fmt.Errorf("%s", results["message"].(string))
|
||||
}
|
||||
return results["data"], nil
|
||||
}
|
||||
|
||||
//Post Request Api
|
||||
func (this *BusinessBase) PostRequest(confKey string, urlQuerys map[string]string, header map[string]string) (data interface{}, err error) {
|
||||
uri := beego.AppConfig.String(confKey)
|
||||
if(uri == "") {
|
||||
return data, fmt.Errorf("%s", "uri conf error")
|
||||
}
|
||||
body, code, err := at_common.HttpPost(uri, urlQuerys, header)
|
||||
if(code != 200) {
|
||||
return data, fmt.Errorf("%s", "httpcode error")
|
||||
}
|
||||
if(err != nil) {
|
||||
return data, err
|
||||
}
|
||||
var results map[string]interface{}
|
||||
json.Unmarshal(body, &results)
|
||||
if(results["code"].(float64) != 1) {
|
||||
return data, fmt.Errorf("%s", results["message"].(string))
|
||||
}
|
||||
return results["data"], nil
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"github.com/golang-collections/lib.go/validation/validator"
|
||||
"github.com/astaxie/beego"
|
||||
"anytunnel/at-web/app/utils"
|
||||
"anytunnel/at-web/app/business"
|
||||
)
|
||||
|
||||
type AuthorController struct {
|
||||
BaseUserController
|
||||
}
|
||||
|
||||
// login
|
||||
func (this *AuthorController) Login() {
|
||||
this.viewLayoutTitle("AnyTunnelCloud", "author/login", "login")
|
||||
}
|
||||
|
||||
// register
|
||||
func (this *AuthorController) Register() {
|
||||
this.viewLayoutTitle("AnyTunnelCloud", "author/register", "login")
|
||||
}
|
||||
|
||||
//register save
|
||||
func (this *AuthorController) Signin() {
|
||||
|
||||
username := strings.Trim(this.GetString("username"), "")
|
||||
password := strings.Trim(this.GetString("password"), "")
|
||||
email := strings.Trim(this.GetString("email"), "")
|
||||
|
||||
if(username == "") {
|
||||
this.jsonError("注册失败:用户名不能为空")
|
||||
}
|
||||
if(password == "") {
|
||||
this.jsonError("注册失败:密码不能为空")
|
||||
}
|
||||
if(email == "") {
|
||||
this.jsonError("注册失败:邮箱不能为空")
|
||||
}
|
||||
if(!validator.IsEmail(email)) {
|
||||
this.jsonError("注册失败:邮箱格式错误")
|
||||
}
|
||||
data := map[string]string{
|
||||
"username": username,
|
||||
"password": password,
|
||||
"email": email,
|
||||
}
|
||||
user, err := business.NewBase().PostRequest("create_user", data, nil);
|
||||
if(err != nil) {
|
||||
this.jsonError("注册失败")
|
||||
}
|
||||
userMap := user.(map[string]interface{})
|
||||
userId := utils.NewConvert().FloatToString(userMap["user_id"].(float64), 'f', 0, 64)
|
||||
//保存session和cookie
|
||||
this.refreshSession(userId)
|
||||
this.jsonSuccess("恭喜,注册成功", nil, "/user/index")
|
||||
}
|
||||
|
||||
//login save
|
||||
func (this *AuthorController) Signup() {
|
||||
|
||||
username := strings.Trim(this.GetString("username"), "")
|
||||
password := strings.Trim(this.GetString("password"), "")
|
||||
|
||||
if(username == "") {
|
||||
this.jsonError("登录失败:用户名不能为空")
|
||||
}
|
||||
if(password == "") {
|
||||
this.jsonError("登录失败:密码不能为空")
|
||||
}
|
||||
|
||||
data := map[string]string{
|
||||
"username":username,
|
||||
}
|
||||
user, err := business.NewBase().GetRequest("get_user_by_name", data)
|
||||
if(err != nil) {
|
||||
this.jsonError("登录失败:server error")
|
||||
}
|
||||
userMap := user.(map[string]interface{})
|
||||
if(len(userMap) == 0) {
|
||||
this.jsonError("登录失败:用户名不存在或密码错误")
|
||||
}
|
||||
if(userMap["is_forbidden"].(string) == "1") {
|
||||
this.jsonError("登录失败:该用户已被屏蔽")
|
||||
}
|
||||
if(userMap["password"].(string) != utils.NewEncrypt().Md5Encode(password)) {
|
||||
this.jsonError("登录失败:用户名或密码错误")
|
||||
}
|
||||
//保存session和cookie
|
||||
this.refreshSession(userMap["user_id"].(string))
|
||||
|
||||
this.jsonSuccess("恭喜,登录成功", nil, "/user/index")
|
||||
}
|
||||
|
||||
func (this *AuthorController) Logout() {
|
||||
passport := beego.AppConfig.String("login.passport")
|
||||
this.Ctx.SetCookie(passport, "")
|
||||
this.SetSession("user", nil)
|
||||
this.redirect("/");
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
type BaseController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *BaseController) viewLayoutTitle(title, viewName, layout string) {
|
||||
this.Layout = "layout/" + layout + ".html"
|
||||
this.TplName = viewName + ".html"
|
||||
this.Data["title"] = title
|
||||
this.Render()
|
||||
}
|
||||
func (this *BaseController) viewLayout(viewName, layout string) {
|
||||
this.Layout = "layout/" + layout + ".html"
|
||||
this.TplName = viewName + ".html"
|
||||
this.Data["title"] = ""
|
||||
this.Render()
|
||||
}
|
||||
func (this *BaseController) view(viewName string) {
|
||||
this.Layout = "layout/default.html"
|
||||
this.TplName = viewName + ".html"
|
||||
this.Data["title"] = ""
|
||||
this.Render()
|
||||
}
|
||||
func (this *BaseController) viewError(errorMessage string, data ...interface{}) {
|
||||
this.Layout = "layout/page.html"
|
||||
errorType := "500"
|
||||
if len(data) > 0 {
|
||||
errorType = data[0].(string)
|
||||
}
|
||||
this.TplName = "error/" + errorType + ".html"
|
||||
this.Data["title"] = "system error"
|
||||
this.Data["errorMessage"] = errorMessage
|
||||
this.Render()
|
||||
}
|
||||
func (this *BaseController) viewTitle(title, viewName string) {
|
||||
this.Layout = "layout/default.html"
|
||||
this.TplName = viewName + ".html"
|
||||
this.Data["title"] = title
|
||||
this.Render()
|
||||
}
|
||||
func (this *BaseController) jsonSuccess(message interface{}, data ...interface{}) {
|
||||
url := ""
|
||||
sleep := 500
|
||||
var _data interface{}
|
||||
if len(data) > 0 {
|
||||
_data = data[0]
|
||||
}
|
||||
if len(data) > 1 {
|
||||
url = data[1].(string)
|
||||
}
|
||||
if len(data) > 2 {
|
||||
sleep = data[2].(int)
|
||||
}
|
||||
|
||||
this.Data["json"] = JSONResponse{
|
||||
Code: 1,
|
||||
Message: message,
|
||||
Data: _data,
|
||||
Redirect: map[string]interface{}{
|
||||
"url": url,
|
||||
"sleep": sleep,
|
||||
},
|
||||
}
|
||||
//this.ServeJSON()
|
||||
j, err := json.MarshalIndent(this.Data["json"], "", "\t")
|
||||
if err != nil {
|
||||
this.Abort(err.Error())
|
||||
} else {
|
||||
this.Abort(string(j))
|
||||
}
|
||||
|
||||
}
|
||||
func (this *BaseController) jsonError(message interface{}, data ...interface{}) {
|
||||
url := ""
|
||||
sleep := 500
|
||||
var _data interface{}
|
||||
if len(data) > 0 {
|
||||
_data = data[0]
|
||||
}
|
||||
if len(data) > 1 {
|
||||
url = data[1].(string)
|
||||
}
|
||||
if len(data) > 2 {
|
||||
sleep = data[2].(int)
|
||||
}
|
||||
this.Data["json"] = JSONResponse{
|
||||
Code: 0,
|
||||
Message: message,
|
||||
Data: _data,
|
||||
Redirect: map[string]interface{}{
|
||||
"url": url,
|
||||
"sleep": sleep,
|
||||
},
|
||||
}
|
||||
j, err := json.MarshalIndent(this.Data["json"], "", " \t")
|
||||
if err != nil {
|
||||
this.Abort(err.Error())
|
||||
} else {
|
||||
this.Abort(string(j))
|
||||
}
|
||||
}
|
||||
|
||||
//获取用户IP地址
|
||||
func (this *BaseController) getClientIp() string {
|
||||
s := strings.Split(this.Ctx.Request.RemoteAddr, ":")
|
||||
return s[0]
|
||||
}
|
||||
|
||||
//302跳转
|
||||
func (this *BaseController) redirect(url string) {
|
||||
this.Redirect(url, 302)
|
||||
this.StopRun()
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"github.com/astaxie/beego"
|
||||
"anytunnel/at-web/app/utils"
|
||||
"anytunnel/at-web/app/business"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type JSONResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message interface{} `json:"message"`
|
||||
Data interface{} `json:"data"`
|
||||
Redirect map[string]interface{} `json:"redirect"`
|
||||
}
|
||||
type BaseUserController struct {
|
||||
BaseController
|
||||
loginUser map[string]interface{}
|
||||
controllerName string
|
||||
methodName string
|
||||
}
|
||||
|
||||
//验证登录
|
||||
func (this *BaseUserController) isLogin() bool {
|
||||
controllerName, actionName := this.GetControllerAndAction()
|
||||
this.controllerName = strings.ToLower(controllerName[0 : len(controllerName)-10])
|
||||
this.methodName = actionName
|
||||
//忽略 /author /error
|
||||
if(this.controllerName == "author" || this.controllerName == "error") {
|
||||
return true;
|
||||
}
|
||||
passport := beego.AppConfig.String("login.passport")
|
||||
cookie := this.Ctx.GetCookie(passport)
|
||||
//cookie 失效
|
||||
if(cookie == "") {
|
||||
return false
|
||||
}
|
||||
user := this.GetSession("user")
|
||||
//session 失效
|
||||
if(user == nil) {
|
||||
return false
|
||||
}
|
||||
cookieValue, _ := utils.NewEncrypt().Base64Decode(cookie)
|
||||
if(cookieValue == "") {
|
||||
return false
|
||||
}
|
||||
identifyList := strings.Split(cookieValue, "@")
|
||||
username := identifyList[0]
|
||||
identify := identifyList[1]
|
||||
userValue := user.(map[string]interface{})
|
||||
//对比cookie 和 session username
|
||||
if(username != userValue["username"].(string)) {
|
||||
return false
|
||||
}
|
||||
//对比客户端UAG and IP
|
||||
if(identify != utils.NewEncrypt().Md5Encode(this.Ctx.Request.UserAgent() + this.getClientIp() + userValue["password"].(string))) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.loginUser = userValue;
|
||||
//this.refreshSession()
|
||||
//success
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *BaseUserController) Prepare() {
|
||||
|
||||
if !this.isLogin() {
|
||||
this.Redirect("/author/login", 302)
|
||||
this.StopRun()
|
||||
}
|
||||
|
||||
this.Layout = "layout/default.html"
|
||||
}
|
||||
func (this *BaseUserController) checkAccess() {
|
||||
|
||||
}
|
||||
|
||||
//重置 session 和 cookie
|
||||
func (this *BaseUserController) refreshSession(userId string) {
|
||||
|
||||
data := map[string]string {
|
||||
"user_id" : userId,
|
||||
}
|
||||
user, err := business.NewBase().GetRequest("get_user_by_id", data)
|
||||
if(err != nil) {
|
||||
fmt.Println("重置session错误")
|
||||
}
|
||||
if(len(user.(map[string]interface{})) > 0) {
|
||||
username := user.(map[string]interface{})["username"].(string)
|
||||
password := user.(map[string]interface{})["password"].(string)
|
||||
//重置 session
|
||||
this.SetSession("user", user)
|
||||
//重置 cookie
|
||||
identify := utils.NewEncrypt().Md5Encode(this.Ctx.Request.UserAgent() + this.getClientIp() + password)
|
||||
passportValue := utils.NewEncrypt().Base64Encode(username + "@" + identify)
|
||||
passport := beego.AppConfig.String("login.passport")
|
||||
cookieTime := beego.AppConfig.String("login.cookie.time")
|
||||
this.Ctx.SetCookie(passport, passportValue, cookieTime)
|
||||
}
|
||||
this.loginUser = user.(map[string]interface{});
|
||||
}
|
||||
|
||||
//get user_id
|
||||
func (this *BaseUserController) getUserId() string {
|
||||
return this.loginUser["user_id"].(string)
|
||||
}
|
||||
|
||||
//get username
|
||||
func (this *BaseUserController) getUsername() string {
|
||||
return this.loginUser["username"].(string)
|
||||
}
|
||||
|
||||
//get email
|
||||
func (this *BaseUserController) getEmail() string {
|
||||
return this.loginUser["email"].(string)
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"anytunnel/at-web/app/utils"
|
||||
"strings"
|
||||
"anytunnel/at-web/app/business"
|
||||
)
|
||||
|
||||
type ClientController struct {
|
||||
BaseUserController
|
||||
}
|
||||
|
||||
func (this *ClientController) List() {
|
||||
|
||||
userId := this.getUserId()
|
||||
keyword := this.GetString("keyword")
|
||||
data := map[string]string {
|
||||
"user_id": userId,
|
||||
"keyword": keyword,
|
||||
}
|
||||
clientValues, err:= business.NewBase().GetRequest("client_list_uri", data)
|
||||
if(err != nil) {
|
||||
this.viewError("request error")
|
||||
}
|
||||
this.Data["clientValues"] = clientValues
|
||||
this.Data["keyword"] = keyword
|
||||
this.viewLayoutTitle("client列表", "client/list", "page")
|
||||
}
|
||||
|
||||
//add client
|
||||
func (this *ClientController) Add() {
|
||||
this.Data["clientValue"] = map[string]string{
|
||||
"client_id": "0",
|
||||
"name": "",
|
||||
"token": "",
|
||||
}
|
||||
this.viewLayoutTitle("添加client", "client/form", "page")
|
||||
}
|
||||
|
||||
//save client
|
||||
func (this *ClientController) Save() {
|
||||
|
||||
name := strings.Trim(this.GetString("name"), "");
|
||||
|
||||
data := map[string]string {
|
||||
"name": name,
|
||||
"token": utils.NewMisc().RandString(32),
|
||||
"user_id": this.getUserId(),
|
||||
}
|
||||
_, err := business.NewBase().PostRequest("client_create_uri", data, nil)
|
||||
if(err != nil) {
|
||||
this.jsonError(err.Error())
|
||||
}
|
||||
|
||||
this.jsonSuccess("添加Client成功", nil, "/client/list");
|
||||
}
|
||||
|
||||
//edit client
|
||||
func (this *ClientController) Edit() {
|
||||
|
||||
clientId := this.GetString("client_id")
|
||||
if(clientId == "") {
|
||||
this.viewError("client_id error")
|
||||
}
|
||||
|
||||
data := map[string]string{
|
||||
"client_id":clientId,
|
||||
}
|
||||
clientValues, err:= business.NewBase().GetRequest("client_info_uri", data)
|
||||
if(err != nil) {
|
||||
this.viewError(err.Error())
|
||||
}
|
||||
|
||||
this.Data["clientValue"] = clientValues
|
||||
this.viewLayoutTitle("修改client", "client/form", "page")
|
||||
}
|
||||
|
||||
//save client
|
||||
func (this *ClientController) Modify() {
|
||||
|
||||
name := this.GetString("name");
|
||||
clientId := this.GetString("client_id");
|
||||
|
||||
data := map[string]string{
|
||||
"name": name,
|
||||
"client_id":clientId,
|
||||
}
|
||||
_, err := business.NewBase().PostRequest("client_update_uri", data, nil)
|
||||
if(err != nil) {
|
||||
this.jsonError(err.Error())
|
||||
}
|
||||
this.jsonSuccess("修改Client成功", nil, "/client/list");
|
||||
}
|
||||
|
||||
//delete client
|
||||
func (this *ClientController) Delete() {
|
||||
|
||||
clientId := this.GetString("client_id")
|
||||
data := map[string]string{
|
||||
"client_id": clientId,
|
||||
}
|
||||
_, err := business.NewBase().GetRequest("client_delete_uri", data)
|
||||
if(err != nil) {
|
||||
this.jsonError(err.Error())
|
||||
}
|
||||
this.jsonSuccess("删除client成功", nil, "client/list")
|
||||
}
|
||||
|
||||
//reset token
|
||||
func (this *ClientController) ResetToken() {
|
||||
|
||||
clientId := this.GetString("client_id");
|
||||
|
||||
data := map[string]string{
|
||||
"token": utils.NewMisc().RandString(32),
|
||||
"client_id": clientId,
|
||||
}
|
||||
_, err := business.NewBase().PostRequest("client_update_uri", data, nil)
|
||||
if(err != nil) {
|
||||
this.jsonError(err.Error())
|
||||
}
|
||||
|
||||
this.jsonSuccess("重置Token成功", nil, "/client/list");
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package controllers
|
||||
|
||||
type MainController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
func (this *MainController) Index() {
|
||||
isLogin := "1"
|
||||
if(this.GetSession("user") == nil) {
|
||||
isLogin = "0"
|
||||
}
|
||||
this.Data["isLogin"] = isLogin
|
||||
this.viewLayoutTitle("AnyTunnelCloud", "web/index", "index")
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"anytunnel/at-web/app/utils"
|
||||
"strings"
|
||||
"anytunnel/at-web/app/business"
|
||||
)
|
||||
|
||||
type ServerController struct {
|
||||
BaseUserController
|
||||
}
|
||||
|
||||
func (this *ServerController) List() {
|
||||
|
||||
userId := this.getUserId()
|
||||
keyword := this.GetString("keyword")
|
||||
data := map[string]string {
|
||||
"user_id": userId,
|
||||
"keyword": keyword,
|
||||
}
|
||||
serverValues, err:= business.NewBase().GetRequest("server_list_uri", data)
|
||||
if(err != nil) {
|
||||
this.viewError("request error")
|
||||
}
|
||||
this.Data["serverValues"] = serverValues
|
||||
this.Data["keyword"] = keyword
|
||||
this.viewLayoutTitle("server列表", "server/list", "page")
|
||||
}
|
||||
|
||||
//add server
|
||||
func (this *ServerController) Add() {
|
||||
this.Data["serverValue"] = map[string]string{
|
||||
"server_id": "0",
|
||||
"name": "",
|
||||
"token": "",
|
||||
}
|
||||
this.viewLayoutTitle("添加server", "server/form", "page")
|
||||
}
|
||||
|
||||
//save server
|
||||
func (this *ServerController) Save() {
|
||||
|
||||
name := strings.Trim(this.GetString("name"), "");
|
||||
|
||||
data := map[string]string {
|
||||
"name": name,
|
||||
"token": utils.NewMisc().RandString(32),
|
||||
"user_id": this.getUserId(),
|
||||
}
|
||||
_, err := business.NewBase().PostRequest("server_create_uri", data, nil)
|
||||
if(err != nil) {
|
||||
this.jsonError(err.Error())
|
||||
}
|
||||
|
||||
this.jsonSuccess("添加Server成功", nil, "/server/list");
|
||||
}
|
||||
|
||||
//edit server
|
||||
func (this *ServerController) Edit() {
|
||||
|
||||
serverId := this.GetString("server_id")
|
||||
if(serverId == "") {
|
||||
this.viewError("server_id error")
|
||||
}
|
||||
|
||||
data := map[string]string{
|
||||
"server_id":serverId,
|
||||
}
|
||||
serverValues, err:= business.NewBase().GetRequest("server_info_uri", data)
|
||||
if(err != nil) {
|
||||
this.viewError(err.Error())
|
||||
}
|
||||
|
||||
this.Data["serverValue"] = serverValues
|
||||
this.viewLayoutTitle("修改server", "server/form", "page")
|
||||
}
|
||||
|
||||
//save server
|
||||
func (this *ServerController) Modify() {
|
||||
|
||||
name := this.GetString("name");
|
||||
serverId := this.GetString("server_id");
|
||||
|
||||
data := map[string]string{
|
||||
"name": name,
|
||||
"server_id":serverId,
|
||||
}
|
||||
_, err := business.NewBase().PostRequest("server_update_uri", data, nil)
|
||||
if(err != nil) {
|
||||
this.jsonError(err.Error())
|
||||
}
|
||||
this.jsonSuccess("修改Server成功", nil, "/server/list");
|
||||
}
|
||||
|
||||
//delete server
|
||||
func (this *ServerController) Delete() {
|
||||
|
||||
serverId := this.GetString("server_id")
|
||||
data := map[string]string{
|
||||
"server_id": serverId,
|
||||
}
|
||||
_, err := business.NewBase().GetRequest("server_delete_uri", data)
|
||||
if(err != nil) {
|
||||
this.jsonError(err.Error())
|
||||
}
|
||||
this.jsonSuccess("删除server成功", nil, "server/list")
|
||||
}
|
||||
|
||||
//reset token
|
||||
func (this *ServerController) ResetToken() {
|
||||
|
||||
serverId := this.GetString("server_id");
|
||||
|
||||
data := map[string]string{
|
||||
"token": utils.NewMisc().RandString(32),
|
||||
"server_id": serverId,
|
||||
}
|
||||
_, err := business.NewBase().PostRequest("server_update_uri", data, nil)
|
||||
if(err != nil) {
|
||||
this.jsonError(err.Error())
|
||||
}
|
||||
|
||||
this.jsonSuccess("重置Token成功", nil, "/server/list");
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"anytunnel/at-web/app/business"
|
||||
"strings"
|
||||
"anytunnel/at-web/app/utils"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const MODE_BASE = "0"
|
||||
const MODE_SENIOR = "1"
|
||||
const MODE_SPECIAL = "2"
|
||||
|
||||
type TunnelController struct {
|
||||
BaseUserController
|
||||
}
|
||||
|
||||
//tunnel list
|
||||
func (this *TunnelController) List() {
|
||||
|
||||
userId := this.getUserId()
|
||||
keyword := this.GetString("keyword")
|
||||
data := map[string]string {
|
||||
"user_id" : userId,
|
||||
"keyword" : keyword,
|
||||
}
|
||||
tunnelValues, err := business.NewBase().GetRequest("tunnel_list_uri", data)
|
||||
if(err != nil) {
|
||||
this.viewError("request error")
|
||||
}
|
||||
this.Data["tunnelValues"] = tunnelValues
|
||||
this.Data["keyword"] = keyword
|
||||
this.viewLayoutTitle("隧道列表", "tunnel/list", "page")
|
||||
}
|
||||
|
||||
//tunnel add 1. tunnel mode
|
||||
func (this *TunnelController) Mode() {
|
||||
|
||||
userId := this.getUserId()
|
||||
data := map[string]string{
|
||||
"user_id": userId,
|
||||
}
|
||||
roles, err := business.NewBase().GetRequest("get_user_role", data)
|
||||
if(err != nil) {
|
||||
this.viewError("request error " + err.Error())
|
||||
}
|
||||
modeBase := "0"
|
||||
modeSenior := "0"
|
||||
modeSpecial := "0"
|
||||
for _, role := range roles.([]interface{}) {
|
||||
role := role.(map[string]interface{})
|
||||
tunnelMode := strings.Split(role["tunnel_mode"].(string), ",")
|
||||
for _, tunnel := range tunnelMode {
|
||||
if(tunnel == MODE_BASE) {
|
||||
modeBase = "1"
|
||||
}
|
||||
if(tunnel == MODE_SENIOR) {
|
||||
modeSenior = "1"
|
||||
}
|
||||
if(tunnel == MODE_SPECIAL) {
|
||||
modeSpecial = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["modeBase"] = modeBase
|
||||
this.Data["modeSenior"] = modeSenior
|
||||
this.Data["modeSpecial"] = modeSpecial
|
||||
//获取所有的 server
|
||||
this.viewLayoutTitle("选择模式", "tunnel/mode", "page")
|
||||
}
|
||||
|
||||
//tunnel add 2. tunnel cluster
|
||||
func (this *TunnelController) Cluster() {
|
||||
|
||||
clusterId := this.GetString("cluster_id", "");
|
||||
mode := this.GetString("mode", "0");
|
||||
|
||||
data := map[string]string{
|
||||
"user_id": this.getUserId(),
|
||||
"mode": mode,
|
||||
}
|
||||
regionClusters, err := business.NewBase().GetRequest("user_cluster_list",data)
|
||||
if(err != nil) {
|
||||
this.viewError("request error " + err.Error())
|
||||
}
|
||||
this.Data["regionClusters"] = regionClusters
|
||||
this.Data["clusterId"] = clusterId
|
||||
this.Data["mode"] = mode
|
||||
this.viewLayoutTitle("选择节点", "tunnel/cluster", "page")
|
||||
}
|
||||
|
||||
//tunnel add 2. tunnel add
|
||||
func (this *TunnelController) Add() {
|
||||
|
||||
if(this.Ctx.Request.Method != "POST") {
|
||||
this.viewError("request error")
|
||||
}
|
||||
clusterId := this.GetString("cluster_id", "");
|
||||
mode := this.GetString("mode", "0");
|
||||
if(clusterId == "") {
|
||||
this.viewError("没有选择节点")
|
||||
}
|
||||
|
||||
isHaveClient := "0"
|
||||
isHaveServer := "0"
|
||||
//基础模式,只能部署client
|
||||
if(mode == MODE_BASE) {
|
||||
isHaveClient = "1"
|
||||
}
|
||||
//高级模式,只能部署client和server
|
||||
if(mode == MODE_SENIOR) {
|
||||
isHaveClient = "1"
|
||||
isHaveServer = "1"
|
||||
}
|
||||
//特殊模式,只能部署server
|
||||
if(mode == MODE_SPECIAL) {
|
||||
isHaveServer = "1"
|
||||
}
|
||||
|
||||
userId := this.getUserId()
|
||||
data := map[string]string{
|
||||
"user_id": userId,
|
||||
}
|
||||
clientValues := []interface{}{}
|
||||
serverValues := []interface{}{}
|
||||
systemClients := []interface{}{}
|
||||
systemServers := []interface{}{}
|
||||
systemServer := map[string]interface{}{}
|
||||
systemClient := map[string]interface{}{}
|
||||
|
||||
//获取系统在线client
|
||||
res, _ := business.NewBase().GetRequest("online_client_by_clusterId", map[string]string{
|
||||
"cluster_id": clusterId,
|
||||
})
|
||||
if(res != nil) {
|
||||
systemClients = res.([]interface{})
|
||||
}
|
||||
|
||||
//获取系统在线server
|
||||
res, _ = business.NewBase().GetRequest("online_server_by_clusterId", map[string]string{
|
||||
"cluster_id": clusterId,
|
||||
})
|
||||
if(res != nil) {
|
||||
systemClients = res.([]interface{})
|
||||
}
|
||||
|
||||
if(isHaveClient == "1") {
|
||||
res, _ := business.NewBase().GetRequest("client_list_uri", data)
|
||||
clientValues = res.([]interface{})
|
||||
//存在,取交集
|
||||
if(len(systemClients) > 0) {
|
||||
for index, clientValue := range clientValues {
|
||||
for _, systemClient := range systemClients {
|
||||
if(clientValue.(map[string]interface{})["client_id"].(string) == systemClient.(map[string]interface{})["cs_id"].(string)) {
|
||||
clientValues = append(clientValues[:index], clientValues[index+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}else {
|
||||
//随机获取一个系统 client
|
||||
systemClient = utils.NewMisc().RandSlice(systemClients).(map[string]interface{})
|
||||
}
|
||||
if(isHaveServer == "1") {
|
||||
res, _ := business.NewBase().GetRequest("server_list_uri", data)
|
||||
serverValues = res.([]interface{})
|
||||
//存在,取交集
|
||||
if(len(systemServers) > 0) {
|
||||
for index, serverValue := range serverValues {
|
||||
for _, systemServer := range systemServers {
|
||||
if(serverValue.(map[string]string)["client_id"] == systemServer.(map[string]string)["cs_id"]) {
|
||||
serverValues = append(serverValues[:index], serverValues[index+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}else {
|
||||
//随机获取一个系统 server
|
||||
systemServer = utils.NewMisc().RandSlice(systemServers).(map[string]interface{})
|
||||
}
|
||||
|
||||
this.Data["isHaveClient"] = isHaveClient
|
||||
this.Data["isHaveServer"] = isHaveServer
|
||||
this.Data["clientValues"] = clientValues
|
||||
this.Data["serverValues"] = serverValues
|
||||
this.Data["systemClient"] = systemClient
|
||||
this.Data["systemServer"] = systemServer
|
||||
this.Data["clusterId"] = clusterId
|
||||
this.Data["mode"] = mode
|
||||
//获取所有的 server
|
||||
this.viewLayoutTitle("添加隧道", "tunnel/form", "page")
|
||||
}
|
||||
|
||||
func (this *TunnelController) Save() {
|
||||
|
||||
if(this.Ctx.Request.Method != "POST") {
|
||||
this.viewError("request error")
|
||||
}
|
||||
|
||||
name := this.GetString("name", "");
|
||||
serverId := this.GetString("server_id", "");
|
||||
serverListenIp := this.GetString("server_listen_ip", "");
|
||||
serverListenPort := this.GetString("server_listen_port", "");
|
||||
clientId := this.GetString("client_id", "");
|
||||
clientLocalHost := this.GetString("client_local_host", "");
|
||||
clientLocalPort := this.GetString("client_local_port", "");
|
||||
mode := this.GetString("mode", "0");
|
||||
clusterId := this.GetString("cluster_id", "0");
|
||||
userId := this.getUserId()
|
||||
|
||||
data := map[string]string{
|
||||
"name": strings.Trim(name, ""),
|
||||
"server_id": strings.Trim(serverId, ""),
|
||||
"server_listen_ip": strings.Trim(serverListenIp, ""),
|
||||
"server_listen_port": strings.Trim(serverListenPort, ""),
|
||||
"client_id": strings.Trim(clientId, ""),
|
||||
"client_local_host": strings.Trim(clientLocalHost, ""),
|
||||
"client_local_port": strings.Trim(clientLocalPort, ""),
|
||||
"mode": mode,
|
||||
"user_id": userId,
|
||||
"protocol": "1",
|
||||
"cluster_id": clusterId,
|
||||
}
|
||||
|
||||
res, err := business.NewBase().PostRequest("tunnel_create_uri", data, nil)
|
||||
if(err != nil) {
|
||||
this.jsonError(err.Error())
|
||||
}
|
||||
|
||||
fmt.Println(res)
|
||||
this.jsonSuccess("添加隧道成功", nil, "/tunnel/list")
|
||||
}
|
||||
|
||||
//启动隧道
|
||||
func (this *TunnelController) Open() {
|
||||
|
||||
tunnelId := this.GetString("tunnel_id", "0");
|
||||
if(tunnelId == "0") {
|
||||
this.jsonError("tunnel_id error")
|
||||
}
|
||||
|
||||
data := map[string]string{
|
||||
"tunnel_id": tunnelId,
|
||||
}
|
||||
|
||||
_, err := business.NewBase().GetRequest("tunnel_open_uri", data)
|
||||
if(err != nil) {
|
||||
this.jsonError(err.Error())
|
||||
}
|
||||
|
||||
this.jsonSuccess("开启隧道成功", nil, "/tunnel/list")
|
||||
}
|
||||
|
||||
//关闭隧道
|
||||
func (this *TunnelController) Close() {
|
||||
|
||||
tunnelId := this.GetString("tunnel_id", "0");
|
||||
if(tunnelId == "0") {
|
||||
this.jsonError("tunnel_id error")
|
||||
}
|
||||
|
||||
data := map[string]string{
|
||||
"tunnel_id": tunnelId,
|
||||
}
|
||||
|
||||
_, err := business.NewBase().GetRequest("tunnel_close_uri", data)
|
||||
if(err != nil) {
|
||||
this.jsonError(err.Error())
|
||||
}
|
||||
|
||||
this.jsonSuccess("关闭隧道成功")
|
||||
}
|
||||
|
||||
//删除隧道
|
||||
func (this *TunnelController) Delete() {
|
||||
|
||||
tunnelId := this.GetString("tunnel_id", "0");
|
||||
if(tunnelId == "0") {
|
||||
this.jsonError("tunnel_id error")
|
||||
}
|
||||
|
||||
data := map[string]string{
|
||||
"tunnel_id": tunnelId,
|
||||
}
|
||||
|
||||
_, err := business.NewBase().GetRequest("tunnel_delete_uri", data)
|
||||
if(err != nil) {
|
||||
this.jsonError(err.Error())
|
||||
}
|
||||
|
||||
this.jsonSuccess("删除隧道成功")
|
||||
}
|
||||
|
||||
//重启隧道
|
||||
func (this *TunnelController) Refresh() {
|
||||
|
||||
tunnelId := this.GetString("tunnel_id", "0");
|
||||
if(tunnelId == "0") {
|
||||
this.jsonError("tunnel_id error")
|
||||
}
|
||||
|
||||
data := map[string]string{
|
||||
"tunnel_id": tunnelId,
|
||||
}
|
||||
|
||||
//关闭
|
||||
_, err := business.NewBase().GetRequest("tunnel_close_uri", data)
|
||||
if(err != nil) {
|
||||
this.jsonError(err.Error())
|
||||
}
|
||||
|
||||
//打开
|
||||
_, err = business.NewBase().GetRequest("tunnel_open_uri", data)
|
||||
if(err != nil) {
|
||||
this.jsonError(err.Error())
|
||||
}
|
||||
|
||||
this.jsonSuccess("重启隧道成功", nil, "/tunnel/list")
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
utils "anytunnel/at-common"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
type UserController struct {
|
||||
BaseUserController
|
||||
}
|
||||
|
||||
//user center
|
||||
func (this *UserController) Index() {
|
||||
this.Data["userValue"] = this.loginUser
|
||||
this.viewLayoutTitle("用户中心", "user/index", "user")
|
||||
}
|
||||
|
||||
//user welcome
|
||||
func (this *UserController) Welcome() {
|
||||
this.viewLayoutTitle("默认首页", "user/welcome", "page")
|
||||
}
|
||||
|
||||
//user profile
|
||||
func (this *UserController) Profile() {
|
||||
this.Data["userValue"] = this.loginUser
|
||||
this.viewLayoutTitle("默认首页", "user/profile", "page")
|
||||
}
|
||||
|
||||
//user password
|
||||
func (this *UserController) Password() {
|
||||
this.Data["userValue"] = this.loginUser
|
||||
this.viewLayoutTitle("默认首页", "user/password", "page")
|
||||
}
|
||||
|
||||
//user save
|
||||
func (this *UserController) Save() {
|
||||
|
||||
userId := strings.Trim(this.GetString("user_id"), "")
|
||||
nickname := strings.Trim(this.GetString("nickname"), "")
|
||||
|
||||
if userId == "" {
|
||||
this.jsonError("user_id error")
|
||||
}
|
||||
|
||||
updateUri := beego.AppConfig.String("user_update_uri")
|
||||
if updateUri == "" {
|
||||
this.jsonError("修改资料失败")
|
||||
}
|
||||
|
||||
data := map[string]string{
|
||||
"nickname": nickname,
|
||||
"user_id": userId,
|
||||
}
|
||||
body, code, err := utils.HttpPost(updateUri, data, nil)
|
||||
if code != 200 || err != nil {
|
||||
this.jsonError("修改资料失败")
|
||||
}
|
||||
var results map[string]interface{}
|
||||
json.Unmarshal(body, &results)
|
||||
if results["code"].(float64) != 1 {
|
||||
this.jsonError(results["message"].(string))
|
||||
}
|
||||
|
||||
//更新session和cookie
|
||||
this.refreshSession(userId)
|
||||
|
||||
this.jsonSuccess("修改资料成功", nil, "/user/profile")
|
||||
}
|
||||
|
||||
//user repass
|
||||
func (this *UserController) Repass() {
|
||||
|
||||
userId := strings.Trim(this.GetString("user_id"), "")
|
||||
oldPass := strings.Trim(this.GetString("old_pass"), "")
|
||||
newPass := strings.Trim(this.GetString("new_pass"), "")
|
||||
confirmPass := strings.Trim(this.GetString("confirm_pass"), "")
|
||||
|
||||
if userId == "" {
|
||||
this.jsonError("user_id error")
|
||||
}
|
||||
if oldPass == "" {
|
||||
this.jsonError("旧密码错误")
|
||||
}
|
||||
if utils.NewEncrypt().Md5Encode(oldPass) != this.loginUser["password"].(string) {
|
||||
this.jsonError("旧密码错误")
|
||||
}
|
||||
if newPass == "" {
|
||||
this.jsonError("新密码不能为空")
|
||||
}
|
||||
if confirmPass == "" {
|
||||
this.jsonError("确认密码不能为空")
|
||||
}
|
||||
if confirmPass != newPass {
|
||||
this.jsonError("确认密码和新密码不一致")
|
||||
}
|
||||
|
||||
updateUri := beego.AppConfig.String("user_update_uri")
|
||||
if updateUri == "" {
|
||||
this.jsonError("修改密码失败")
|
||||
}
|
||||
|
||||
data := map[string]string{
|
||||
"password": newPass,
|
||||
"user_id": userId,
|
||||
}
|
||||
body, code, err := utils.HttpPost(updateUri, data, nil)
|
||||
if code != 200 || err != nil {
|
||||
this.jsonError("修改密码失败")
|
||||
}
|
||||
var results map[string]interface{}
|
||||
json.Unmarshal(body, &results)
|
||||
if results["code"].(float64) != 1 {
|
||||
this.jsonError(results["message"].(string))
|
||||
}
|
||||
|
||||
//更新session和cookie
|
||||
this.refreshSession(userId)
|
||||
|
||||
this.jsonSuccess("修改密码成功", nil, "/user/password")
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
"anytunnel/at-web/app/controllers"
|
||||
"anytunnel/at-web/app/utils"
|
||||
"html/template"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
func init() {
|
||||
beego.AppConfig.Set("sys.name", "ATC")
|
||||
beego.AppConfig.Set("sys.fullname", "AnyTunnel Cloud")
|
||||
|
||||
beego.BConfig.ServerName = beego.AppConfig.String("sys.name")
|
||||
beego.SetStaticPath("/static/", "static")
|
||||
beego.BConfig.WebConfig.AutoRender = false
|
||||
beego.BConfig.WebConfig.Session.SessionName = "ssidw"
|
||||
beego.BConfig.WebConfig.Session.SessionOn = true
|
||||
beego.BConfig.RouterCaseSensitive = false
|
||||
beego.AutoRouter(&controllers.MainController{})
|
||||
beego.AutoRouter(&controllers.AuthorController{})
|
||||
beego.AutoRouter(&controllers.UserController{})
|
||||
beego.AutoRouter(&controllers.TunnelController{})
|
||||
beego.AutoRouter(&controllers.ClientController{})
|
||||
beego.AutoRouter(&controllers.ServerController{})
|
||||
beego.Router("/", &controllers.MainController{}, "*:Index")
|
||||
beego.AddFuncMap("randInt", randInt)
|
||||
beego.AddFuncMap("dateFormat", utils.NewDate().Format)
|
||||
beego.ErrorHandler("404", page_not_found)
|
||||
beego.ErrorHandler("500", page_not_found)
|
||||
beego.BConfig.WebConfig.ViewsPath = "app/views"
|
||||
}
|
||||
func page_not_found(rw http.ResponseWriter, r *http.Request) {
|
||||
t, _ := template.New("500-full.html").ParseFiles(beego.BConfig.WebConfig.ViewsPath + "/error/500-full.html")
|
||||
data := make(map[string]interface{})
|
||||
data["content"] = ""
|
||||
t.Execute(rw, data)
|
||||
}
|
||||
|
||||
func randInt(start, end int) int {
|
||||
return rand.Intn(end) + start
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package utils
|
||||
|
||||
import "strconv"
|
||||
|
||||
type Convert struct{}
|
||||
|
||||
func NewConvert() *Convert {
|
||||
return &Convert{}
|
||||
}
|
||||
|
||||
// bool 转化为字符串
|
||||
func (convert *Convert) BoolToString(boolValue bool) string {
|
||||
if boolValue == true {
|
||||
return "true"
|
||||
} else {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
|
||||
//bool 转化为 int
|
||||
func (convert *Convert) BoolToInt(boolValue bool) int {
|
||||
if boolValue == true {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
//int 转化为 bool
|
||||
func (convert *Convert) IntToBool(number int) bool {
|
||||
if number == 0 {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
//int 转化为字符串
|
||||
//base 范围 2-32 进制
|
||||
func (convert *Convert) IntToString(number int64, base int) string {
|
||||
return strconv.FormatInt(number, base)
|
||||
}
|
||||
|
||||
//string to int(10进制)
|
||||
func (convert *Convert) StringToInt(str string) int {
|
||||
intValue, _ := strconv.Atoi(str)
|
||||
return intValue
|
||||
}
|
||||
|
||||
// string to int64(10进制)
|
||||
func (convert *Convert) StringToInt64(str string) int64 {
|
||||
intValue, _ := strconv.ParseInt(str, 10, 64)
|
||||
return intValue
|
||||
}
|
||||
|
||||
//int 转化为10进制字符串 IntToString(number, 10)
|
||||
func (convert *Convert) IntToTenString(number int) string {
|
||||
return strconv.Itoa(number)
|
||||
}
|
||||
|
||||
// float 转化为字符串
|
||||
func (convert *Convert) FloatToString(f float64, fmt byte, prec, bitSize int) string {
|
||||
return strconv.FormatFloat(f, fmt, prec, bitSize)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Date struct{}
|
||||
|
||||
func NewDate() *Date {
|
||||
return &Date{}
|
||||
}
|
||||
|
||||
//格式化 unix 时间戳
|
||||
func (date *Date) Format(unixTime interface{}, format string) string {
|
||||
|
||||
convert := NewConvert();
|
||||
var convertTime int64
|
||||
|
||||
switch unixTime.(type) {
|
||||
case string:
|
||||
convertTime = convert.StringToInt64(unixTime.(string))
|
||||
case int:
|
||||
convertTime = int64(unixTime.(int))
|
||||
case int8:
|
||||
convertTime = int64(unixTime.(int8))
|
||||
case int16:
|
||||
convertTime = int64(unixTime.(int16))
|
||||
case int32:
|
||||
convertTime = int64(unixTime.(int32))
|
||||
}
|
||||
|
||||
return beego.Date(time.Unix(convertTime, 0), format);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
const (
|
||||
BASE_64_TABLE = "1234567890poiuytreqwasdfghjklmnbvcxzQWERTYUIOPLKJHGFDSAZXCVBNM-_"
|
||||
)
|
||||
|
||||
type Encrypt struct{}
|
||||
|
||||
func NewEncrypt() *Encrypt {
|
||||
return &Encrypt{}
|
||||
}
|
||||
|
||||
//base64 加密
|
||||
func (encrypt *Encrypt) Base64Encode(str string) string {
|
||||
var coder = base64.NewEncoding(BASE_64_TABLE)
|
||||
var src []byte = []byte(str)
|
||||
return string([]byte(coder.EncodeToString(src)))
|
||||
}
|
||||
|
||||
//base64 加密
|
||||
func (encrypt *Encrypt) Base64EncodeBytes(bytes []byte) []byte {
|
||||
var coder = base64.NewEncoding(BASE_64_TABLE)
|
||||
return []byte(coder.EncodeToString(bytes))
|
||||
}
|
||||
|
||||
//base64 解密
|
||||
func (encrypt *Encrypt) Base64Decode(str string) (string, error) {
|
||||
var src []byte = []byte(str)
|
||||
var coder = base64.NewEncoding(BASE_64_TABLE)
|
||||
by, err := coder.DecodeString(string(src))
|
||||
return string(by), err
|
||||
}
|
||||
|
||||
//base64 解密
|
||||
func (encrypt *Encrypt) Base64DecodeBytes(str string) ([]byte, error) {
|
||||
var coder = base64.NewEncoding(BASE_64_TABLE)
|
||||
return coder.DecodeString(str)
|
||||
}
|
||||
|
||||
//md5加密
|
||||
func (encrypt *Encrypt) Md5Encode(str string) string {
|
||||
hash := md5.New()
|
||||
hash.Write([]byte(str))
|
||||
return hex.EncodeToString(hash.Sum(nil))
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Misc struct{}
|
||||
|
||||
func NewMisc() *Misc {
|
||||
return &Misc{}
|
||||
}
|
||||
|
||||
func (m *Misc) RandString(strlen int) string {
|
||||
codes := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
codeLen := len(codes)
|
||||
data := make([]byte, strlen)
|
||||
rand.Seed(time.Now().UnixNano() + rand.Int63() + rand.Int63() + rand.Int63() + rand.Int63())
|
||||
for i := 0; i < strlen; i++ {
|
||||
idx := rand.Intn(codeLen)
|
||||
data[i] = byte(codes[idx])
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
|
||||
//根据slice随机返回其中一个元素
|
||||
func (m *Misc) RandSlice(slices []interface{}) interface{} {
|
||||
number := len(slices)
|
||||
rand.Seed(time.Now().Unix())
|
||||
idx := rand.Intn(number)
|
||||
return slices[idx]
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页方法
|
||||
* @param type $total 一共多少记录
|
||||
* @param type $page 当前是第几页
|
||||
* @param type $pagesize 每页多少
|
||||
* @param type $url url是什么,url里面的{page}会被替换成页码
|
||||
* @param array $order 分页条的组成,是一个数组,可以按着1-6的序号,选择分页条组成部分和每个部分的顺序
|
||||
* @param int $a_count 分页条中a页码链接的总数量,不包含当前页的a标签,默认10个。
|
||||
* @return type String
|
||||
* echo Sr::page(100,3,10,'?article/list/{page}',array(3,4,5,1,2,6));
|
||||
*/
|
||||
func (m *Misc) Page(total, page, pagesize int, url string, args ...interface{}) string {
|
||||
order := []int{1, 2, 3, 4, 5, 6}
|
||||
a_count := 10
|
||||
if len(args) >= 1 {
|
||||
order = args[0].([]int)
|
||||
}
|
||||
if len(args) >= 2 {
|
||||
a_count = args[1].(int)
|
||||
}
|
||||
a_num := a_count
|
||||
first := "首页"
|
||||
last := "尾页"
|
||||
pre := "上页"
|
||||
next := "下页"
|
||||
if a_num%2 == 0 {
|
||||
a_num++
|
||||
}
|
||||
pages := int(math.Ceil(float64(total) / float64(pagesize)))
|
||||
curpage := page
|
||||
if curpage > pages || curpage <= 0 {
|
||||
curpage = 1
|
||||
}
|
||||
body := `<span class="page_body">`
|
||||
prefix := ""
|
||||
subfix := ""
|
||||
start := curpage - ((a_num - 1) / 2)
|
||||
end := curpage + ((a_num - 1) / 2)
|
||||
if start <= 0 {
|
||||
start = 1
|
||||
}
|
||||
if end > pages {
|
||||
end = pages
|
||||
}
|
||||
if pages >= a_num {
|
||||
if curpage <= (a_num-1)/2 {
|
||||
end = a_num
|
||||
}
|
||||
if end-curpage <= (a_num-1)/2 {
|
||||
start -= int(math.Floor(float64(a_num)/float64(2))) - (end - curpage)
|
||||
}
|
||||
}
|
||||
for i := start; i <= end; i++ {
|
||||
if i == curpage {
|
||||
body += fmt.Sprintf(`<a class="page_cur_page" href="javascript:void(0);"><b>%d</b></a>`, i)
|
||||
} else {
|
||||
body += fmt.Sprintf(`<a href="%s">%d</a>`, strings.Replace(url, "{page}", fmt.Sprintf("%d", i), 1), i)
|
||||
|
||||
}
|
||||
}
|
||||
body += "</span>"
|
||||
if curpage > 1 {
|
||||
prefix = fmt.Sprintf(`<span class="page_bar_prefix"><a href="%s">%s</a><a href="%s">%s</a></span>`, strings.Replace(url, "{page}", fmt.Sprintf("%d", 1), 1), first, strings.Replace(url, "{page}", fmt.Sprintf("%d", curpage-1), 1), pre)
|
||||
}
|
||||
if curpage != pages {
|
||||
subfix = fmt.Sprintf(`<span class="page_bar_subfix"><a href="%s">%s</a><a href="%s">%s</a></span>`, strings.Replace(url, "{page}", fmt.Sprintf("%d", curpage+1), 1), next, strings.Replace(url, "{page}", fmt.Sprintf("%d", pages), 1), last)
|
||||
}
|
||||
info := fmt.Sprintf(`<span class="page_cur">第%d/%d页</span>`, curpage, pages)
|
||||
id := fmt.Sprintf("gsd09fhas9d%d%d%d", rand.Intn(1000), rand.Intn(1000), rand.Intn(1000))
|
||||
gostr := fmt.Sprintf(`<script>function ekup(){if(event.keyCode==13){clkyup();}}function clkyup(){var num=document.getElementById('%s').value;if(!/^\d+$/.test(num)||num<=0||num>%d){alert('请输入正确页码!');return;};location='%s'.replace(/\{page\}/,document.getElementById('%s').value);}</script><span class="page_input_num"><input onkeyup="ekup()" type="text" id="%s" style="width:40px;vertical-align:text-baseline;padding:0 2px;font-size:10px;border:1px solid gray;"/></span><span class="page_btn_go" onclick="clkyup();" style="cursor:pointer;">转到</span>`, id, pages, url, id, id)
|
||||
totalstr := fmt.Sprintf(`<span class="page_total">共%d条</span>`, total)
|
||||
pagenation := []string{totalstr, info, prefix, body, subfix, gostr}
|
||||
output := []string{}
|
||||
for _, v := range order {
|
||||
if v-1 < len(pagenation) && v-1 >= 0 {
|
||||
output = append(output, pagenation[v-1])
|
||||
}
|
||||
}
|
||||
if pages > 1 {
|
||||
return strings.Join(output, "")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Urls struct {}
|
||||
|
||||
func NewUrls() *Urls {
|
||||
return &Urls{}
|
||||
}
|
||||
|
||||
func (Urls *Urls) HttpQueryBuild(queryValues map[string]string) (queryString string) {
|
||||
queryString = ""
|
||||
for queryKey, queryValue := range queryValues {
|
||||
queryString = queryString + "&" + queryKey + "=" + url.QueryEscape(queryValue)
|
||||
}
|
||||
queryString = strings.Replace(queryString, "&", "", 1)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<div class="logo_box">
|
||||
<h3>隧道云,欢迎你</h3>
|
||||
<form class="login_form" action="/author/signup" method="post">
|
||||
<div class="input_outer">
|
||||
<span class="u_user"></span>
|
||||
<input name="username" class="text" style="color: #FFFFFF !important" type="text" placeholder="请输入账户">
|
||||
</div>
|
||||
<div class="input_outer">
|
||||
<span class="us_uer"></span>
|
||||
<input name="password" class="text" style="color: #FFFFFF !important; position:absolute; z-index:100;" value="" type="password" placeholder="请输入密码">
|
||||
</div>
|
||||
<div class="mb2"><a class="act-but submit" href="javascript:;" onclick="Author.login()" style="color: #FFFFFF">登录</a></div>
|
||||
</form>
|
||||
<p class="error_message" style="text-align: center;color: indianred;display: none"><strong></strong></p>
|
||||
<p class="success_message" style="text-align: center;color: #00ba8b;display: none"><strong></strong></p>
|
||||
<h5 style="text-align: center;"><a href="/" style="color: #00ba8b"> >>返回首页 </a>|<a href="/author/register" style="color: #00ba8b">没有账号?点击注册 <<</a></h5>
|
||||
</div>
|
||||
<script type="text/javascript" src="/static/js/module/author.js"></script>
|
||||
@@ -0,0 +1,22 @@
|
||||
<div class="logo_box">
|
||||
<h3>你好,欢迎<b style="color:darkgoldenrod">注册</b>隧道云</h3>
|
||||
<form class="register_form" action="/author/signin" method="post">
|
||||
<div class="input_outer">
|
||||
<span class="u_user"></span>
|
||||
<input name="username" class="text" style="color: #FFFFFF !important" type="text" placeholder="请输入用户名">
|
||||
</div>
|
||||
<div class="input_outer">
|
||||
<span class="us_uer"></span>
|
||||
<input name="password" class="text" style="color: #FFFFFF !important; position:absolute; z-index:100;" value="" type="password" placeholder="请输入密码">
|
||||
</div>
|
||||
<div class="input_outer">
|
||||
<span class="u_email"></span>
|
||||
<input name="email" class="text" style="color: #FFFFFF !important" type="text" placeholder="请输入邮箱">
|
||||
</div>
|
||||
<div class="mb2"><a class="act-but submit" href="javascript:;" onclick="Author.register()" style="color: #FFFFFF">注册</a></div>
|
||||
</form>
|
||||
<p class="error_message" style="text-align: center;color: indianred;display: none"><strong></strong></p>
|
||||
<p class="success_message" style="text-align: center;color: #00ba8b;display: none"><strong></strong></p>
|
||||
<h5 style="text-align: center;"><a href="/" style="color: #00ba8b"> >>返回首页 </a>|<a href="/author/login" style="color: #00ba8b">已有账号?点击登录 <<</a></h5>
|
||||
</div>
|
||||
<script type="text/javascript" src="/static/js/module/author.js"></script>
|
||||
@@ -0,0 +1,61 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="alert alert-info" role="alert">
|
||||
<strong><span class="glyphicon glyphicon-volume-up"></span> 注意!</strong> 普通用户只能选择普通节点,VIP 可选择VIP节点。<i class="ace-icon fa fa-hand-o-right blue"></i> <a href="">如何成为VIP?</a>
|
||||
</div>
|
||||
<form class="form-horizontal ajaxform">
|
||||
<input type="hidden" name="role_id" value="" />
|
||||
<h4><span class="label label-default">普通节点</span></h4>
|
||||
<hr>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>北美地区</strong> <span class="pull-right"><span class="badge">5</span></span></li>
|
||||
<li class="list-group-item">北美1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美4<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美5<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>香港地区</strong> <span class="pull-right"><span class="badge">3</span></span></li>
|
||||
<li class="list-group-item">香港1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">香港2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">香港3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>大陆地区</strong> <span class="pull-right"><span class="badge">4</span></span></li>
|
||||
<li class="list-group-item">大陆1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆5<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<h4><span class="label label-warning">VIP节点</span></h4>
|
||||
<hr>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>北美地区</strong> <span class="pull-right"><span class="badge">5</span></span></li>
|
||||
<li class="list-group-item">北美1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美4<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美5<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>香港地区</strong> <span class="pull-right"><span class="badge">3</span></span></li>
|
||||
<li class="list-group-item">香港1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">香港2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">香港3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>大陆地区</strong> <span class="pull-right"><span class="badge">4</span></span></li>
|
||||
<li class="list-group-item">大陆1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆5<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<div class="form-group">
|
||||
<div class="col-md-8" style="margin-left:10px;">
|
||||
<button type="submit" class="btn btn-primary">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,19 @@
|
||||
<div class="panel panel-default">
|
||||
<br>{{$clientValue := .clientValue}}
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal" method="post" action="{{if eq $clientValue.client_id "0"}} /client/save {{else}} /client/modify {{end}}">
|
||||
<input type="hidden" name="client_id" value="{{$clientValue.client_id}}">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span>Client名称</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="name" class="form-control" value="{{$clientValue.name}}" placeholder="请输入 Client 名称">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="button" name="submit" onclick="Form.ajaxSubmit(this.form, false)" class="btn btn-primary">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,53 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<a href="/client/add" class="btn btn-primary">添加 Client</a>
|
||||
</div>
|
||||
<div class="col-md-3 col-md-offset-7">
|
||||
<form action="/client/list" method="get">
|
||||
<div class="input-group">
|
||||
<input class="form-control" name="keyword" type="text" value="{{.keyword}}" placeholder="名称/Token"/>
|
||||
<span class="input-group-btn">
|
||||
<button type="submit" class="btn btn-primary"><i class="glyphicon glyphicon-search"></i></button>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w20p">名称</th>
|
||||
<th class="w20p">token</th>
|
||||
<th class="w13p">创建时间</th>
|
||||
<th class="w13p">修改时间</th>
|
||||
<th class="w15p">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range $key, $clientValue := .clientValues}}
|
||||
<tr>
|
||||
<td>{{$clientValue.name}}</td>
|
||||
<td>{{$clientValue.token}}</td>
|
||||
<td class="center">{{dateFormat $clientValue.create_time "Y-m-d H:i:s"}}</td>
|
||||
<td class="center">{{dateFormat $clientValue.update_time "Y-m-d H:i:s"}}</td>
|
||||
<td class="center">
|
||||
<a name="edit" class="glyphicon glyphicon-edit" href="/client/edit?client_id={{$clientValue.client_id}}">修改</a>
|
||||
<a onclick="Common.confirm('确定要删除吗?', '/client/delete?client_id={{$clientValue.client_id}}')" class="glyphicon glyphicon-remove">删除</a>
|
||||
<a onclick="Common.confirm('确定要重置token吗?', '/client/resetToken?client_id={{$clientValue.client_id}}')" class="glyphicon glyphicon-refresh">重置Token</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<div class="row">
|
||||
<div class="col-md-8 m-pagination" id="paginator">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,48 @@
|
||||
<div class="panel panel-default">
|
||||
<br>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal ajaxform" ajaxSuccess="success" ajaxAlways="always" method="post" action="">
|
||||
<input type="hidden" name="role_id" value="">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span>名称</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="name" class="form-control" value="" placeholder="client 名称">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span>server_ip</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="server_ip" class="form-control" value="" placeholder="请输入server_ip">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span>cluster节点</label>
|
||||
<div class="col-sm-4">
|
||||
<div class="input-group">
|
||||
<input type="text" name="cluster_name" class="form-control" value="" aria-describedby="cluster" placeholder="请选择cluster节点" readonly>
|
||||
<span class="input-group-addon" id="cluster"><a name="select_cluster" data-link="/cs/cluster" class="glyphicon glyphicon-th-list"></a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" class="btn btn-primary">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$("a[name='select_cluster']").bind('click', function() {
|
||||
$.fancybox({
|
||||
padding: 5,
|
||||
minWidth : 800,
|
||||
minHeight : 520,
|
||||
width : '95%',
|
||||
height : '60%',
|
||||
autoSize : false,
|
||||
type : 'iframe',
|
||||
href : $(this).attr('data-link')
|
||||
});
|
||||
});
|
||||
</script>
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
<!--==== bootstrap ====-->
|
||||
<script src="/static/js/bootstrap.min.js"></script>
|
||||
<!--==== plugins js ====-->
|
||||
<script src="/static/js/plugins.js"></script>
|
||||
<!--==== magnific-popup-options js ====-->
|
||||
<script src="/static/js/magnific-popup-options.js"></script>
|
||||
<!--==== validator js ====-->
|
||||
<script src="/static/js/validator.min.js"></script>
|
||||
<!--==== particles js ====-->
|
||||
<script src="/static/js/particles.min.js"></script>
|
||||
<!--==== app js ====-->
|
||||
<script src="/static/js/app.js"></script>
|
||||
<!--==== app js ====-->
|
||||
<script src="/static/js/wow-1.3.0.min.js"></script>
|
||||
<!--==== main js ====-->
|
||||
<script src="/static/js/main.js"></script>
|
||||
@@ -0,0 +1,25 @@
|
||||
<!--======******************* FOOTER SECTION ******************======-->
|
||||
|
||||
<footer class="footer">
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 text-center">
|
||||
|
||||
<div class="footer-text wow fadeInUp" data-wow-delay="0.4s">
|
||||
|
||||
<p>Copyright © Company <i style="color:#4183D7;">{{config "String" "sys.fullname" ""}}</i> All rights reserved.</p>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</footer>
|
||||
|
||||
<!--======******************* END FOOTER SECTION ***************======-->
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="keywords" content="">
|
||||
|
||||
<!--==== bootstrap ====-->
|
||||
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!--==== font-awesome ====-->
|
||||
<link href="/static/css/font-awesome.min.css" rel="stylesheet">
|
||||
<!--==== owl-carousel ====-->
|
||||
<link href="/static/css/owl.carousel.css" rel="stylesheet">
|
||||
<!--==== magnific-popup ====-->
|
||||
<link href="/static/css/magnific-popup.css" rel="stylesheet">
|
||||
<!--==== animate css ====-->
|
||||
<link href="/static/css/animate.min.css" rel="stylesheet">
|
||||
|
||||
<!--==== style css ====-->
|
||||
<link href="/static/css/style.css" rel="stylesheet">
|
||||
<!--==== responsive css ====-->
|
||||
<link href="/static/css/responsive.css" rel="stylesheet">
|
||||
|
||||
<!--==== jquery ====-->
|
||||
<script src="/static/js/jquery-2.1.4.min.js"></script>
|
||||
|
||||
<!--[if lt IE 9]>
|
||||
<script src="/static/js/html5shiv/3.7.2/html5shiv.min.js"></script>
|
||||
<script src="/static/js/respond/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
@@ -0,0 +1,26 @@
|
||||
<div id="user-home" class="" style="height:70px;">
|
||||
<header class="navbar custom-navbar">
|
||||
<div class="logo pull-left">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
</div>
|
||||
<a href="/user/index">{{config "String" "sys.fullname" ""}}</a>
|
||||
</div>
|
||||
<nav class="main-menu pull-right">
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="smooth-scroll"><a target="main" href="/tunnel/mode"><span class="label label-danger">添加隧道</span></a></li>
|
||||
<li class="smooth-scroll" style="text-transform:none;"><a><span class="label label-primary">Hi:{{.userValue.username}} </span></a></li>
|
||||
<li class="smooth-scroll"><a class="theme-color" href="/">首页</a></li>
|
||||
<!--<li class="smooth-scroll"><a class="theme-color" href="/user/index">个人中心</a></li>-->
|
||||
<li class="smooth-scroll"><a class="theme-color" href="/author/logout">退出</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
</div>
|
||||
@@ -0,0 +1,56 @@
|
||||
<div id="home" class="intro-section">
|
||||
<header class="navbar custom-navbar" style="border-radius:0">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-sm-3 col-xs-12">
|
||||
<div class="logo">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
</div>
|
||||
<a href="#home">{{config "String" "sys.fullname" ""}}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9 col-sm-9 col-xs-12">
|
||||
<nav class="main-menu">
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="active smooth-scroll"><a class="theme-color" href="#home">首页</a></li>
|
||||
<li class="smooth-scroll"><a class="theme-color" href="#services">服务</a></li>
|
||||
{{if eq .isLogin "1"}}
|
||||
<li class="smooth-scroll"><a class="theme-color" href="/user/index">个人中心</a></li>
|
||||
<li class="smooth-scroll"><a class="theme-color" href="/author/logout">退出</a></li>
|
||||
{{else}}
|
||||
<li class="smooth-scroll"><a class="theme-color" href="/author/login">登录</a></li>
|
||||
<li class="smooth-scroll"><a class="theme-color" href="/author/register">注册</a></li>
|
||||
{{end}}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="welcome-area">
|
||||
<div id="particles-js"></div>
|
||||
<div class="welcome-table">
|
||||
<div class="welcome-cell">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12 col-sm-12 col-xs-12">
|
||||
<div class="welcome-text text-center">
|
||||
<h4>隧道云</h4>
|
||||
<h1>让你轻松<span class="theme-color">连通</span>世界每个角落 </h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#services" class="scroll-btn banner-icon theme-color"><i class="fa fa-angle-double-down"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>出错啦!</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="/static/js/jquery-2.1.4.min.js"></script>
|
||||
<link rel="stylesheet" href="/static/css/fonts.googleapis.com.css">
|
||||
<link rel="stylesheet" href="/static/css/common.css">
|
||||
<link rel="stylesheet" href="/static/css/font-awesome.min.css">
|
||||
|
||||
<!--bootstrap google plus theme-->
|
||||
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
|
||||
<script src="/static/js/bootstrap.min.js"></script>
|
||||
<!--end-->
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<strong><span class="blue bigger-125">
|
||||
<i class="ace-icon fa fa-random"></i>
|
||||
</span></strong> 很抱歉,服务器返回错误!
|
||||
</div>
|
||||
<div class="space"></div>
|
||||
|
||||
<hr>
|
||||
<div class="space"></div>
|
||||
<div class="center" style="text-align: center">
|
||||
<a href="javascript:history.back()" class="btn btn-default">
|
||||
<i class="ace-icon fa fa-arrow-left"></i> 返回
|
||||
</a>
|
||||
<a target="_parent" href="/user/index" class="btn btn-primary">
|
||||
<i class="ace-icon fa fa-tachometer"></i> 主页
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,31 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<strong><span class="blue bigger-125">
|
||||
<i class="ace-icon fa fa-random"></i>
|
||||
</span></strong> 很抱歉,服务器返回错误!
|
||||
</div>
|
||||
<div class="space"></div>
|
||||
<div>
|
||||
<h4 class="lighter smaller">以下是具体的错误信息:</h4>
|
||||
<ul class="list-unstyled spaced inline bigger-110 margin-15">
|
||||
<li>
|
||||
<i class="ace-icon fa fa-hand-o-right blue"></i>
|
||||
<span class="text-danger">{{.errorMessage}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="space"></div>
|
||||
<div class="center" style="text-align: center">
|
||||
<a href="javascript:history.back()" class="btn btn-default">
|
||||
<i class="ace-icon fa fa-arrow-left"></i>
|
||||
返回
|
||||
</a>
|
||||
<a target="_parent" href="/main/index" class="btn btn-primary">
|
||||
<i class="ace-icon fa fa-tachometer"></i>
|
||||
首页
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
{{template "common/head.html" .}}
|
||||
</head>
|
||||
|
||||
<body class="blue_color_theme">
|
||||
{{template "common/header.html" .}} {{.LayoutContent}} {{template "common/footer.html" .}} {{template "common/foot.html" .}}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
{{template "common/head.html" .}}
|
||||
</head>
|
||||
|
||||
<body class="blue_color_theme">
|
||||
{{template "common/header_index.html" .}} {{.LayoutContent}} {{template "common/footer.html" .}} {{template "common/foot.html" .}}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="no-js">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{.title}}</title>
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/normalize.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/demo.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/component.css" />
|
||||
<!--[if IE]>
|
||||
<script src="/static/js/html5.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container demo-1">
|
||||
<div class="content">
|
||||
<div id="large-header" class="large-header">
|
||||
<canvas id="demo-canvas"></canvas> {{.LayoutContent}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /container -->
|
||||
<!--==== jquery ====-->
|
||||
<script src="/static/js/jquery-2.1.4.min.js"></script>
|
||||
<script src="/static/js/jquery.form.js"></script>
|
||||
<script src="/static/js/TweenLite.min.js"></script>
|
||||
<script src="/static/js/EasePack.min.js"></script>
|
||||
<script src="/static/js/rAF.js"></script>
|
||||
<script src="/static/js/demo-1.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!--==== bootstrap ====-->
|
||||
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!--==== font-awesome ====-->
|
||||
<link href="/static/css/font-awesome.min.css" rel="stylesheet">
|
||||
<link href="/static/css/common.css" rel="stylesheet">
|
||||
<!--==== animate css ====-->
|
||||
<link href="/static/css/animate.min.css" rel="stylesheet">
|
||||
<link href="/static/plugins/jquery-fancybox/css/jquery.fancybox.css" rel="stylesheet">
|
||||
<link href="/static/plugins/sweetalert/css/sweetalert.css" rel="stylesheet"/>
|
||||
|
||||
<!--==== jquery ====-->
|
||||
<script src="/static/js/jquery-2.1.4.min.js"></script>
|
||||
<!--==== bootstrap ====-->
|
||||
<script src="/static/js/bootstrap.min.js"></script>
|
||||
<script src="/static/js/jquery.form.js"></script>
|
||||
<script src="/static/plugins/jquery-fancybox/jquery.fancybox.js"></script>
|
||||
<script src="/static/plugins/jquery-notify/notify.js"></script>
|
||||
<script src="/static/plugins/sweetalert/sweetalert.min.js"></script>
|
||||
<script src="/static/js/common/common.js"></script>
|
||||
<script src="/static/js/common/form.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{{.LayoutContent}}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
{{template "common/head.html" .}}
|
||||
<link href="/static/css/navbar-fixed-side.css" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
<body class="blue_color_theme">
|
||||
{{template "common/header.html" .}} {{.LayoutContent}} {{template "common/foot.html" .}}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,61 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="alert alert-info" role="alert">
|
||||
<strong><span class="glyphicon glyphicon-volume-up"></span> 注意!</strong> 普通用户只能选择普通节点,VIP 可选择VIP节点。<i class="ace-icon fa fa-hand-o-right blue"></i> <a href="">如何成为VIP?</a>
|
||||
</div>
|
||||
<form class="form-horizontal ajaxform">
|
||||
<input type="hidden" name="role_id" value="" />
|
||||
<h4><span class="label label-default">普通节点</span></h4>
|
||||
<hr>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>北美地区</strong> <span class="pull-right"><span class="badge">5</span></span></li>
|
||||
<li class="list-group-item">北美1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美4<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美5<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>香港地区</strong> <span class="pull-right"><span class="badge">3</span></span></li>
|
||||
<li class="list-group-item">香港1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">香港2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">香港3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>大陆地区</strong> <span class="pull-right"><span class="badge">4</span></span></li>
|
||||
<li class="list-group-item">大陆1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆5<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<h4><span class="label label-warning">VIP节点</span></h4>
|
||||
<hr>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>北美地区</strong> <span class="pull-right"><span class="badge">5</span></span></li>
|
||||
<li class="list-group-item">北美1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美4<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美5<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>香港地区</strong> <span class="pull-right"><span class="badge">3</span></span></li>
|
||||
<li class="list-group-item">香港1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">香港2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">香港3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>大陆地区</strong> <span class="pull-right"><span class="badge">4</span></span></li>
|
||||
<li class="list-group-item">大陆1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆5<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<div class="form-group">
|
||||
<div class="col-md-8" style="margin-left:10px;">
|
||||
<button type="submit" class="btn btn-primary">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,19 @@
|
||||
<div class="panel panel-default">
|
||||
<br>{{$serverValue := .serverValue}}
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal" method="post" action="{{if eq $serverValue.server_id "0"}} /server/save {{else}} /server/modify {{end}}">
|
||||
<input type="hidden" name="server_id" value="{{$serverValue.server_id}}">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span>Server名称</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="name" class="form-control" value="{{$serverValue.name}}" placeholder="请输入 Server 名称">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="button" name="submit" onclick="Form.ajaxSubmit(this.form, false)" class="btn btn-primary">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,53 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<a href="/server/add" class="btn btn-primary">添加 Server</a>
|
||||
</div>
|
||||
<div class="col-md-3 col-md-offset-7">
|
||||
<form action="/server/list" method="get">
|
||||
<div class="input-group">
|
||||
<input class="form-control" name="keyword" type="text" value="{{.keyword}}" placeholder="名称/Token"/>
|
||||
<span class="input-group-btn">
|
||||
<button type="submit" class="btn btn-primary"><i class="glyphicon glyphicon-search"></i></button>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w20p">名称</th>
|
||||
<th class="w20p">token</th>
|
||||
<th class="w13p">创建时间</th>
|
||||
<th class="w13p">修改时间</th>
|
||||
<th class="w15p">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range $key, $serverValue := .serverValues}}
|
||||
<tr>
|
||||
<td>{{$serverValue.name}}</td>
|
||||
<td>{{$serverValue.token}}</td>
|
||||
<td class="center">{{dateFormat $serverValue.create_time "Y-m-d H:i:s"}}</td>
|
||||
<td class="center">{{dateFormat $serverValue.update_time "Y-m-d H:i:s"}}</td>
|
||||
<td class="center">
|
||||
<a name="edit" class="glyphicon glyphicon-edit" href="/server/edit?server_id={{$serverValue.server_id}}">修改</a>
|
||||
<a onclick="Common.confirm('确定要删除吗?', '/server/delete?server_id={{$serverValue.server_id}}')" class="glyphicon glyphicon-remove">删除</a>
|
||||
<a onclick="Common.confirm('确定要重置token吗?', '/server/resetToken?server_id={{$serverValue.server_id}}')" class="glyphicon glyphicon-refresh">重置Token</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<div class="row">
|
||||
<div class="col-md-8 m-pagination" id="paginator">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,39 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">{{$clusterId := .clusterId}}
|
||||
<div class="alert alert-info" role="alert">
|
||||
<strong><span class="glyphicon glyphicon-volume-up"></span> 注意!</strong> 普通用户只能选择普通节点,VIP 可选择VIP节点。<i class="ace-icon fa fa-hand-o-right blue"></i> <a href="">如何成为VIP?</a>
|
||||
</div>
|
||||
<form class="form-horizontal">
|
||||
<input type="hidden" name="role_id" value="" />
|
||||
{{range $name, $regionCluster := .regionClusters}}
|
||||
<h4><span class="label label-default">{{$name}}</span></h4>
|
||||
{{range $regionKey, $regions := $regionCluster}}
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>{{$regions.name}}</strong> <span class="pull-right"><span class="badge"></span></span></li>
|
||||
{{range $clusterKey, $cluster := $regions.clusters}}
|
||||
<li class="list-group-item cluster_{{$cluster.cluster_id}}">{{$cluster.name}}
|
||||
<span class="pull-right">
|
||||
<input name="cluster_id" type="radio" value="{{$cluster.cluster_id}}" {{if eq $clusterId $cluster.cluster_id}} checked {{end}}/>
|
||||
</span>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<div class="form-group">
|
||||
<div class="col-md-8" style="margin-left:10px;">
|
||||
<button type="button" onclick="fancyboxClose()" class="btn btn-primary">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
function fancyboxClose() {
|
||||
var clusterId = $("input[name='cluster_id']:checked").val();
|
||||
var clusterName = $(".cluster_"+clusterId).text();
|
||||
parent.$("input[name='cluster_name']").val(clusterName);
|
||||
parent.$("input[name='cluster_id']").val(clusterId);
|
||||
parent.$.fancybox.close();
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,61 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="alert alert-info" role="alert">
|
||||
<strong><span class="glyphicon glyphicon-volume-up"></span> 注意!</strong> 普通用户只能选择普通节点,VIP 可选择VIP节点。<i class="ace-icon fa fa-hand-o-right blue"></i> <a href="">如何成为VIP?</a>
|
||||
</div>
|
||||
<form class="form-horizontal ajaxform">
|
||||
<input type="hidden" name="role_id" value="" />
|
||||
<h4><span class="label label-default">普通节点</span></h4>
|
||||
<hr>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>北美地区</strong> <span class="pull-right"><span class="badge">5</span></span></li>
|
||||
<li class="list-group-item">北美1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美4<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美5<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>香港地区</strong> <span class="pull-right"><span class="badge">3</span></span></li>
|
||||
<li class="list-group-item">香港1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">香港2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">香港3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>大陆地区</strong> <span class="pull-right"><span class="badge">4</span></span></li>
|
||||
<li class="list-group-item">大陆1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆5<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<h4><span class="label label-warning">VIP节点</span></h4>
|
||||
<hr>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>北美地区</strong> <span class="pull-right"><span class="badge">5</span></span></li>
|
||||
<li class="list-group-item">北美1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美4<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">北美5<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>香港地区</strong> <span class="pull-right"><span class="badge">3</span></span></li>
|
||||
<li class="list-group-item">香港1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">香港2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">香港3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>大陆地区</strong> <span class="pull-right"><span class="badge">4</span></span></li>
|
||||
<li class="list-group-item">大陆1<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆2<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆3<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
<li class="list-group-item">大陆5<span class="pull-right"><input name="" type="radio" value="" onclick="" /></span></li>
|
||||
</ul>
|
||||
<div class="form-group">
|
||||
<div class="col-md-8" style="margin-left:10px;">
|
||||
<button type="submit" class="btn btn-primary">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,103 @@
|
||||
<div class="panel panel-default">
|
||||
<br>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal" method="post" action="/tunnel/save">
|
||||
<input type="hidden" name="tunnel_id" value="">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span>名称</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="name" class="form-control" value="" placeholder="请输入隧道名称">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span> 模式 </label>
|
||||
<div class="col-sm-4">
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="mode" value="0" checked="checked">基本
|
||||
</label>
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="mode" value="1">高级
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span> Server</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="server_id" class="form-control">
|
||||
{{range $serverValue := .serverValues}}
|
||||
<option value="{{$serverValue.server_id}}">{{$serverValue.name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span>Server绑定IP</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="server_listen_ip" class="form-control" value="" placeholder="请输入Server绑定IP">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span>Server监听端口</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="server_listen_port" class="form-control" value="" placeholder="请输入Server监听端口">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span> Client</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="" class="form-control">
|
||||
{{range $clientValue := .clientValues}}
|
||||
<option value="{{$clientValue.client_id}}">{{$clientValue.name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span>Client绑定IP</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="client_local_host" class="form-control" value="" placeholder="请输入Server绑定IP">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span>Client监听端口</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="client_local_port" class="form-control" value="" placeholder="请输入Server监听端口">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span> 选择节点 </label>
|
||||
<div class="col-sm-4">
|
||||
<div class="input-group">
|
||||
<input type="text" name="cluster_name" class="form-control" aria-describedby="cluster-input" readonly>
|
||||
<input type="hidden" name="cluster_id" class="form-control" value="">
|
||||
<span class="input-group-addon" id="cluster-input">
|
||||
<a class="glyphicon glyphicon-th-list" name="select_cluster" data-link="/tunnel/cluster"></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="button" name="submit" onclick="Form.ajaxSubmit(this.form, false)" class="btn btn-primary">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$("a[name='select_cluster']").bind('click', function() {
|
||||
var clusterId = $("input[name='cluster_id']").val();
|
||||
$.fancybox({
|
||||
padding: 5,
|
||||
minWidth : 800,
|
||||
minHeight : 520,
|
||||
width : '95%',
|
||||
height : '70%',
|
||||
autoSize : false,
|
||||
type : 'iframe',
|
||||
href : $(this).attr('data-link') + "?cluster_id=" + clusterId,
|
||||
afterClose: function (current, previous) {
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,53 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<a href="/tunnel/add" class="btn btn-primary">添加隧道</a>
|
||||
</div>
|
||||
<div class="col-md-3 col-md-offset-7">
|
||||
<form action="/tunnel/list" method="get">
|
||||
<div class="input-group">
|
||||
<input class="form-control" name="keyword" type="text" value="{{.keyword}}" placeholder="名称/Token"/>
|
||||
<span class="input-group-btn">
|
||||
<button type="submit" class="btn btn-primary"><i class="glyphicon glyphicon-search"></i></button>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w20p">名称</th>
|
||||
<th class="w8p">模式</th>
|
||||
<th class="w13p">创建时间</th>
|
||||
<th class="w13p">修改时间</th>
|
||||
<th class="w15p">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range $key, $tunnelValue := .tunnelValues}}
|
||||
<tr>
|
||||
<td>{{$tunnelValue.name}}</td>
|
||||
<td>{{$tunnelValue.token}}</td>
|
||||
<td class="center">{{dateFormat $tunnelValue.create_time "Y-m-d H:i:s"}}</td>
|
||||
<td class="center">{{dateFormat $tunnelValue.update_time "Y-m-d H:i:s"}}</td>
|
||||
<td class="center">
|
||||
<a name="edit" class="glyphicon glyphicon-edit" href="/tunnel/edit?tunnel_id={{$tunnelValue.tunnel_id}}">修改</a>
|
||||
<a onclick="Common.confirm('确定要删除吗?', '/tunnel/delete?tunnel_id={{$tunnelValue.tunnel_id}}')" class="glyphicon glyphicon-remove">删除</a>
|
||||
<a onclick="Common.confirm('确定要重置token吗?', '/tunnel/resetToken?tunnel_id={{$tunnelValue.tunnel_id}}')" class="glyphicon glyphicon-refresh">重置Token</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<div class="row">
|
||||
<div class="col-md-8 m-pagination" id="paginator">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,35 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4><span class="label label-danger">第二步:</span> 请选择节点</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{$clusterId := .clusterId}}
|
||||
<div class="alert alert-info" role="alert">
|
||||
<strong><span class="glyphicon glyphicon-volume-up"></span> 注意!</strong> 普通用户只能选择普通节点,VIP 可选择VIP节点。<i class="ace-icon fa fa-hand-o-right blue"></i> <a href="">如何成为VIP?</a>
|
||||
</div>
|
||||
<form class="form-horizontal" action="/tunnel/add" method="post">
|
||||
<input type="hidden" name="mode" value="{{.mode}}" />
|
||||
{{range $name, $regionCluster := .regionClusters}}
|
||||
<h4><span class="label label-default">{{$name}}</span></h4>
|
||||
{{range $regionKey, $regions := $regionCluster}}
|
||||
<ul class="list-group w240 inline-group">
|
||||
<li class="list-group-item"><strong>{{$regions.name}}</strong> <span class="pull-right"><span class="badge"></span></span></li>
|
||||
{{range $clusterKey, $cluster := $regions.clusters}}
|
||||
<li class="list-group-item cluster_{{$cluster.cluster_id}}">{{$cluster.name}}
|
||||
<span class="pull-right">
|
||||
<input name="cluster_id" type="radio" value="{{$cluster.cluster_id}}" {{if eq $clusterId $cluster.cluster_id}} checked {{end}}/>
|
||||
</span>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<div class="form-group center">
|
||||
<div class="col-md-12" style="margin-left:10px;">
|
||||
<a type="button" href="javascript:history.back(-1)" class="btn btn-default"><span class="glyphicon glyphicon-arrow-left"></span>上一步</a>
|
||||
<button type="submit" class="btn btn-primary">下一步 <span class="glyphicon glyphicon-arrow-right"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,88 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4><span class="label label-danger">第三步:</span> 请填写隧道信息 </h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal" method="post" action="/tunnel/save">
|
||||
<input type="hidden" name="mode" value="{{.mode}}">
|
||||
<input type="hidden" name="cluster_id" value="{{.clusterId}}">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label"><span class="text-danger"> * </span>隧道名称</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="name" class="form-control" value="" placeholder="请输入隧道名称">
|
||||
</div>
|
||||
</div>
|
||||
{{if eq .isHaveServer "1"}}
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label"><span class="text-danger"> * </span> 选择Server</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="server_id" class="form-control">
|
||||
{{range $serverValue := .serverValues}}
|
||||
<option value="{{$serverValue.server_id}}">{{$serverValue.name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label"><span class="text-danger"> * </span>Server绑定IP</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="server_listen_ip" class="form-control" value="" placeholder="请输入Server绑定IP">
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label"><span class="text-danger"> * </span> Server</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="hidden" name="server_id" class="form-control" value="{{.systemServer.cs_id}}" readonly>
|
||||
<input type="text" class="form-control" value="系统server" readonly>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label"><span class="text-danger"> * </span>Server端口</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="server_listen_port" class="form-control" value="" placeholder="请输入Server端口">
|
||||
</div>
|
||||
</div>
|
||||
{{if eq .isHaveClient "1"}}
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label"><span class="text-danger"> * </span> 选择Client</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="client_id" class="form-control">
|
||||
{{range $clientValue := .clientValues}}
|
||||
<option value="{{$clientValue.client_id}}">{{$clientValue.name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label"><span class="text-danger"> * </span>Client绑定IP</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="client_local_host" class="form-control" value="" placeholder="请输入Server绑定IP">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label"><span class="text-danger"> * </span>Client监听端口</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="client_local_port" class="form-control" value="" placeholder="请输入Server监听端口">
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label"><span class="text-danger"> * </span> Client</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="hidden" name="client_id" class="form-control" value="{{.systemClient.cs_id}}" readonly>
|
||||
<input type="text" class="form-control" value="系统client" readonly>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="form-group center">
|
||||
<div class="col-sm-12">
|
||||
<a type="button" href="javascript:history.back(-1)" class="btn btn-default"><span class="glyphicon glyphicon-arrow-left"></span>上一步</a>
|
||||
<button type="button" name="submit" onclick="Form.ajaxSubmit(this.form, false)" class="btn btn-primary">
|
||||
<span class="glyphicon glyphicon-ok"></span> 保存 </button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,79 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<a href="/tunnel/mode" class="btn btn-primary">添加隧道</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w13p">名称</th>
|
||||
<th class="w8p">模式</th>
|
||||
<th class="w8p">Server Ip</th>
|
||||
<th class="w8p">Server Port</th>
|
||||
<th class="w8p">Client Ip</th>
|
||||
<th class="w8p">Client Port</th>
|
||||
<th class="w8p">状态</th>
|
||||
<th class="w8p">开启</th>
|
||||
<th class="w13p">创建时间</th>
|
||||
<th class="w13p">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range $key, $tunnelValue := .tunnelValues}}
|
||||
<tr>
|
||||
<td>{{$tunnelValue.name}}</td>
|
||||
<td>
|
||||
{{if eq $tunnelValue.mode "0"}}
|
||||
基础模式
|
||||
{{else if eq $tunnelValue.mode "1"}}
|
||||
高级模式
|
||||
{{else}}
|
||||
特殊模式
|
||||
{{end}}
|
||||
</td>
|
||||
<td class="center">{{$tunnelValue.server_listen_ip}}</td>
|
||||
<td class="center">{{$tunnelValue.server_listen_port}}</td>
|
||||
<td class="center">{{$tunnelValue.client_local_host}}</td>
|
||||
<td class="center">{{$tunnelValue.client_local_port}}</td>
|
||||
<td class="center">{{if eq $tunnelValue.status "0"}}
|
||||
<label class="label label-danger">异常</label>
|
||||
{{else}}
|
||||
<label class="label label-success">正常</label>
|
||||
{{end}}
|
||||
</td>
|
||||
<td class="center">{{if eq $tunnelValue.is_open "0"}}
|
||||
<label class="label label-danger">未开启</label>
|
||||
{{else}}
|
||||
<label class="label label-success">已开启</label>
|
||||
{{end}}
|
||||
</td>
|
||||
<td class="center">{{dateFormat $tunnelValue.create_time "Y-m-d H:i:s"}}</td>
|
||||
<td class="center">
|
||||
{{if eq $tunnelValue.is_open "0"}}
|
||||
<a onclick="Common.confirm('确定要开启隧道吗?', '/tunnel/open?tunnel_id={{$tunnelValue.tunnel_id}}')" class="glyphicon glyphicon-ok-circle">开启</a>
|
||||
{{else}}
|
||||
<a onclick="Common.confirm('确定要关闭隧道吗?', '/tunnel/close?tunnel_id={{$tunnelValue.tunnel_id}}')" class="glyphicon glyphicon-ban-circle">关闭</a>
|
||||
{{end}}
|
||||
{{if eq $tunnelValue.status "0"}}
|
||||
{{if eq $tunnelValue.is_open "1"}}
|
||||
<a onclick="Common.confirm('确定要重启隧道吗?', '/tunnel/refresh?tunnel_id={{$tunnelValue.tunnel_id}}')" class="glyphicon glyphicon-refresh">重启</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<a onclick="Common.confirm('确定要删除隧道吗?', '/tunnel/delete?tunnel_id={{$tunnelValue.tunnel_id}}')" class="glyphicon glyphicon-remove">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<div class="row">
|
||||
<div class="col-md-8 m-pagination" id="paginator">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,60 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4>
|
||||
<span class="label label-danger">第一步:</span> 请选择模式
|
||||
</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="col-sm-6 col-md-4">
|
||||
<div class="thumbnail">
|
||||
<img alt="100%x200" src="/static/images/tunnel/base.png" data-holder-rendered="true" style="background-color: #9d9d9d ;height: 200px; width: 100%; display: block;" >
|
||||
<div class="caption" style="height: 200px;">
|
||||
<h3>基本模式</h3>
|
||||
<p>基本模式基本模式基本模式基本模式基本模式基本模式基本模式基本模式基本模式高级模式高级模式高级模式高级模式高级模式高级模式高级模式高级模式</p>
|
||||
<p>
|
||||
{{if eq .modeBase "1"}}
|
||||
<a href="/tunnel/cluster?mode=0" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-hand-right"></span> 选择</a>
|
||||
{{else}}
|
||||
<a href="javascript:;" class="btn btn-primary" role="button" disabled="disabled"><span class="glyphicon glyphicon-remove"></span> 选择</a>
|
||||
<span class="text-danger">没有权限</span>
|
||||
{{end}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-4">
|
||||
<div class="thumbnail">
|
||||
<img data-src="holder.js/100%x200" alt="100%x200" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMjQyIiBoZWlnaHQ9IjIwMCIgdmlld0JveD0iMCAwIDI0MiAyMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjwhLS0KU291cmNlIFVSTDogaG9sZGVyLmpzLzEwMCV4MjAwCkNyZWF0ZWQgd2l0aCBIb2xkZXIuanMgMi42LjAuCkxlYXJuIG1vcmUgYXQgaHR0cDovL2hvbGRlcmpzLmNvbQooYykgMjAxMi0yMDE1IEl2YW4gTWFsb3BpbnNreSAtIGh0dHA6Ly9pbXNreS5jbwotLT48ZGVmcz48c3R5bGUgdHlwZT0idGV4dC9jc3MiPjwhW0NEQVRBWyNob2xkZXJfMTVlNTE1YjY4YTQgdGV4dCB7IGZpbGw6I0FBQUFBQTtmb250LXdlaWdodDpib2xkO2ZvbnQtZmFtaWx5OkFyaWFsLCBIZWx2ZXRpY2EsIE9wZW4gU2Fucywgc2Fucy1zZXJpZiwgbW9ub3NwYWNlO2ZvbnQtc2l6ZToxMnB0IH0gXV0+PC9zdHlsZT48L2RlZnM+PGcgaWQ9ImhvbGRlcl8xNWU1MTViNjhhNCI+PHJlY3Qgd2lkdGg9IjI0MiIgaGVpZ2h0PSIyMDAiIGZpbGw9IiNFRUVFRUUiLz48Zz48dGV4dCB4PSI4OS44NTkzNzUiIHk9IjEwNS4xIj4yNDJ4MjAwPC90ZXh0PjwvZz48L2c+PC9zdmc+" data-holder-rendered="true" style="height: 200px; width: 100%; display: block;">
|
||||
<div class="caption" style="height: 200px;">
|
||||
<h3>高级模式</h3>
|
||||
<p>高级模式高级模式高级模式高级模式高级模式高级模式高级模式高级模式高级模式高级模式高级模式高级模式高级模式高级模式高级模式高级模式</p>
|
||||
<p>
|
||||
{{if eq .modeSenior "1"}}
|
||||
<a href="/tunnel/cluster?mode=1" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-hand-right"></span> 选择</a>
|
||||
{{else}}
|
||||
<a href="javascript:;" class="btn btn-primary" role="button" disabled="disabled">选择</a>
|
||||
<span class="text-danger">没有权限</span>
|
||||
{{end}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-4">
|
||||
<div class="thumbnail">
|
||||
<img data-src="holder.js/100%x200" alt="100%x200" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMjQyIiBoZWlnaHQ9IjIwMCIgdmlld0JveD0iMCAwIDI0MiAyMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjwhLS0KU291cmNlIFVSTDogaG9sZGVyLmpzLzEwMCV4MjAwCkNyZWF0ZWQgd2l0aCBIb2xkZXIuanMgMi42LjAuCkxlYXJuIG1vcmUgYXQgaHR0cDovL2hvbGRlcmpzLmNvbQooYykgMjAxMi0yMDE1IEl2YW4gTWFsb3BpbnNreSAtIGh0dHA6Ly9pbXNreS5jbwotLT48ZGVmcz48c3R5bGUgdHlwZT0idGV4dC9jc3MiPjwhW0NEQVRBWyNob2xkZXJfMTVlNTE1YjMwMGMgdGV4dCB7IGZpbGw6I0FBQUFBQTtmb250LXdlaWdodDpib2xkO2ZvbnQtZmFtaWx5OkFyaWFsLCBIZWx2ZXRpY2EsIE9wZW4gU2Fucywgc2Fucy1zZXJpZiwgbW9ub3NwYWNlO2ZvbnQtc2l6ZToxMnB0IH0gXV0+PC9zdHlsZT48L2RlZnM+PGcgaWQ9ImhvbGRlcl8xNWU1MTViMzAwYyI+PHJlY3Qgd2lkdGg9IjI0MiIgaGVpZ2h0PSIyMDAiIGZpbGw9IiNFRUVFRUUiLz48Zz48dGV4dCB4PSI4OS44NTkzNzUiIHk9IjEwNS4xIj4yNDJ4MjAwPC90ZXh0PjwvZz48L2c+PC9zdmc+" data-holder-rendered="true" style="height: 200px; width: 100%; display: block;">
|
||||
<div class="caption" style="height: 200px;">
|
||||
<h3>特殊模式</h3>
|
||||
<p>特殊模式特殊模式特殊模式特殊模式特殊模式特殊模式特殊模式特殊模式特殊模式特殊模式特殊模式特殊模式特殊模式特殊模式特殊模式特殊模式特殊模式特殊模式特殊模式</p>
|
||||
<p>
|
||||
{{if eq .modeSpecial "1"}}
|
||||
<a href="/tunnel/cluster?mode=2" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-hand-right"></span> 选择</a>
|
||||
{{else}}
|
||||
<a href="javascript:;" class="btn btn-primary" role="button" disabled="disabled">选择</a>
|
||||
<span class="text-danger">没有权限</span>
|
||||
{{end}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,100 @@
|
||||
<style>
|
||||
#user-home header {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.nav-list {
|
||||
border: none;
|
||||
}
|
||||
|
||||
ul.navbar {
|
||||
padding: 0;
|
||||
padding-top: 10px;
|
||||
background-color: rgba(10, 10, 10, 0.8);
|
||||
}
|
||||
|
||||
ul.navbar li {
|
||||
list-style: none;
|
||||
display: block;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
cursor: pointer;
|
||||
/* text-align: center; */
|
||||
}
|
||||
|
||||
ul.navbar li a {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
color: whitesmoke;
|
||||
}
|
||||
|
||||
ul.navbar li a i {
|
||||
margin-right: 10px;
|
||||
margin-left: 40px;
|
||||
}
|
||||
|
||||
ul.navbar li a:hover {
|
||||
background-color: rgba(10, 10, 10, 0.6);
|
||||
color: whitesmoke;
|
||||
}
|
||||
|
||||
.navbar .logo {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.left-menu {
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.right-content {
|
||||
padding-left: 190px;
|
||||
padding-top: 10px;
|
||||
padding-right: 10px;
|
||||
min-height: 100px;
|
||||
}
|
||||
</style>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-3 col-lg-2 navbar-menu left-menu">
|
||||
<ul class="navbar nav-list navbar-default navbar-fixed-side">
|
||||
<li>
|
||||
<a href="/user/profile"><i class="fa fa-user-circle"></i>我的资料</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/client/list"><i class="fa fa-exchange"></i>我的Client</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/server/list"><i class="fa fa-server"></i>我的Server</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/tunnel/list"><i class="fa fa-retweet"></i>我的隧道</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="right-content">
|
||||
<iframe id="main" name="main" src="/user/welcome" scrolling="yes" style="overflow-y:auto;border:none;" frameborder="yes" width="100%" height="100%"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
setInterval(function() {
|
||||
var mainheight = $("#main").contents().find("body").height();
|
||||
var minHeight = $(window).height() - 90;
|
||||
if (mainheight < minHeight) {
|
||||
mainheight = minHeight
|
||||
}
|
||||
$("#main").height(mainheight);
|
||||
var src = $("#main").attr("src");
|
||||
if(src == "/author/login") {
|
||||
location.href = src;
|
||||
}
|
||||
}, 200);
|
||||
$('ul.nav-list a').not('.dropdown-toggle').click(function() {
|
||||
$('#main').attr('src', this.href);
|
||||
return false
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,36 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<ul class="nav nav-tabs">
|
||||
<li><a href="/user/profile">修改资料</a></li>
|
||||
<li class="active"><a href="/user/password">修改密码</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal" method="post" action="/user/repass">
|
||||
<input type="hidden" name="user_id" value="{{.userValue.user_id}}">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span>旧密码</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="password" name="old_pass" class="form-control" value="" placeholder="请输入当前密码">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span>新密码</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="password" name="new_pass" class="form-control" value="" placeholder="请输入新密码">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="text-danger"> * </span>确认新密码</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="password" name="confirm_pass" class="form-control" value="" placeholder="请再次输入新密码">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="button" name="submit" onclick="Form.ajaxSubmit(this.form, false)" class="btn btn-primary">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="/user/profile">修改资料</a></li>
|
||||
<li><a href="/user/password">修改密码</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal" method="post" action="/user/save">
|
||||
<input type="hidden" name="user_id" value="{{.userValue.user_id}}">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-1 control-label"><span class="text-danger"> * </span>用户名</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="username" class="form-control" value="{{.userValue.username}}" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-1 control-label"><span class="text-danger"> * </span>邮箱</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="email" class="form-control" value="{{.userValue.email}}" placeholder="请输入邮箱" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-1 control-label"><span class="text-danger"></span>昵称</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="nickname" class="form-control" value="{{.userValue.nickname}}" placeholder="请输入昵称">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<button type="button" name="submit" onclick="Form.ajaxSubmit(this.form, false)" class="btn btn-primary">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1 @@
|
||||
Welcome
|
||||
@@ -0,0 +1,204 @@
|
||||
<div class="demo_panel_box">
|
||||
<div class="color_panel_box">
|
||||
<div class="spiner_button slide_in_out"><i class="fa fa-cog fa-spin"></i></div>
|
||||
<span class="red_color"></span>
|
||||
<span class="blue_color"></span>
|
||||
<span class="yellow_color"></span>
|
||||
<span class="purple_color"></span>
|
||||
<span class="pink_color"></span>
|
||||
<span class="green_color"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="preloader">
|
||||
<div class="spinner">
|
||||
<div class="double-bounce1"></div>
|
||||
<div class="double-bounce2"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section id="services" class="services-section section-padding">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="section-title">
|
||||
<h2><span class="theme-color">What i offer</span> Services</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-sm-4 col-xs-12">
|
||||
<div class="single-services text-center wow fadeInUp" data-wow-delay="0.2s">
|
||||
<div class="servise-icon">
|
||||
<i class="fa fa-pencil-square"></i>
|
||||
</div>
|
||||
<h4>design</h4>
|
||||
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-4 col-xs-12">
|
||||
<div class="single-services text-center wow fadeInUp" data-wow-delay="0.4s">
|
||||
<div class="servise-icon">
|
||||
<i class="fa fa-codepen"></i>
|
||||
</div>
|
||||
<h4>idea</h4>
|
||||
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-4 col-xs-12">
|
||||
<div class="single-services last-service text-center wow fadeInUp" data-wow-delay="0.6s">
|
||||
|
||||
<div class="servise-icon">
|
||||
|
||||
<i class="fa fa-laptop"></i>
|
||||
|
||||
</div>
|
||||
|
||||
<h4>development</h4>
|
||||
|
||||
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<div id="quotes" class="quotes-area section-padding">
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-12">
|
||||
|
||||
<div class="quotes-content text-center">
|
||||
|
||||
<h3>Let's work together!</h3>
|
||||
|
||||
<p>I am available for freelance projects.</p>
|
||||
|
||||
<a class="scroll-btn btn theme-color" href="#contact">Get Quotes</a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="review" class="review-section section-padding">
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-12">
|
||||
|
||||
<div class="section-title">
|
||||
|
||||
<h2><span class="theme-color">Here's what others say about me</span> Reviews</h2>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
|
||||
<div class="review-full-area">
|
||||
|
||||
<div class="review-list">
|
||||
|
||||
<div class="single-review">
|
||||
|
||||
<!-- start single carousel item -->
|
||||
|
||||
<div class="review-content">
|
||||
|
||||
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to
|
||||
make a type specimen book.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<h5 class="author"> Paul Flavius. <span>CEO Devsoft Inc</span></h5>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- end single carousel item -->
|
||||
|
||||
<div class="single-review">
|
||||
|
||||
<!-- start single carousel item -->
|
||||
|
||||
<div class="review-content">
|
||||
|
||||
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to
|
||||
make a type specimen book.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<h5 class="author"> Paul Flavius,<span>CEO Devsoft Inc</span></h5>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- end single carousel item -->
|
||||
|
||||
<div class="single-review">
|
||||
|
||||
<!-- start single carousel item -->
|
||||
|
||||
<div class="review-content">
|
||||
|
||||
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to
|
||||
make a type specimen book.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<h5 class="author"> Paul Flavius,<span>CEO Devsoft Inc</span></h5>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- end start single carousel item -->
|
||||
|
||||
<div class="single-review">
|
||||
|
||||
<!-- start single carousel item -->
|
||||
|
||||
<div class="review-content">
|
||||
|
||||
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to
|
||||
make a type specimen book.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<h5 class="author"> Paul Flavius,<span>CEO Devsoft Inc</span></h5>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- end start single carousel item -->
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
Reference in New Issue
Block a user