فهرست منبع

add admin page

iaun 5 سال پیش
والد
کامیت
f3ccbc706f
10فایلهای تغییر یافته به همراه808 افزوده شده و 90 حذف شده
  1. 1 0
      db.go
  2. 5 1
      errors.go
  3. 31 5
      handler.go
  4. 186 6
      handler_functions.go
  5. 49 1
      request.go
  6. 322 0
      static/admin/home.html
  7. 117 0
      static/admin/index.html
  8. 8 8
      static/home.html
  9. 36 0
      struct.go
  10. 53 69
      timer.go

+ 1 - 0
db.go

@@ -16,6 +16,7 @@ func init() {
 	if err != nil {
 		fmt.Println(err)
 	}
+	db.SetMaxOpenConns(100)
 	err = db.Ping()
 	if err != nil {
 		fmt.Println(err)

+ 5 - 1
errors.go

@@ -17,7 +17,11 @@ const (
 	ERR_WRONG_PASSWORD     = "用户名或密码错误"
 	ERR_USERNAME_LENGTH    = "用户名长度需在1-18位"
 	ERR_PASSWORD_LENGTH    = "密码长度需在6-18位"
-	ERR_KEY                = "暗号不匹配!有内鬼,终止交易"
+	ERR_KEY                = "暗号不匹配!"
+
+	// admin
+	ERR_EMPTY_KEY = "验证码不能为空"
+	ERR_WRONG_KEY = "验证码错误"
 
 	// request
 	ERR_REQUESTING = "正在请求中,请等待请求完成"

+ 31 - 5
handler.go

@@ -22,9 +22,15 @@ func init() {
 
 	// log
 	http.HandleFunc("/api/log/get", getLogHandler)
-	http.HandleFunc("/api/log/get/admin", getLogAdminHandler)
+	// http.HandleFunc("/api/log/get/admin", getLogAdminHandler)
 	http.HandleFunc("/api/log/get/details", getLogDetailsHandler)
 
+	// admin
+	http.HandleFunc("/api/admin/login", adminLoginHandler)
+	http.HandleFunc("/api/admin/get", adminGetDataHandler)
+	http.HandleFunc("/api/admin/login/cookie", adminCookieLoginHandler)
+	http.HandleFunc("/api/admin/key/get", adminGetKeyHandler)
+
 }
 
 func loginHandler(w http.ResponseWriter, r *http.Request) {
@@ -72,12 +78,32 @@ func getLogHandler(w http.ResponseWriter, r *http.Request) {
 	f_getLog(w, r)
 }
 
-func getLogAdminHandler(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-Type", "application/json")
-	f_getLogAdmin(w, r)
-}
+// func getLogAdminHandler(w http.ResponseWriter, r *http.Request) {
+// 	w.Header().Set("Content-Type", "application/json")
+// 	f_getLogAdmin(w, r)
+// }
 
 func getLogDetailsHandler(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	f_getLogDetails(w, r)
 }
+
+func adminLoginHandler(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	f_adminLogin(w, r)
+}
+
+func adminGetDataHandler(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	f_adminGetData(w, r)
+}
+
+func adminCookieLoginHandler(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	f_adminCookieLogin(w, r)
+}
+
+func adminGetKeyHandler(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	f_adminGetKey(w, r)
+}

+ 186 - 6
handler_functions.go

@@ -22,6 +22,19 @@ func f_cookieGetUid(r *http.Request) (int, bool) {
 	return uid, true
 }
 
+// return uid,isvalid
+func f_adminCookieGetUid(r *http.Request) (int, bool) {
+	token, err := r.Cookie("admin_token")
+	if err != nil {
+		return -1, false
+	}
+	uid, err := parseToken(token.Value)
+	if err != nil {
+		return -1, false
+	}
+	return uid, true
+}
+
 func f_readBody(r *http.Request) ([]byte, error) {
 	return ioutil.ReadAll(r.Body)
 }
@@ -245,6 +258,7 @@ func f_getUserInfo(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	rows, err := db_query("select `name` from `user` where id = ? LIMIT 1", uid)
+	defer rows.Close()
 	if err != nil {
 		fmt.Fprint(w, simpleJsonMsg(ERR_DB, 0))
 		return
@@ -441,20 +455,186 @@ func f_getLog(w http.ResponseWriter, r *http.Request) {
 	fmt.Fprint(w, logData)
 }
 
-func f_getLogAdmin(w http.ResponseWriter, r *http.Request) {
+// func f_getLogAdmin(w http.ResponseWriter, r *http.Request) {
+// 	_, valid := f_cookieGetUid(r)
+// 	if !valid {
+// 		fmt.Fprint(w, simpleJsonMsg(ERR_TOKEN, 0))
+// 		return
+// 	}
+// 	fmt.Fprint(w, "")
+// }
+
+func f_getLogDetails(w http.ResponseWriter, r *http.Request) {
 	_, valid := f_cookieGetUid(r)
 	if !valid {
 		fmt.Fprint(w, simpleJsonMsg(ERR_TOKEN, 0))
 		return
 	}
-	fmt.Fprint(w, logAdmin)
+	fmt.Fprint(w, logDetail)
 }
 
-func f_getLogDetails(w http.ResponseWriter, r *http.Request) {
-	_, valid := f_cookieGetUid(r)
-	if !valid {
+func f_adminLogin(w http.ResponseWriter, r *http.Request) {
+	body, err := f_readBody(r)
+	if err != nil {
+		fmt.Fprint(w, simpleJsonMsg(ERR_READ_BODY, 0))
+		return
+	}
+	data := &HandlerAdminLogin{}
+	err = json.Unmarshal(body, data)
+	if err != nil {
+		fmt.Fprint(w, simpleJsonMsg(ERR_LOAD_JSON, 0))
+		return
+	}
+	if data.Key == "" {
+		fmt.Fprint(w, simpleJsonMsg(ERR_EMPTY_KEY, 0))
+		return
+	}
+	if data.Key != "adminkey" {
+		fmt.Fprint(w, simpleJsonMsg(ERR_WRONG_KEY, 0))
+		return
+	}
+
+	token, err := createToken(-1)
+	if err != nil {
+		fmt.Println(err)
+		fmt.Fprint(w, simpleJsonMsg(ERR_UNKNOWN, 0))
+	} else {
+		ck := &http.Cookie{
+			Name:   "admin_token",
+			Value:  token,
+			Path:   "/",
+			MaxAge: 86400,
+		}
+		http.SetCookie(w, ck)
+		fmt.Fprint(w, simpleJsonMsg("success", 1))
+	}
+}
+
+func f_adminGetData(w http.ResponseWriter, r *http.Request) {
+	uid, valid := f_adminCookieGetUid(r)
+	if !valid || uid != -1 {
 		fmt.Fprint(w, simpleJsonMsg(ERR_TOKEN, 0))
 		return
 	}
-	fmt.Fprint(w, logDetail)
+	body, err := f_readBody(r)
+	if err != nil {
+		fmt.Fprint(w, simpleJsonMsg(ERR_READ_BODY, 0))
+		return
+	}
+	reqData := &HandlerAdminGetDataRequest{}
+	err = json.Unmarshal(body, reqData)
+	if err != nil {
+		fmt.Fprint(w, simpleJsonMsg(ERR_LOAD_JSON, 0))
+		return
+	}
+	if reqData.Page <= 0 {
+		reqData.Page = 1
+	}
+	if reqData.Length <= 0 {
+		reqData.Length = 10
+	}
+	rtnData := &HandlerAdminDataReturn{}
+	rows, err := db_query("call get_log_admin(?,?)", reqData.Page, reqData.Length)
+	defer rows.Close()
+	if err != nil {
+		fmt.Fprint(w, simpleJsonMsg(ERR_DB, 0))
+		return
+	}
+	if rows.Next() {
+		rows.Scan(&rtnData.Count)
+	}
+	if !rows.NextResultSet() {
+		fmt.Fprint(w, simpleJsonMsg(ERR_DB, 0))
+		return
+	}
+	data := []*HandlerAdminGetData{}
+	for rows.Next() {
+		d := &HandlerAdminGetData{}
+		err = rows.Scan(&d.Time, &d.Name, &d.Type, &d.Msg)
+		if err != nil {
+			fmt.Println("admin get log error")
+			fmt.Println(err)
+		}
+		data = append(data, d)
+	}
+	rtnData.Data = data
+	rtn := &MsgInterface{}
+	rtn.Success = 1
+	rtn.Msg = rtnData
+	j, err := json.Marshal(rtn)
+	if err != nil {
+		fmt.Fprint(w, simpleJsonMsg(ERR_LOAD_JSON, 0))
+		return
+	}
+	fmt.Fprint(w, string(j))
+
+}
+
+func f_adminCookieLogin(w http.ResponseWriter, r *http.Request) {
+	uid, valid := f_adminCookieGetUid(r)
+	if valid && uid == -1 {
+		// 刷新cookie时间
+		token, err := createToken(uid)
+		if err != nil {
+			fmt.Println(err)
+			fmt.Fprint(w, simpleJsonMsg(ERR_UNKNOWN, 0))
+		} else {
+			ck := &http.Cookie{
+				Name:   "admin_token",
+				Value:  token,
+				Path:   "/",
+				MaxAge: 86400,
+			}
+			http.SetCookie(w, ck)
+			fmt.Fprint(w, simpleJsonMsg("success", 1))
+		}
+	} else {
+		fmt.Fprint(w, simpleJsonMsg(ERR_TOKEN, 0))
+	}
+}
+
+func f_adminGetKey(w http.ResponseWriter, r *http.Request) {
+	uid, valid := f_adminCookieGetUid(r)
+	if !valid || uid != -1 {
+		fmt.Fprint(w, simpleJsonMsg(ERR_TOKEN, 0))
+		return
+	}
+	body, err := f_readBody(r)
+	if err != nil {
+		fmt.Fprint(w, simpleJsonMsg(ERR_READ_BODY, 0))
+		return
+	}
+	reqData := &HandlerGetKeyReq{}
+	err = json.Unmarshal(body, &reqData)
+	if err != nil {
+		fmt.Fprint(w, simpleJsonMsg(ERR_LOAD_JSON, 0))
+		return
+	}
+	rows, err := db_query("select UNIX_TIMESTAMP(`time`), `admin_msg` from `log` where `type` = 3 AND `uid` = ?", reqData.Id)
+	defer rows.Close()
+	if err != nil {
+		fmt.Fprint(w, simpleJsonMsg(ERR_DB, 0))
+		return
+	}
+	arr := []*HandlerGetKeyData{}
+	for rows.Next() {
+		d := &HandlerGetKeyData{}
+		err = rows.Scan(&d.Time, &d.Msg)
+		if err != nil {
+			fmt.Println("get key err")
+			fmt.Println(err)
+		}
+		arr = append(arr, d)
+	}
+	rtn := &MsgInterface{
+		Success: 1,
+		Msg:     arr,
+	}
+	j, err := json.Marshal(rtn)
+	if err != nil {
+		fmt.Fprint(w, simpleJsonMsg(ERR_LOAD_JSON, 0))
+		return
+	}
+	fmt.Fprint(w, string(j))
+
 }

+ 49 - 1
request.go

@@ -6,6 +6,7 @@ import (
 	"io/ioutil"
 	"net/http"
 	"strconv"
+	"strings"
 	"time"
 )
 
@@ -41,7 +42,54 @@ func f_send_db(uid int, status int, msg string, url string) bool {
 	return true
 }
 
-func f_send(uid int, url string) {
+func f_send(uid int, u string) {
+	client := &http.Client{
+		Timeout: time.Duration(10 * time.Second),
+	}
+
+	req, err := http.NewRequest("POST", u, strings.NewReader("reservationid=5000000"))
+	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+	// req = req.WithContext(ctx)
+	if err != nil {
+		f_send_db(uid, 2, fmt.Sprintf("%s", err), u)
+		fmt.Println("err newrequest")
+		fmt.Println(err)
+		return
+	}
+	startTime := time.Now()
+	resp, err := client.Do(req)
+	if err != nil {
+		f_send_db(uid, 2, fmt.Sprintf("%s", err), u)
+		fmt.Println("err do")
+		fmt.Println(err)
+		return
+	}
+	defer func() {
+		_ = resp.Body.Close()
+	}()
+	if resp.StatusCode == 200 {
+		fmt.Println("OK")
+		since := time.Since(startTime)
+		fmt.Println(since.Seconds())
+	} else {
+		fmt.Println("HTTP " + strconv.Itoa(resp.StatusCode))
+		f_send_db(uid, 2, "HTTP "+strconv.Itoa(resp.StatusCode), u)
+		return
+	}
+	fmt.Println("body")
+	body, _ := ioutil.ReadAll(resp.Body)
+	s := string(body)
+	fmt.Println(s)
+	if strings.Contains(s, "Unicorn Access Code: NSWMCHZZsDmTLLGkmFiFupdLG") && strings.Contains(s, "Unicorn.Rentals_v") && strings.Contains(s, "Reservation Name: Miss Alba Schiller") {
+		// 匹配成功
+		f_send_db(uid, 1, "结果匹配成功", u)
+	} else {
+		f_send_db(uid, 2, "结果不匹配", u)
+	}
+}
+
+// backup
+func f_send_get(uid int, url string) {
 	client := &http.Client{
 		Timeout: time.Duration(10 * time.Second),
 	}

+ 322 - 0
static/admin/home.html

@@ -0,0 +1,322 @@
+<html lang="zh">
+
+<head>
+    <title>管理员主页</title>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
+    <script src="/jquery.min.js"></script>
+    <script src="/vue.js"></script>
+    <script src="/elementui.js"></script>
+    <script src="/js.cookie.min.js"></script>
+    <link rel="stylesheet" type="text/css" href="/elementui.css">
+
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+        }
+
+        .font {
+            font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
+        }
+
+        .right {
+            float: left;
+            padding: 20px;
+            width: calc(100% - 240px);
+            overflow: auto;
+            height: calc(100% - 40px);
+        }
+    </style>
+</head>
+
+<body>
+
+    <div id="app">
+        <div style="float:left; width:200px; height: 100%;">
+            <!-- 菜单项 -->
+            <el-menu style="height:100%;" :default-active="activeIndex" @select="handleSelect">
+                <el-menu-item index="1">
+                    <i class="el-icon-coin"></i>
+                    <span slot="title">日志</span>
+                </el-menu-item>
+                <el-menu-item index="2">
+                    <i class="el-icon-zoom-in"></i>
+                    <span slot="title">详情</span>
+                </el-menu-item>
+                <li style="padding: 0 20px;box-sizing: border-box;text-align: center;">
+                    <el-popconfirm title="确定要退出登录吗?" @confirm="logout">
+                        <el-button slot="reference" style="margin-top: 20px;">退出登录</el-button>
+                    </el-popconfirm>
+                </li>
+            </el-menu>
+
+        </div>
+        <div class="right" v-show="activeIndex==='1'">
+            <el-table :data="logData" stripe style="width: 100%;">
+                <el-table-column prop="time" label="时间" width="180">
+                </el-table-column>
+                <el-table-column prop="name" label="姓名" width="310">
+                </el-table-column>
+                <el-table-column prop="type" label="类型" width="180">
+                </el-table-column>
+                <el-table-column prop="msg" label="消息">
+                </el-table-column>
+            </el-table>
+            <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="data.page" :page-size="data.len" :page-sizes="[10, 20, 30, 50, 100]" layout="sizes, total, prev, pager, next" :total="data.count">
+            </el-pagination>
+        </div>
+        <div class="right" v-show="activeIndex==='2'">
+            <el-table :data="detailsData" stripe style="width: 100%;">
+                <el-table-column prop="name" label="姓名" width="310">
+                </el-table-column>
+                <el-table-column prop="time" label="首次完成时间" width="180">
+                </el-table-column>
+                <el-table-column prop="fail" label="失败提交次数" width="180">
+                </el-table-column>
+                <el-table-column prop="fail" label="查看实验账号密码">
+                    <template slot-scope="scope">
+                        <el-button @click="handleClick(scope.row.id, scope.row.name)">查看</el-button>
+                    </template>
+                </el-table-column>
+
+            </el-table>
+        </div>
+        <div>
+            <el-dialog :title="showKeyUser" :visible="userKey!==null" width="50%" :show-close="false">
+                <el-table :data="msgData" stripe style="height: 50%;" height="50%">
+                    <el-table-column prop="time" label="时间">
+                    </el-table-column>
+                    <el-table-column prop="msg" label="账号密码">
+                    </el-table-column>
+                </el-table>
+                <span slot="footer" class="dialog-footer">
+                <el-button type="primary" @click="handleClose">确定</el-button>
+                </span>
+            </el-dialog>
+
+        </div>
+    </div>
+
+    <script>
+        var app;
+        var vue = new Vue({
+            el: '#app',
+            data: {
+                apiUrl: '/api',
+                isLoading: false,
+                activeIndex: "",
+                data: {
+                    count: 0,
+                    page: 1,
+                    len: 10,
+                    data: [],
+                    interval: -1
+                },
+                details: {
+                    data: [],
+                    interval: -1
+                },
+                userKey: null,
+                showKeyUser: ""
+            },
+            computed: {
+                msgData: function() {
+                    if (!this.userKey) {
+                        return []
+                    }
+                    for (var i = 0, j = this.userKey.length; i < j; i++) {
+                        if (this.userKey[i]["time"] === 0) {
+                            this.userKey[i]["time"] = "";
+                        }
+                        else {
+                            this.userKey[i]["time"] = this.formatDate(this.userKey[i]["time"]);
+                        }
+
+                    }
+                    return this.userKey;
+                },
+                detailsData: function() {
+                    for (var i = 0, j = this.details.data.length; i < j; i++) {
+                        if (this.details.data[i]["time"] === 0) {
+                            this.details.data[i]["time"] = "";
+                        }
+                        else {
+                            this.details.data[i]["time"] = this.formatDate(this.details.data[i]["time"]);
+                        }
+
+                    }
+                    return this.details.data;
+                },
+                logData: function() {
+                    for (var i = 0, j = this.data.data.length; i < j; i++) {
+                        if (this.data.data[i]["time"] === 0) {
+                            this.data.data[i]["time"] = "";
+                        }
+                        else {
+                            this.data.data[i]["time"] = this.formatDate(this.data.data[i]["time"]);
+                        }
+                        switch (this.data.data[i]["type"]) {
+                            case 0:
+                                this.data.data[i]["type"] = "提交URL";
+                                break;
+                            case 1:
+                                this.data.data[i]["type"] = "URL结果匹配成功!!";
+                                break;
+                            case 2:
+                                this.data.data[i]["type"] = "URL结果匹配失败";
+                                break;
+                            case 3:
+                                this.data.data[i]["type"] = "提交实验账号";
+                                break;
+                            default:
+                                this.data.data[i]["type"] = "";
+                                break;
+                        }
+
+                    }
+                    return this.data.data;
+                },
+            },
+            methods: {
+                req(url, method, data) {
+                    data = data ? JSON.stringify(data) : "";
+                    return new Promise(function(resolve, reject) {
+                        $.ajax({
+                            type: method,
+                            url: url,
+                            data: data ? data : "",
+                            contentType: data ? "application/json" : "",
+                            success: function(data) {
+                                resolve(data);
+                            },
+                            error: function(err) {
+                                reject(err);
+                            }
+                        });
+                    });
+                },
+                getDetails() {
+                    this.req(this.apiUrl + "/log/get/details", "GET", null).then((data) => {
+                        this.details.data = data;
+                    }).catch((err) => {
+                        this.logoutAlert("服务器错误8");
+                    });
+                },
+                logoutAlert(msg) {
+                    this.$alert(msg, '错误', {
+                        showClose: false,
+                        confirmButtonText: '重新登录',
+                        callback: action => {
+                            this.logout();
+                        }
+                    });
+                },
+                logout() {
+                    Cookies.set("admin_token", "");
+                    location.href = "/admin";
+                },
+                getData() {
+                    this.req(this.apiUrl + "/admin/get", "POST", { page: this.data.page, length: this.data.len }).then((data) => {
+                        if (data && data["success"]) {
+                            this.data.data = data["msg"]["data"];
+                            this.data.count = data["msg"]["count"];
+                        }
+                        else {
+                            logoutAlert("无法获取数据");
+                        }
+                    }).catch((err) => {
+                        logoutAlert("未知错误");
+                    });
+                },
+                formatDate: function(timestamp) {
+                    var d = new Date(timestamp * 1000);
+                    return d.getFullYear() + "-" + ((d.getMonth() + 1 >= 10) ? (d.getMonth() + 1) : "0" + (d.getMonth() + 1)) + "-" + ((d.getDate() >= 10) ? d.getDate() + "" : "0" + d.getDate()) + " " + ((d.getHours() >= 10) ? d.getHours() + "" : "0" + d.getHours()) + ":" + ((d.getMinutes() >= 10) ? d.getMinutes() + "" : "0" + d.getMinutes()) + ":" + ((d.getSeconds() >= 10) ? d.getSeconds() + "" : "0" + d.getSeconds());
+                },
+                handleSizeChange: function(size) {
+                    this.data.len = size;
+                    this.getData();
+                },
+                handleCurrentChange: function(page) {
+                    this.data.page = page;
+                    this.getData();
+                },
+                handleSelect: function(index) {
+                    if (index === this.activeIndex) {
+                        return;
+                    }
+                    if (index === "1") {
+                        this.getData();
+                        var self = this;
+                        this.data.interval = setInterval(function() { self.getData(); }, 3000);
+                    }
+                    else {
+                        clearInterval(this.data.interval);
+                    }
+                    if (index === "2") {
+                        this.getDetails();
+                        var self = this;
+                        this.details.interval = setInterval(function() { self.getDetails(); }, 3000);
+                    }
+                    else {
+                        clearInterval(this.details.interval);
+                    }
+                    Cookies.set("admin_page", index);
+                    this.activeIndex = index;
+                },
+                handleClick: function(id, name) {
+                    this.showKeyUser = name;
+                    this.req(this.apiUrl + "/admin/key/get", "POST", { id: id }).then((data) => {
+                        if (data["success"]) {
+                            this.userKey = data["msg"];
+                        }
+                        else {
+                            this.$message.closeAll();
+                            this.$message({
+                                type: 'error',
+                                showClose: true,
+                                message: data["msg"]
+                            });
+                        }
+                    }).catch((err) => {
+                        this.$message.closeAll();
+                        this.$message({
+                            type: 'error',
+                            showClose: true,
+                            message: "服务器错误"
+                        });
+                    });
+                },
+                handleClose: function() {
+                    this.userKey = null;
+                }
+            },
+            mounted: function() {
+                app = this;
+                var token = Cookies.get("admin_token");
+                if (token) {
+                    this.req(this.apiUrl + "/admin/login/cookie", "GET", null).then((data) => {
+                        if (!data || !data["success"]) {
+                            Cookies.set("admin_token", "");
+                            logoutAlert(data["msg"]);
+                        }
+                    }).catch(() => {
+                        logoutAlert(data["msg"]);
+                        Cookies.set("admin_token", "");
+                    });
+                }
+                var page = Cookies.get("admin_page");
+                if (page) {
+                    this.handleSelect(page);
+                }
+                else {
+                    this.handleSelect("1");
+                }
+                // this.getData();
+                // this.getDetails();
+            }
+        });
+    </script>
+</body>
+
+</html>

+ 117 - 0
static/admin/index.html

@@ -0,0 +1,117 @@
+<html lang="zh">
+
+<head>
+    <title>登录</title>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
+    <script src="/jquery.min.js"></script>
+    <script src="/vue.js"></script>
+    <script src="/elementui.js"></script>
+    <script src="/js.cookie.min.js"></script>
+    <link rel="stylesheet" type="text/css" href="/elementui.css">
+
+    <style>
+        .login-card {
+            width: 350px;
+            margin: 20px auto 0 auto;
+        }
+    </style>
+</head>
+
+<body>
+
+    <div id="app">
+        <div>
+            <el-card class="box-card login-card">
+                <div slot="header">
+                    <span>身份验证</span>
+                </div>
+                <el-input :disabled="isLoading" minlength="6" maxlength="18" @keydown.native.enter="login" v-model="password" placeholder="验证码" type="password"></el-input>
+                <el-button @click="login" style="margin-top:20px;display: block;margin-left: auto;margin-right: auto;" type="primary" plain :loading="isLoading">登录</el-button>
+            </el-card>
+        </div>
+    </div>
+
+    <script>
+        var app;
+        var vue = new Vue({
+            el: '#app',
+            data: {
+                apiUrl: '/api',
+                isLoading: false,
+                password: ""
+            },
+            methods: {
+                req(url, method, data) {
+                    data = data ? JSON.stringify(data) : "";
+                    return new Promise(function(resolve, reject) {
+                        $.ajax({
+                            type: method,
+                            url: url,
+                            data: data ? data : "",
+                            contentType: data ? "application/json" : "",
+                            success: function(data) {
+                                resolve(data);
+                            },
+                            error: function(err) {
+                                reject(err);
+                            }
+                        });
+                    });
+                },
+                login() {
+                    this.isLoading = true;
+                    this.req(this.apiUrl + "/admin/login", "POST", { "key": this.password }).then((data) => {
+                        this.isLoading = false;
+                        if (data["success"] === 1) {
+                            this.$message.closeAll();
+                            this.$message({
+                                type: 'success',
+                                showClose: true,
+                                message: "验证成功"
+                            });
+                            location.href = "/admin/home.html";
+                        }
+                        else {
+                            this.$message.closeAll();
+                            this.$message({
+                                type: 'error',
+                                showClose: true,
+                                message: data["msg"]
+                            });
+                        }
+                    }).catch((err) => {
+                        this.isLoading = false;
+                        this.$message.closeAll();
+                        this.$message({
+                            type: 'error',
+                            showClose: true,
+                            message: "服务器错误"
+                        });
+                    });
+                },
+            },
+            mounted: function() {
+                app = this;
+                var token = Cookies.get("admin_token");
+                if (token) {
+                    this.isLoading = true;
+                    this.req(this.apiUrl + "/admin/login/cookie", "GET", null).then((data) => {
+                        this.isLoading = false;
+                        if (data && data["success"]) {
+                            location.href = "/admin/home.html";
+                        }
+                        else {
+                            Cookies.set("admin_token", "");
+                        }
+                    }).catch(() => {
+                        this.isLoading = false;
+                        Cookies.set("admin_token", "");
+                    });
+                }
+            }
+        });
+    </script>
+</body>
+
+</html>

+ 8 - 8
static/home.html

@@ -39,10 +39,10 @@
         <div style="float:left; width:200px; height: 100%;">
             <!-- 菜单项 -->
             <el-menu style="height:100%;" :default-active="activeIndex" class="el-menu-vertical-demo" @select="handleSelect">
-                <el-menu-item index="1">
+                <!--<el-menu-item index="1">
                     <i class="el-icon-menu"></i>
                     <span slot="title">帮助</span>
-                </el-menu-item>
+                </el-menu-item>-->
                 <el-menu-item index="2">
                     <i class="el-icon-document"></i>
                     <span slot="title">提交</span>
@@ -71,7 +71,7 @@
         <!--help-->
         <div v-show="activeIndex==='1'" class="right">
             <p style="margin-bottom: 20px;">当前用户:{{name}}</p>
-            <p>干就完事</p>
+            <p>帮助页面</p>
         </div>
         <!--submit-->
         <div v-show="activeIndex==='2'" class="right" v-loading="!submit.urlOK || !submit.keyOK">
@@ -104,11 +104,11 @@
             <p style="margin-bottom: 20px;">当前用户:{{name}}</p>
             <!-- v-loading="!log.reqOK"-->
             <el-table :data="logData" stripe style="width: 100%;">
-                <el-table-column prop="name" label="姓名" width="300">
+                <el-table-column prop="name" label="姓名" width="310">
                 </el-table-column>
                 <el-table-column prop="time" label="时间" width="180">
                 </el-table-column>
-                <el-table-column prop="type" label="操作">
+                <el-table-column prop="type" label="内容">
                 </el-table-column>
             </el-table>
         </div>
@@ -116,7 +116,7 @@
         <div v-show="activeIndex==='4'" class="right">
             <p style="margin-bottom: 20px;">当前用户:{{name}}</p>
             <el-table :data="detailsData" stripe style="width: 100%;">
-                <el-table-column prop="name" label="姓名" width="300">
+                <el-table-column prop="name" label="姓名" width="310">
                 </el-table-column>
                 <el-table-column prop="time" label="首次完成时间" width="180">
                 </el-table-column>
@@ -453,14 +453,14 @@
             },
             mounted: function() {
                 app = this;
-                var page = Cookies.get("page")
+                this.getUser();
+                var page = Cookies.get("page");
                 if (page) {
                     this.handleSelect(page);
                 }
                 else {
                     this.handleSelect("2");
                 }
-                this.getUser();
                 // this.getLog();
             }
         });

+ 36 - 0
struct.go

@@ -51,6 +51,42 @@ type HandlerKey struct {
 	SK string `json:"sk"`
 }
 
+// admin login
+type HandlerAdminLogin struct {
+	Key string `json:"key"`
+}
+
+// admin get data request
+type HandlerAdminGetDataRequest struct {
+	Page   int `json:"page"`
+	Length int `json:"length"`
+}
+
+// admin data
+type HandlerAdminGetData struct {
+	Time int    `json:"time"`
+	Name string `json:"name"`
+	Type int    `json:"type"`
+	Msg  string `json:"msg"`
+}
+
+// admin return data
+type HandlerAdminDataReturn struct {
+	Count int                    `json:"count"`
+	Data  []*HandlerAdminGetData `json:"data"`
+}
+
+// admin get key req
+type HandlerGetKeyReq struct {
+	Id int `json:"id"`
+}
+
+// admin get key data
+type HandlerGetKeyData struct {
+	Time int    `json:"time"`
+	Msg  string `json:"msg"`
+}
+
 // *data
 // user
 type LogData struct {

+ 53 - 69
timer.go

@@ -8,7 +8,8 @@ import (
 )
 
 var logData string
-var logAdmin string
+
+// var logAdmin string
 var logDetail string
 
 func init() {
@@ -17,78 +18,61 @@ func init() {
 
 func loadLog() {
 	logData = "[]"
-	logAdmin = "[]"
+	// logAdmin = "[]"
 	logDetail = "[]"
-	ticker := time.NewTicker(3 * time.Second)
+	ticker := time.NewTicker(1 * time.Second)
 	for {
-		// user
-		rows, err := db.Query("select UNIX_TIMESTAMP(`log`.`time`), `user`.`name`, `log`.`type` from `log` LEFT JOIN `user` on `log`.`uid` = `user`.`id` where `log`.`type` != 0 AND `log`.`type` != 3 order by `log`.`time` desc LIMIT 50")
-		if err != nil {
-			logData = "[]"
-			fmt.Printf("loadLog query error: %s\n", err)
-			continue
-		}
-		var data []*LogData
-		for rows.Next() {
-			d := &LogData{}
-			rows.Scan(&d.Time, &d.Name, &d.Type)
-			data = append(data, d)
-		}
-		rows.Close()
-		j, err := json.Marshal(data)
-		if err != nil {
-			logData = "[]"
-			fmt.Printf("loadLog json error: %s\n", err)
-			continue
-		}
-		logData = string(j)
+		timer_get()
+		<-ticker.C
+	}
+}
 
-		// admin
-		rows, err = db.Query("select UNIX_TIMESTAMP(`log`.`time`), `user`.`name`, `log`.`type`, `log`.`admin_msg` from `log` LEFT JOIN `user` on `log`.`uid` = `user`.`id` order by `log`.`time` desc")
-		if err != nil {
-			logAdmin = "[]"
-			fmt.Printf("loadLog query error: %s\n", err)
-			continue
-		}
-		var dataAdmin []*LogDataAdmin
-		for rows.Next() {
-			d := &LogDataAdmin{}
-			rows.Scan(&d.Time, &d.Name, &d.Type, &d.Msg)
-			dataAdmin = append(dataAdmin, d)
-		}
-		rows.Close()
-		j, err = json.Marshal(dataAdmin)
-		if err != nil {
-			logAdmin = "[]"
-			fmt.Printf("loadLog json error: %s\n", err)
-			continue
-		}
-		logAdmin = string(j)
+func timer_get() {
+	// user
+	rows, err := db.Query("select UNIX_TIMESTAMP(`log`.`time`), `user`.`name`, `log`.`type` from `log` LEFT JOIN `user` on `log`.`uid` = `user`.`id` where `log`.`type` != 0 AND `log`.`type` != 3 order by `log`.`time` desc LIMIT 50")
+	defer rows.Close()
+	if err != nil {
+		logData = "[]"
+		fmt.Printf("loadLog query error: %s\n", err)
+		return
+	}
+	var data []*LogData
+	for rows.Next() {
+		d := &LogData{}
+		rows.Scan(&d.Time, &d.Name, &d.Type)
+		data = append(data, d)
+	}
 
-		// select detail
-		rows, err = db.Query("call get_log_details()")
-		if err != nil {
-			logDetail = "[]"
-			fmt.Printf("loadLog query error: %s\n", err)
-			continue
-		}
-		var dataDetails []*LogDataDetails
-		for rows.Next() {
-			d := &LogDataDetails{}
-			var t sql.NullInt64
-			err = rows.Scan(&d.Uid, &d.Name, &t, &d.Fail)
-			d.Time = int(t.Int64)
-			dataDetails = append(dataDetails, d)
-		}
-		rows.Close()
-		j, err = json.Marshal(dataDetails)
-		if err != nil {
-			logDetail = "[]"
-			fmt.Printf("loadLog json error: %s\n", err)
-			continue
-		}
-		logDetail = string(j)
+	j, err := json.Marshal(data)
+	if err != nil {
+		logData = "[]"
+		fmt.Printf("loadLog json error: %s\n", err)
+		return
+	}
+	logData = string(j)
 
-		<-ticker.C
+	// select detail
+	rows, err = db.Query("call get_log_details()")
+	defer rows.Close()
+	if err != nil {
+		logDetail = "[]"
+		fmt.Printf("loadLog query error: %s\n", err)
+		return
+	}
+	var dataDetails []*LogDataDetails
+	for rows.Next() {
+		d := &LogDataDetails{}
+		var t sql.NullInt64
+		err = rows.Scan(&d.Uid, &d.Name, &t, &d.Fail)
+		d.Time = int(t.Int64)
+		dataDetails = append(dataDetails, d)
+	}
+
+	j, err = json.Marshal(dataDetails)
+	if err != nil {
+		logDetail = "[]"
+		fmt.Printf("loadLog json error: %s\n", err)
+		return
 	}
+	logDetail = string(j)
 }