Merge 049ca8487a
into d5026cf5ef
This commit is contained in:
commit
e346a97a51
8 changed files with 439 additions and 16 deletions
77
shadowsocks/api.py
Normal file
77
shadowsocks/api.py
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import config
|
||||||
|
import logging
|
||||||
|
import cymysql
|
||||||
|
import re
|
||||||
|
from flask import Flask,request,session,redirect,render_template
|
||||||
|
if config.LOG_ENABLE:
|
||||||
|
logging.basicConfig(
|
||||||
|
filename=config.LOG_FILE,
|
||||||
|
level=config.LOG_LEVEL,
|
||||||
|
datefmt='%Y-%m-%d %H:%M:%S',
|
||||||
|
format='%(asctime)s %(levelname)s %(filename)s[%(lineno)d] %(message)s'
|
||||||
|
)
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.secret_key = 'asdjhlasdlkjahskldhakjshd782934879123987*(Z&*(&98237498'
|
||||||
|
|
||||||
|
def get_mysql_conn():
|
||||||
|
conn = cymysql.connect(host=config.MYSQL_HOST, port=config.MYSQL_PORT, user=config.MYSQL_USER,
|
||||||
|
passwd=config.MYSQL_PASS, db=config.MYSQL_DB, charset='utf8')
|
||||||
|
return conn;
|
||||||
|
def validateEmail(email):
|
||||||
|
if len(email) > 4:
|
||||||
|
if re.match("\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", email) != None:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
@app.route("/")
|
||||||
|
def index():
|
||||||
|
if 'uid' in session:
|
||||||
|
conn = get_mysql_conn()
|
||||||
|
cur = conn.cursor(cursor=cymysql.cursors.DictCursor)
|
||||||
|
cur.execute("SELECT * FROM user WHERE id=%s",(session['uid']))
|
||||||
|
userinfo = cur.fetchone()
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
return render_template("index.html",user=userinfo)
|
||||||
|
return redirect("/login")
|
||||||
|
@app.route("/login",methods=['POST', 'GET'])
|
||||||
|
def login():
|
||||||
|
if request.method == 'POST':
|
||||||
|
email = request.form["username"]
|
||||||
|
password = request.form["password"]
|
||||||
|
if(validateEmail(email)):
|
||||||
|
conn = get_mysql_conn()
|
||||||
|
cur = conn.cursor(cursor=cymysql.cursors.DictCursor)
|
||||||
|
cur.execute("SELECT * FROM user WHERE u_email=%s",(email))
|
||||||
|
userinfo = cur.fetchone()
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
if(userinfo == None or userinfo["u_pwd"] != password):
|
||||||
|
return render_template("login.html", errormsg=u"用户不存在或者密码错误")
|
||||||
|
else:
|
||||||
|
session['uid']=userinfo['id']
|
||||||
|
return redirect("/")
|
||||||
|
else:
|
||||||
|
return render_template("login.html", errormsg=u"邮件格式错误")
|
||||||
|
else:
|
||||||
|
return render_template("login.html")
|
||||||
|
@app.route('/logout')
|
||||||
|
def logout():
|
||||||
|
session.pop('uid', None)
|
||||||
|
return redirect("/login")
|
||||||
|
@app.route('/update_ss_pwd',methods=['POST'])
|
||||||
|
def update_ss_pwd():
|
||||||
|
if 'uid' in session:
|
||||||
|
ss_pwd = request.form["ss_pwd"]
|
||||||
|
conn = get_mysql_conn()
|
||||||
|
cur = conn.cursor(cursor=cymysql.cursors.DictCursor)
|
||||||
|
update_sql = "update user set ss_pwd=%s where id=%s"
|
||||||
|
cur.execute(update_sql,(ss_pwd,session['uid']))
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
return u"修改成功"
|
||||||
|
else:
|
||||||
|
return u"修改失败"
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(host='0.0.0.0')
|
23
shadowsocks/config.py
Normal file
23
shadowsocks/config.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
#Config
|
||||||
|
MYSQL_HOST = '127.0.0.1'
|
||||||
|
MYSQL_PORT = 3306
|
||||||
|
MYSQL_USER = 'root'
|
||||||
|
MYSQL_PASS = ''
|
||||||
|
MYSQL_DB = 'shadowsocks'
|
||||||
|
|
||||||
|
SS_BIND_IP = '0.0.0.0'
|
||||||
|
SS_METHOD = 'rc4-md5'
|
||||||
|
MANAGE_BIND_IP = '127.0.0.1'
|
||||||
|
MANAGE_PORT = 3333
|
||||||
|
|
||||||
|
NODE = 'node1'
|
||||||
|
CHECKTIME = 15
|
||||||
|
SYNCTIME = 600
|
||||||
|
|
||||||
|
#LOG CONFIG
|
||||||
|
LOG_ENABLE = False
|
||||||
|
LOG_LEVEL = logging.INFO
|
||||||
|
LOG_FILE = '/var/log/shadowsocks.log'
|
||||||
|
|
143
shadowsocks/dbtransfer.py
Normal file
143
shadowsocks/dbtransfer.py
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: UTF-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import cymysql
|
||||||
|
import time
|
||||||
|
import socket
|
||||||
|
import config
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class DbTransfer(object):
|
||||||
|
instance = None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.last_get_transfer = {}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_instance():
|
||||||
|
if DbTransfer.instance is None:
|
||||||
|
DbTransfer.instance = DbTransfer()
|
||||||
|
return DbTransfer.instance
|
||||||
|
@staticmethod
|
||||||
|
def get_mysql_conn():
|
||||||
|
conn = cymysql.connect(host=config.MYSQL_HOST, port=config.MYSQL_PORT, user=config.MYSQL_USER,
|
||||||
|
passwd=config.MYSQL_PASS, db=config.MYSQL_DB, charset='utf8')
|
||||||
|
return conn;
|
||||||
|
@staticmethod
|
||||||
|
def send_command(cmd):
|
||||||
|
data = ''
|
||||||
|
try:
|
||||||
|
cli = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
cli.settimeout(1)
|
||||||
|
cli.sendto(cmd, ('%s' % (config.MANAGE_BIND_IP), config.MANAGE_PORT))
|
||||||
|
data, addr = cli.recvfrom(1500)
|
||||||
|
cli.close()
|
||||||
|
# TODO: bad way solve timed out
|
||||||
|
# time.sleep(0.05)
|
||||||
|
except:
|
||||||
|
logging.warn('send_command response')
|
||||||
|
return data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_servers_transfer():
|
||||||
|
dt_transfer = {}
|
||||||
|
cli = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
cli.settimeout(2)
|
||||||
|
cli.sendto('transfer: {}', ('%s' % (config.MANAGE_BIND_IP), config.MANAGE_PORT))
|
||||||
|
while True:
|
||||||
|
data, addr = cli.recvfrom(1500)
|
||||||
|
if data == 'e':
|
||||||
|
break
|
||||||
|
data = json.loads(data)
|
||||||
|
dt_transfer.update(data)
|
||||||
|
cli.close()
|
||||||
|
return dt_transfer
|
||||||
|
|
||||||
|
def push_db_all_user(self):
|
||||||
|
logging.info("push_db_all_user")
|
||||||
|
dt_transfer = self.get_servers_transfer()
|
||||||
|
last_time = time.time()
|
||||||
|
conn = DbTransfer.get_mysql_conn()
|
||||||
|
cur = conn.cursor()
|
||||||
|
for port in dt_transfer.keys():
|
||||||
|
update_sql='UPDATE user '+\
|
||||||
|
'set b_usage=b_usage+'+str(dt_transfer[port])+\
|
||||||
|
' where ss_port = '+str(port)
|
||||||
|
insert_sql='insert bandwidth_log value(null,"'+config.NODE+'",'+str(port)+','+str(dt_transfer[port])+','+str(int(last_time))+')'
|
||||||
|
logging.info(update_sql)
|
||||||
|
cur.execute(update_sql)
|
||||||
|
cur.execute(insert_sql)
|
||||||
|
cur.close()
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def pull_db_all_user():
|
||||||
|
conn = DbTransfer.get_mysql_conn()
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute("SELECT ss_port, ss_pwd, b_usage, b_max, u_status FROM user")
|
||||||
|
rows = []
|
||||||
|
for r in cur.fetchall():
|
||||||
|
rows.append(list(r))
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
return rows
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def del_server_out_of_bound_safe(rows):
|
||||||
|
for row in rows:
|
||||||
|
server = json.loads(DbTransfer.get_instance().send_command('stat: {"server_port":%s}' % row[0]))
|
||||||
|
if server['stat'] != 'ko':
|
||||||
|
if row[4] < 0:
|
||||||
|
# stop disable or switch off user
|
||||||
|
logging.info('db stop server at port [%s] reason: disable' % (row[0]))
|
||||||
|
DbTransfer.send_command('remove: {"server_port":%s}' % row[0])
|
||||||
|
elif row[2] >= row[3]:
|
||||||
|
# stop out bandwidth user
|
||||||
|
logging.info('db stop server at port [%s] reason: out bandwidth' % (row[0]))
|
||||||
|
DbTransfer.send_command('remove: {"server_port":%s}' % row[0])
|
||||||
|
if server['password'] != row[1]:
|
||||||
|
# password changed
|
||||||
|
logging.info('db stop server at port [%s] reason: password changed' % (row[0]))
|
||||||
|
DbTransfer.send_command('remove: {"server_port":%s}' % row[0])
|
||||||
|
else:
|
||||||
|
if row[4] > 0 and row[2] < row[3]:
|
||||||
|
logging.info('db start server at port [%s] pass [%s]' % (row[0], row[1]))
|
||||||
|
DbTransfer.send_command('add: {"server_port": %s, "password":"%s"}' % (row[0], row[1]))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def thread_db():
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
timeout = 30
|
||||||
|
socket.setdefaulttimeout(timeout)
|
||||||
|
while True:
|
||||||
|
logging.info('db thread_db')
|
||||||
|
try:
|
||||||
|
rows = DbTransfer.get_instance().pull_db_all_user()
|
||||||
|
DbTransfer.del_server_out_of_bound_safe(rows)
|
||||||
|
except Exception as e:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
logging.warn('db thread except:%s' % e)
|
||||||
|
finally:
|
||||||
|
time.sleep(config.CHECKTIME)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def thread_push():
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
timeout = 30
|
||||||
|
socket.setdefaulttimeout(timeout)
|
||||||
|
while True:
|
||||||
|
logging.info('db thread_push')
|
||||||
|
try:
|
||||||
|
DbTransfer.get_instance().push_db_all_user()
|
||||||
|
except Exception as e:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
logging.warn('db thread except:%s' % e)
|
||||||
|
finally:
|
||||||
|
time.sleep(config.SYNCTIME)
|
|
@ -67,7 +67,7 @@ class Manager(object):
|
||||||
exit(1)
|
exit(1)
|
||||||
self._loop.add(self._control_socket,
|
self._loop.add(self._control_socket,
|
||||||
eventloop.POLL_IN, self)
|
eventloop.POLL_IN, self)
|
||||||
self._loop.add_periodic(self.handle_periodic)
|
# self._loop.add_periodic(self.handle_periodic)
|
||||||
|
|
||||||
port_password = config['port_password']
|
port_password = config['port_password']
|
||||||
del config['port_password']
|
del config['port_password']
|
||||||
|
@ -107,6 +107,14 @@ class Manager(object):
|
||||||
logging.error("server not exist at %s:%d" % (config['server'],
|
logging.error("server not exist at %s:%d" % (config['server'],
|
||||||
port))
|
port))
|
||||||
|
|
||||||
|
def stat_port(self, config):
|
||||||
|
port = int(config['server_port'])
|
||||||
|
servers = self._relays.get(port, None)
|
||||||
|
if servers:
|
||||||
|
self._send_control_data(b'{"stat":"ok", "password":"%s"}' % servers[0]._config['password'])
|
||||||
|
else:
|
||||||
|
self._send_control_data(b'{"stat":"ko"}')
|
||||||
|
|
||||||
def handle_event(self, sock, fd, event):
|
def handle_event(self, sock, fd, event):
|
||||||
if sock == self._control_socket and event == eventloop.POLL_IN:
|
if sock == self._control_socket and event == eventloop.POLL_IN:
|
||||||
data, self._control_client_addr = sock.recvfrom(BUF_SIZE)
|
data, self._control_client_addr = sock.recvfrom(BUF_SIZE)
|
||||||
|
@ -114,22 +122,27 @@ class Manager(object):
|
||||||
if parsed:
|
if parsed:
|
||||||
command, config = parsed
|
command, config = parsed
|
||||||
a_config = self._config.copy()
|
a_config = self._config.copy()
|
||||||
if config:
|
if command == 'transfer':
|
||||||
# let the command override the configuration file
|
self.handle_periodic()
|
||||||
a_config.update(config)
|
|
||||||
if 'server_port' not in a_config:
|
|
||||||
logging.error('can not find server_port in config')
|
|
||||||
else:
|
else:
|
||||||
if command == 'add':
|
if config:
|
||||||
self.add_port(a_config)
|
# let the command override the configuration file
|
||||||
self._send_control_data(b'ok')
|
a_config.update(config)
|
||||||
elif command == 'remove':
|
if 'server_port' not in a_config:
|
||||||
self.remove_port(a_config)
|
logging.error('can not find server_port in config')
|
||||||
self._send_control_data(b'ok')
|
|
||||||
elif command == 'ping':
|
|
||||||
self._send_control_data(b'pong')
|
|
||||||
else:
|
else:
|
||||||
logging.error('unknown command %s', command)
|
if command == 'add':
|
||||||
|
self.add_port(a_config)
|
||||||
|
self._send_control_data(b'ok')
|
||||||
|
elif command == 'remove':
|
||||||
|
self.remove_port(a_config)
|
||||||
|
self._send_control_data(b'ok')
|
||||||
|
elif command == 'stat':
|
||||||
|
self.stat_port(a_config)
|
||||||
|
elif command == 'ping':
|
||||||
|
self._send_control_data(b'pong')
|
||||||
|
else:
|
||||||
|
logging.error('unknown command %s', command)
|
||||||
|
|
||||||
def _parse_command(self, data):
|
def _parse_command(self, data):
|
||||||
# commands:
|
# commands:
|
||||||
|
@ -161,7 +174,7 @@ class Manager(object):
|
||||||
# use compact JSON format (without space)
|
# use compact JSON format (without space)
|
||||||
data = common.to_bytes(json.dumps(data_dict,
|
data = common.to_bytes(json.dumps(data_dict,
|
||||||
separators=(',', ':')))
|
separators=(',', ':')))
|
||||||
self._send_control_data(b'stat: ' + data)
|
self._send_control_data(data)
|
||||||
|
|
||||||
for k, v in self._statistics.items():
|
for k, v in self._statistics.items():
|
||||||
r[k] = v
|
r[k] = v
|
||||||
|
@ -173,6 +186,7 @@ class Manager(object):
|
||||||
i = 0
|
i = 0
|
||||||
if len(r) > 0:
|
if len(r) > 0:
|
||||||
send_data(r)
|
send_data(r)
|
||||||
|
self._send_control_data('e')
|
||||||
self._statistics.clear()
|
self._statistics.clear()
|
||||||
|
|
||||||
def _send_control_data(self, data):
|
def _send_control_data(self, data):
|
||||||
|
|
37
shadowsocks/servers.py
Executable file
37
shadowsocks/servers.py
Executable file
|
@ -0,0 +1,37 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import thread
|
||||||
|
import time
|
||||||
|
import manager
|
||||||
|
import config
|
||||||
|
from dbtransfer import DbTransfer
|
||||||
|
if config.LOG_ENABLE:
|
||||||
|
logging.basicConfig(
|
||||||
|
filename=config.LOG_FILE,
|
||||||
|
level=config.LOG_LEVEL,
|
||||||
|
datefmt='%Y-%m-%d %H:%M:%S',
|
||||||
|
format='%(asctime)s %(levelname)s %(filename)s[%(lineno)d] %(message)s'
|
||||||
|
)
|
||||||
|
def main():
|
||||||
|
configer = {
|
||||||
|
'server': '%s' % config.SS_BIND_IP,
|
||||||
|
'local_port': 1081,
|
||||||
|
'port_password': {
|
||||||
|
},
|
||||||
|
'method': '%s' % config.SS_METHOD,
|
||||||
|
'manager_address': '%s:%s' % (config.MANAGE_BIND_IP, config.MANAGE_PORT),
|
||||||
|
'timeout': 60, # some protocol keepalive packet 3 min Eg bt
|
||||||
|
'fast_open': False,
|
||||||
|
'verbose': 1
|
||||||
|
}
|
||||||
|
start_shadowsock = thread.start_new_thread(manager.run, (configer,))
|
||||||
|
time.sleep(1)
|
||||||
|
sync_users = thread.start_new_thread(DbTransfer.thread_db, ())
|
||||||
|
time.sleep(1)
|
||||||
|
sysc_transfer = thread.start_new_thread(DbTransfer.thread_push, ())
|
||||||
|
while True:
|
||||||
|
time.sleep(3600)
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
38
shadowsocks/shadowsocks.sql
Normal file
38
shadowsocks/shadowsocks.sql
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
|
||||||
|
SET NAMES utf8;
|
||||||
|
SET FOREIGN_KEY_CHECKS = 0;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for `bandwidth_log`
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `bandwidth_log`;
|
||||||
|
CREATE TABLE `bandwidth_log` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`node` varchar(255) NOT NULL,
|
||||||
|
`port` int(11) NOT NULL,
|
||||||
|
`data` bigint(20) NOT NULL,
|
||||||
|
`time` int(11) NOT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for `user`
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `user`;
|
||||||
|
CREATE TABLE `user` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`u_email` varchar(32) NOT NULL COMMENT '邮件',
|
||||||
|
`u_pwd` varchar(32) NOT NULL COMMENT '密码',
|
||||||
|
`u_nickname` varchar(255) NOT NULL COMMENT '昵称',
|
||||||
|
`u_status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '用户状态',
|
||||||
|
`ss_port` int(11) NOT NULL COMMENT 'ss端口',
|
||||||
|
`ss_pwd` varchar(32) NOT NULL COMMENT 'ss密码',
|
||||||
|
`b_usage` bigint(20) NOT NULL COMMENT '使用流量',
|
||||||
|
`b_max` bigint(20) NOT NULL COMMENT '可使用最大流量',
|
||||||
|
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `pk_ss_port` (`ss_port`),
|
||||||
|
UNIQUE KEY `pk_u_email` (`u_email`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
|
||||||
|
|
||||||
|
SET FOREIGN_KEY_CHECKS = 1;
|
33
shadowsocks/templates/index.html
Normal file
33
shadowsocks/templates/index.html
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-cmn-Hans">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0">
|
||||||
|
<title>SS查询系统</title>
|
||||||
|
<link rel="stylesheet" href="https://res.wx.qq.com/open/libs/weui/0.4.3/weui.min.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function show_b(b) {
|
||||||
|
if(b/1024/1024/1024>1){
|
||||||
|
document.write((b/1024/1024/1024).toFixed(2)+"GB")
|
||||||
|
}else if(b/1024/1024>1){
|
||||||
|
document.write((b/1024/1024).toFixed(2)+"MB")
|
||||||
|
}else{
|
||||||
|
document.write((b/1024).toFixed(2)+"KB")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<div class="container" id="container">
|
||||||
|
<div class="hd">
|
||||||
|
<h1 class="page_title">Welcome {{ user.u_nickname }}</h1>
|
||||||
|
<h3> IP:107.182.191.61</h3>
|
||||||
|
<h3> 加密方式:rc4-md5</h3>
|
||||||
|
<h3> 端口:{{ user.ss_port }}</h3>
|
||||||
|
<h3> 密码:{{ user.ss_pwd }}</h3>
|
||||||
|
<h3> 已用流量:<script>show_b('{{ user.b_usage}}')</script></h3>
|
||||||
|
<h3> 总流量:<script>show_b('{{ user.b_max}}')</script></h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
58
shadowsocks/templates/login.html
Normal file
58
shadowsocks/templates/login.html
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-cmn-Hans">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0">
|
||||||
|
<title>SS查询系统</title>
|
||||||
|
<link rel="stylesheet" href="https://res.wx.qq.com/open/libs/weui/0.4.3/weui.min.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container" id="container">
|
||||||
|
<div class="cell">
|
||||||
|
<form id="loginfrom" action="/login" method="post">
|
||||||
|
<div class="hd">
|
||||||
|
<div style="height: 120px;"></div>
|
||||||
|
<div class="weui_cells_title">SS查询系统</div>
|
||||||
|
<div class="weui_cells weui_cells_form">
|
||||||
|
<div class="weui_cell">
|
||||||
|
<div class="weui_cell_hd"><label class="weui_label">邮件</label></div>
|
||||||
|
<div class="weui_cell_bd weui_cell_primary">
|
||||||
|
<input class="weui_input" name="username" type="text" placeholder="请输入邮件">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="weui_cell">
|
||||||
|
<div class="weui_cell_hd"><label class="weui_label">邮件</label></div>
|
||||||
|
<div class="weui_cell_bd weui_cell_primary">
|
||||||
|
<input class="weui_input" name="password" type="password" placeholder="请输入邮件">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="weui_btn_area">
|
||||||
|
<a class="weui_btn weui_btn_primary" onclick="javascript:formsubmit()">登录</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function formsubmit() {
|
||||||
|
document.getElementById("loginfrom").submit()
|
||||||
|
}
|
||||||
|
function close_error_dialog() {
|
||||||
|
document.getElementById("error_dialog").style.display="none"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% if errormsg %}
|
||||||
|
<div class="weui_dialog_alert" id="error_dialog">
|
||||||
|
<div class="weui_mask"></div>
|
||||||
|
<div class="weui_dialog">
|
||||||
|
<div class="weui_dialog_hd"><strong class="weui_dialog_title">错误信息</strong></div>
|
||||||
|
<div class="weui_dialog_bd">{{ errormsg }}</div>
|
||||||
|
<div class="weui_dialog_ft">
|
||||||
|
<a href='javascript:close_error_dialog();' class="weui_btn_dialog primary">确定</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue