1. 修正bug#145: 密码已经过期时,用户在登录界面登录后会跳转到修改密码界面,必须先修改密码后方可继续登录; 2. 远程连接时检查助手版本是否匹配; 3. 修正:登录界面刚显示出来就点击密码输入框,会在短时间后焦点调到用户名输入框。
|
@ -18,6 +18,7 @@ class Builder:
|
|||
self.VER_TP_TPCORE = ''
|
||||
self.VER_TP_TPWEB = ''
|
||||
self.VER_TP_ASSIST = ''
|
||||
self.VER_TP_ASSIST_REQUIRE = ''
|
||||
|
||||
def build(self):
|
||||
cc.n('update version...')
|
||||
|
@ -43,12 +44,17 @@ class Builder:
|
|||
x = l.split(' ')
|
||||
self.VER_TP_ASSIST = x[1].strip()
|
||||
# self.VER_TP_ASSIST += '.0'
|
||||
elif l.startswith('TP_ASSIST_REQUIRE '):
|
||||
x = l.split(' ')
|
||||
self.VER_TP_ASSIST_REQUIRE = x[1].strip()
|
||||
# self.VER_TP_ASSIST += '.0'
|
||||
|
||||
cc.v('new version:')
|
||||
cc.v(' Server : ', self.VER_TP_SERVER)
|
||||
cc.v(' - tp_core : ', self.VER_TP_TPCORE)
|
||||
cc.v(' - tp_web : ', self.VER_TP_TPWEB)
|
||||
cc.v(' Assist : ', self.VER_TP_ASSIST)
|
||||
cc.v(' - Require : ', self.VER_TP_ASSIST_REQUIRE)
|
||||
cc.v('')
|
||||
|
||||
self.make_builder_ver()
|
||||
|
@ -100,7 +106,12 @@ class Builder:
|
|||
def make_server_ver(self):
|
||||
ver_file = os.path.join(env.root_path, 'server', 'www', 'teleport', 'webroot', 'app', 'app_ver.py')
|
||||
# ver_content = '# -*- coding: utf8 -*-\n\nTS_VER = "{}"\n'.format(self.VER_TELEPORT_SERVER)
|
||||
ver_content = '# -*- coding: utf8 -*-\nTP_SERVER_VER = "{}"\n'.format(self.VER_TP_SERVER)
|
||||
# ver_content = '# -*- coding: utf8 -*-\nTP_SERVER_VER = "{}"\n'.format(self.VER_TP_SERVER)
|
||||
ver_content = '' \
|
||||
'# -*- coding: utf8 -*-\n' \
|
||||
'TP_SERVER_VER = "{}"\n' \
|
||||
'TP_ASSIST_REQUIRE_VER = "{}"\n' \
|
||||
''.format(self.VER_TP_SERVER, self.VER_TP_ASSIST_REQUIRE)
|
||||
|
||||
rewrite = False
|
||||
if not os.path.exists(ver_file):
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# -*- coding: utf8 -*-
|
||||
VER_TP_SERVER = "3.2.0"
|
||||
VER_TP_ASSIST = "3.2.0"
|
||||
# -*- coding: utf8 -*-
|
||||
VER_TP_SERVER = "3.2.1"
|
||||
VER_TP_ASSIST = "3.2.0"
|
||||
|
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 22 KiB |
|
@ -178,7 +178,7 @@ $app.on_table_groups_cell_created = function (tbl, row_id, col_key, cell_obj) {
|
|||
$app.dlg_edit_group.show_edit(_row_id);
|
||||
});
|
||||
cell_obj.find('[data-btn-remove]').click(function () {
|
||||
console.log(_row_id);
|
||||
// console.log(_row_id);
|
||||
$app.on_btn_remove_group_click(_row_id);
|
||||
});
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ $app.on_table_groups_render_created = function (render) {
|
|||
if (_.isUndefined(fields.members))
|
||||
return '';
|
||||
|
||||
console.log(fields.members);
|
||||
// console.log(fields.members);
|
||||
|
||||
var ret = [];
|
||||
for (var i = 0; i < fields.members.length; ++i) {
|
||||
|
@ -516,7 +516,7 @@ $app.create_dlg_edit_group = function () {
|
|||
};
|
||||
|
||||
dlg.on_save = function () {
|
||||
console.log('---save.');
|
||||
// console.log('---save.');
|
||||
dlg.hide_error();
|
||||
if (!dlg.check_input())
|
||||
return;
|
||||
|
|
|
@ -174,7 +174,7 @@ $app.on_table_groups_cell_created = function (tbl, row_id, col_key, cell_obj) {
|
|||
$app.dlg_edit_group.show_edit(_row_id);
|
||||
});
|
||||
cell_obj.find('[data-btn-remove]').click(function () {
|
||||
console.log(_row_id);
|
||||
// console.log(_row_id);
|
||||
$app.on_btn_remove_group_click(_row_id);
|
||||
});
|
||||
}
|
||||
|
@ -258,8 +258,6 @@ $app.on_table_groups_render_created = function (render) {
|
|||
if (_.isUndefined(fields.members))
|
||||
return '';
|
||||
|
||||
console.log('xxx', fields.members);
|
||||
|
||||
var ret = [];
|
||||
for (var i = 0; i < fields.members.length; ++i) {
|
||||
ret.push('<div class="acc-info-wrap"><div class="acc-info');
|
||||
|
@ -509,7 +507,7 @@ $app.create_dlg_edit_group = function () {
|
|||
};
|
||||
|
||||
dlg.on_save = function () {
|
||||
console.log('---save.');
|
||||
// console.log('---save.');
|
||||
dlg.hide_error();
|
||||
if (!dlg.check_input())
|
||||
return;
|
||||
|
|
|
@ -20,9 +20,8 @@ var SLOGAN = [
|
|||
'追求进步,<br/>不求完美。'
|
||||
];
|
||||
|
||||
|
||||
$app.on_init = function (cb_stack) {
|
||||
$app.login_type = TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA;
|
||||
$app.login_type = -1;
|
||||
$app.dom = {
|
||||
slogan: $('#msg-slogan'),
|
||||
auth_box: $('#auth-box-container'),
|
||||
|
@ -47,9 +46,11 @@ $app.on_init = function (cb_stack) {
|
|||
$app.last_img_idx = 0;
|
||||
$app.last_slogan_idx = 0;
|
||||
|
||||
// console.log($app.options);
|
||||
if ($app.options.username.length > 0) {
|
||||
$app.dom.input_username.val($app.options.username);
|
||||
$app.dom.input_password.focus();
|
||||
} else {
|
||||
$app.dom.input_username.focus();
|
||||
}
|
||||
|
||||
$app.dom.captcha_image.attr('src', '/auth/captcha?h=36&rnd=' + Math.random());
|
||||
|
@ -59,18 +60,10 @@ $app.on_init = function (cb_stack) {
|
|||
//$app.init_slogan();
|
||||
|
||||
$app.dom.btn_login_type_password.click(function () {
|
||||
$app.login_type = TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA;
|
||||
$app.dom.btn_login_type_oath.removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
$app.dom.area_oath.slideUp(100);
|
||||
$app.dom.area_captcha.slideDown(100);
|
||||
$app.switch_login_type(TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA, true);
|
||||
});
|
||||
$app.dom.btn_login_type_oath.click(function () {
|
||||
$app.login_type = TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH;
|
||||
$app.dom.btn_login_type_password.removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
$app.dom.area_oath.slideDown(100);
|
||||
$app.dom.area_captcha.slideUp(100);
|
||||
$app.switch_login_type(TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH, true);
|
||||
});
|
||||
|
||||
$app.dom.btn_login.click($app.login_account);
|
||||
|
@ -108,14 +101,43 @@ $app.on_init = function (cb_stack) {
|
|||
});
|
||||
|
||||
if ($app.options.default_auth & TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA) {
|
||||
$app.dom.btn_login_type_password.click();
|
||||
$app.switch_login_type(TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA, false);
|
||||
} else if ($app.options.default_auth & TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH) {
|
||||
$app.dom.btn_login_type_oath.click();
|
||||
$app.switch_login_type(TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH, false);
|
||||
}
|
||||
|
||||
cb_stack.exec();
|
||||
};
|
||||
|
||||
$app.switch_login_type = function(login_type, animate) {
|
||||
if($app.login_type === login_type)
|
||||
return;
|
||||
|
||||
if(login_type === TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA) {
|
||||
$app.login_type = login_type;
|
||||
$app.dom.btn_login_type_oath.removeClass('selected');
|
||||
$app.dom.btn_login_type_password.addClass('selected');
|
||||
if(animate) {
|
||||
$app.dom.area_oath.slideUp(100);
|
||||
$app.dom.area_captcha.slideDown(100);
|
||||
} else {
|
||||
$app.dom.area_oath.hide();
|
||||
$app.dom.area_captcha.show();
|
||||
}
|
||||
} else if(login_type === TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH) {
|
||||
$app.login_type = login_type;
|
||||
$app.dom.btn_login_type_password.removeClass('selected');
|
||||
$app.dom.btn_login_type_oath.addClass('selected');
|
||||
if(animate) {
|
||||
$app.dom.area_oath.slideDown(100);
|
||||
$app.dom.area_captcha.slideUp(100);
|
||||
} else {
|
||||
$app.dom.area_oath.show();
|
||||
$app.dom.area_captcha.hide();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$app.hide_op_box = function () {
|
||||
$app.dom.message.hide();
|
||||
};
|
||||
|
@ -245,8 +267,8 @@ $app.on_screen_resize = function () {
|
|||
$app.init_blur_bg = function () {
|
||||
$app.last_img_idx = Math.floor(Math.random() * (BLUR_BG_IMG.length));
|
||||
$('body').backgroundBlur({
|
||||
imageURL: '/static/img/login/' + BLUR_BG_IMG[$app.last_img_idx] + '?' + Math.random(),
|
||||
blurAmount: 15,
|
||||
imageURL: '/static/img/login/' + BLUR_BG_IMG[$app.last_img_idx], // + '?' + Math.random(),
|
||||
blurAmount: 8,
|
||||
duration: 1000,
|
||||
imageClass: 'bg-blur',
|
||||
overlayClass: 'bg-blur-overlay'
|
||||
|
@ -256,13 +278,7 @@ $app.init_blur_bg = function () {
|
|||
|
||||
setTimeout(function () {
|
||||
$app.init_slogan();
|
||||
}, 2000);
|
||||
|
||||
setTimeout(function () {
|
||||
$app.dom.auth_box.fadeIn(800, function () {
|
||||
$app.dom.input_username.focus();
|
||||
});
|
||||
}, 300);
|
||||
}, 1200);
|
||||
};
|
||||
|
||||
$app._update_blur_bg = function () {
|
||||
|
@ -273,14 +289,14 @@ $app._update_blur_bg = function () {
|
|||
break;
|
||||
}
|
||||
}
|
||||
$('body').backgroundBlur('/static/img/login/' + BLUR_BG_IMG[$app.last_img_idx] + '?' + Math.random());
|
||||
$('body').backgroundBlur('/static/img/login/' + BLUR_BG_IMG[$app.last_img_idx]);// + '?' + Math.random());
|
||||
};
|
||||
|
||||
$app.init_slogan = function () {
|
||||
$app.last_slogan_idx = Math.floor(Math.random() * SLOGAN.length);
|
||||
$app.dom.slogan.html(SLOGAN[$app.last_slogan_idx]).fadeIn(1000);
|
||||
|
||||
setInterval($app._update_slogan, 8100);
|
||||
setInterval($app._update_slogan, 12100);
|
||||
};
|
||||
|
||||
$app._update_slogan = function () {
|
||||
|
|
|
@ -8,7 +8,7 @@ $app.on_init = function (cb_stack) {
|
|||
// , group_selected: $('#group-selected')
|
||||
};
|
||||
|
||||
console.log($app.options);
|
||||
// console.log($app.options);
|
||||
if(!$app.options.core_cfg.detected) {
|
||||
$tp.notify_error('核心服务未启动,无法进行远程连接!');
|
||||
cb_stack.exec();
|
||||
|
|
|
@ -402,7 +402,7 @@ $app.get_selected_sessions = function (tbl) {
|
|||
|
||||
$app.on_btn_kill_sessions_click = function () {
|
||||
var sessions = $app.get_selected_sessions($app.table_session);
|
||||
console.log(sessions);
|
||||
// console.log(sessions);
|
||||
if (sessions.length === 0) {
|
||||
$tp.notify_error('请选择要强行终止的会话!');
|
||||
return;
|
||||
|
|
|
@ -3,11 +3,19 @@
|
|||
$tp.assist = {
|
||||
running: false,
|
||||
version: '',
|
||||
ver_require: '0.0.0',
|
||||
errcode: TPE_OK,
|
||||
api_url: '',
|
||||
teleport_ip: window.location.hostname
|
||||
teleport_ip: window.location.hostname,
|
||||
|
||||
dom: {
|
||||
msg_box_title: null,
|
||||
msg_box_info: null,
|
||||
msg_box_desc: null
|
||||
}
|
||||
};
|
||||
|
||||
console.log(window.location.protocol);
|
||||
// console.log(window.location.protocol);
|
||||
|
||||
// $assist 是 $tp.assist 的别名,方便使用。
|
||||
var $assist = $tp.assist;
|
||||
|
@ -59,22 +67,56 @@ $assist.init = function (cb_stack) {
|
|||
};
|
||||
|
||||
$assist.alert_assist_not_found = function () {
|
||||
console.log($assist.errcode);
|
||||
if($assist.errcode === TPE_NO_ASSIST) {
|
||||
$assist.dom.msg_box_title.html('未检测到TELEPORT助手');
|
||||
$assist.dom.msg_box_info.html('需要TELEPORT助手来辅助远程连接,请确认本机运行了TELEPORT助手!');
|
||||
$assist.dom.msg_box_desc.html('如果您尚未运行TELEPORT助手,请 <a href="http://tp4a.com/download" target="_blank"><strong>下载最新版TELEPORT助手安装包</strong></a> 并安装。一旦运行了TELEPORT助手,即可重新进行远程连接。');
|
||||
} else if($assist.errcode === TPE_OLD_ASSIST) {
|
||||
$assist.dom.msg_box_title.html('TELEPORT助手需要升级');
|
||||
$assist.dom.msg_box_info.html('检测到TELEPORT助手版本 v'+ $assist.version +',但需要最低版本 v'+ $assist.ver_require+'。');
|
||||
$assist.dom.msg_box_desc.html('请 <a href="http://tp4a.com/download" target="_blank"><strong>下载最新版TELEPORT助手安装包</strong></a> 并安装。一旦升级了TELEPORT助手,即可重新进行远程连接。');
|
||||
}
|
||||
|
||||
$('#dialog-need-assist').modal();
|
||||
};
|
||||
|
||||
// 1.2.0 > 1.1.0
|
||||
// 1.2 = 1.2.0
|
||||
// 2.1.1 > 1.2.9
|
||||
// 2.1.10 > 2.1.9
|
||||
$assist._version_compare = function () {
|
||||
var ver_current = $assist.version.split(".");
|
||||
var ver_require = $assist.ver_require.split(".");
|
||||
|
||||
var count = ver_current.length;
|
||||
if(ver_require.length > count)
|
||||
count = ver_require.length;
|
||||
|
||||
var c, r;
|
||||
for(var i = 0; i < count; ++i) {
|
||||
c = ver_current[i] || 0;
|
||||
r = ver_require[i] || 0;
|
||||
if(c < r)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
$assist._make_message_box = function () {
|
||||
var _html = [
|
||||
'<div class="modal fade" id="dialog-need-assist">',
|
||||
'<div class="modal-dialog" role="document">',
|
||||
'<div class="modal-content">',
|
||||
'<div class="modal-header">',
|
||||
'<h4 class="modal-title">未检测到TELEPORT助手!</h4>',
|
||||
'<h4 class="modal-title" id="assist-msg-box-tittle"></h4>',
|
||||
'</div>',
|
||||
'<div class="modal-body">',
|
||||
'<div class="alert alert-info" role="alert">',
|
||||
'<p>需要TELEPORT助手来辅助远程连接,请确认本机运行了TELEPORT助手!</p>',
|
||||
'<div class="alert alert-danger" role="alert">',
|
||||
'<p id="assist-msg-box-info"></p>',
|
||||
'</div>',
|
||||
'<p>如果您尚未运行TELEPORT助手,请 <a href="http://tp4a.com/download" target="_blank"><strong>下载最新版TELEPORT助手</strong></a> 并安装。一旦运行了TELEPORT助手,即可重新进行远程连接。</p>',
|
||||
'<p id="assist-msg-box-desc"></p>',
|
||||
'</div>',
|
||||
'<div class="modal-footer">',
|
||||
'<button type="button" class="btn btn-sm btn-default" data-dismiss="modal"><i class="fa fa-times fa-fw"></i> 我知道了</button>',
|
||||
|
@ -85,9 +127,23 @@ $assist._make_message_box = function () {
|
|||
'</div>'
|
||||
].join('\n');
|
||||
$('body').append($(_html));
|
||||
|
||||
$assist.dom.msg_box_title = $('#assist-msg-box-tittle');
|
||||
$assist.dom.msg_box_info = $('#assist-msg-box-info');
|
||||
$assist.dom.msg_box_desc = $('#assist-msg-box-desc');
|
||||
};
|
||||
|
||||
$assist.do_teleport = function (args, func_success, func_error) {
|
||||
if(!$assist.running) {
|
||||
$assist.errcode = TPE_NO_ASSIST;
|
||||
func_error(TPE_NO_ASSIST, '');
|
||||
return;
|
||||
} else if(!$assist._version_compare()) {
|
||||
$assist.errcode = TPE_OLD_ASSIST;
|
||||
func_error(TPE_NO_ASSIST, '');
|
||||
return;
|
||||
}
|
||||
|
||||
// 第一步:将参数传递给web服务,准备获取一个远程连接会话ID
|
||||
var args_ = JSON.stringify(args);
|
||||
$.ajax({
|
||||
|
@ -127,19 +183,17 @@ $assist.do_teleport = function (args, func_success, func_error) {
|
|||
|
||||
// console.log('---', data);
|
||||
var args_ = encodeURIComponent(JSON.stringify(data));
|
||||
//判断是否使用urlprocotol处理方式
|
||||
// 判断是否使用 url-protocol 处理方式
|
||||
if ($app.options.url_proto){
|
||||
|
||||
if(!$("#urlproto").length) {
|
||||
var _html = "<div id='urlproto' style='display:none;z-index=-1;'><iframe src=''/></div>";
|
||||
if(!$("#url-protocol").length) {
|
||||
var _html = '<div id="url-protocol" style="display:none;z-index=-1;"><iframe src=""/></div>';
|
||||
$('body').append($(_html));
|
||||
}
|
||||
$("#urlproto").find("iframe").attr("src",'teleport://' + JSON.stringify(data));
|
||||
$("#url-protocol").find("iframe").attr("src",'teleport://' + JSON.stringify(data));
|
||||
}else{
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
timeout: 5000,
|
||||
//url: 'http://localhost:50022/ts_op/' + args_,
|
||||
url: $assist.api_url + '/run/' + args_,
|
||||
jsonp: 'callback',
|
||||
dataType: 'json',
|
||||
|
|
|
@ -98,7 +98,7 @@ var TP_POLICY_AUTH_gUSER_gHOST = 8; // 8=用户组:主机组
|
|||
// =======================================================
|
||||
// 全局配置
|
||||
// =======================================================
|
||||
var TP_ASSIST_STARTUP_URLPROTO = 1; // 启用urlprotocol功能
|
||||
var TP_ASSIST_STARTUP_URLPROTO = 1; // 启用 url-protocol 功能
|
||||
|
||||
// =======================================================
|
||||
// 授权标记
|
||||
|
|
|
@ -104,135 +104,172 @@ $app.show_op_box = function (op_type, op_msg) {
|
|||
$app.dom.op_message.show();
|
||||
};
|
||||
|
||||
$app.on_send_find_password_email = function () {
|
||||
// $app.on_send_find_password_email = function () {
|
||||
// $app.hide_op_box();
|
||||
// var str_username = $app.dom.find.input_username.val();
|
||||
// var str_email = $app.dom.find.input_email.val();
|
||||
// var str_captcha = $app.dom.find.input_captcha.val();
|
||||
//
|
||||
// if (str_username.length === 0) {
|
||||
// $app.show_op_box('error', '用户名未填写!');
|
||||
// $app.dom.find.input_username.attr('data-content', "请填写您的用户名!").focus().popover('show');
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (str_email.length === 0) {
|
||||
// $app.show_op_box('error', '电子邮件地址未填写!');
|
||||
// $app.dom.find.input_email.attr('data-content', "请填写您的电子邮件地址!").focus().popover('show');
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (!tp_is_email(str_email)) {
|
||||
// $app.show_op_box('error', '无效的电子邮件地址!');
|
||||
// $app.dom.find.input_email.attr('data-content', "请检查输入的电子邮件地址!").focus().popover('show');
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (str_captcha.length !== 4) {
|
||||
// $app.show_op_box('error', '验证码错误!');
|
||||
// $app.dom.find.input_captcha.attr('data-content', "验证码为4位数字和字母的组合,请重新填写!").focus().select().popover('show');
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// $app.dom.find.btn_submit.attr('disabled', 'disabled');
|
||||
// $tp.ajax_post_json('/auth/verify-captcha', {captcha: str_captcha},
|
||||
// function (ret) {
|
||||
// if (ret.code === TPE_OK) {
|
||||
// // 验证成功
|
||||
// $app.hide_op_box();
|
||||
// $app.show_op_box('wait', '<i class="fa fa-circle-o-notch fa-spin"></i> 正在发送密码重置确认函,请稍候...');
|
||||
// $app.do_send_reset_email(str_username, str_email, str_captcha);
|
||||
// }
|
||||
// else {
|
||||
// $app.dom.find.btn_submit.removeAttr('disabled');
|
||||
// $app.hide_op_box();
|
||||
// $app.show_op_box('error', tp_error_msg(ret.code, ret.message));
|
||||
// $app.dom.captcha_image.attr('src', '/auth/captcha?h=28&rnd=' + Math.random());
|
||||
// $app.dom.input_captcha.focus().select().val('');
|
||||
// }
|
||||
// },
|
||||
// function () {
|
||||
// $app.hide_op_box();
|
||||
// $app.show_op_box('error', '很抱歉,无法连接服务器!请稍后再试一次!');
|
||||
// $app.dom.find.btn_submit.removeAttr('disabled');
|
||||
// }
|
||||
// );
|
||||
// };
|
||||
//
|
||||
// $app.do_send_reset_email = function (str_username, str_email, str_captcha) {
|
||||
// $tp.ajax_post_json('/user/do-reset-password', {
|
||||
// mode: 3,
|
||||
// username: str_username,
|
||||
// email: str_email,
|
||||
// captcha: str_captcha
|
||||
// },
|
||||
// function (ret) {
|
||||
// if (ret.code === TPE_OK) {
|
||||
// $app.dom.find.btn_submit.slideUp('fast');
|
||||
// $app.show_op_box('success', '密码重置确认函已发送,请注意查收!');
|
||||
// } else {
|
||||
// $app.dom.find.btn_submit.removeAttr('disabled');
|
||||
// $app.hide_op_box();
|
||||
// var msg = '';
|
||||
// if (ret.code === TPE_NOT_EXISTS)
|
||||
// msg = tp_error_msg(ret.code, '用户不存在,请检查输入的用户和电子邮件地址是否匹配!');
|
||||
// else
|
||||
// msg = tp_error_msg(ret.code, ret.message);
|
||||
// $app.show_op_box('error', msg);
|
||||
// }
|
||||
// },
|
||||
// function () {
|
||||
// $app.dom.find.btn_submit.removeAttr('disabled');
|
||||
// $app.hide_op_box();
|
||||
// $app.show_op_box('error', '网络故障,密码重置确认函发送失败!');
|
||||
// },
|
||||
// 15000
|
||||
// );
|
||||
// };
|
||||
|
||||
$app.on_change_password = function () {
|
||||
$app.hide_op_box();
|
||||
var str_username = $app.dom.find.input_username.val();
|
||||
var str_email = $app.dom.find.input_email.val();
|
||||
var str_captcha = $app.dom.find.input_captcha.val();
|
||||
var str_password = $app.dom.txt_password.val();
|
||||
var str_new_password = $app.dom.txt_new_password.val();
|
||||
var str_captcha = $app.dom.txt_captcha.val();
|
||||
|
||||
if (str_username.length === 0) {
|
||||
$app.show_op_box('error', '用户名未填写!');
|
||||
$app.dom.find.input_username.attr('data-content', "请填写您的用户名!").focus().popover('show');
|
||||
if (str_password.length === 0) {
|
||||
$app.show_op_box('error', '密码未填写!');
|
||||
$app.dom.txt_password.attr('data-content', "请输入您的当前密码!").focus().popover('show');
|
||||
return;
|
||||
}
|
||||
|
||||
if (str_email.length === 0) {
|
||||
$app.show_op_box('error', '电子邮件地址未填写!');
|
||||
$app.dom.find.input_email.attr('data-content', "请填写您的电子邮件地址!").focus().popover('show');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tp_is_email(str_email)) {
|
||||
$app.show_op_box('error', '无效的电子邮件地址!');
|
||||
$app.dom.find.input_email.attr('data-content', "请检查输入的电子邮件地址!").focus().popover('show');
|
||||
if (str_new_password.length === 0) {
|
||||
$app.show_op_box('error', '请设置新的密码!');
|
||||
$app.dom.txt_new_password.attr('data-content', "请设置您的新密码!").focus().popover('show');
|
||||
return;
|
||||
}
|
||||
|
||||
if (str_captcha.length !== 4) {
|
||||
$app.show_op_box('error', '验证码错误!');
|
||||
$app.dom.find.input_captcha.attr('data-content', "验证码为4位数字和字母的组合,请重新填写!").focus().select().popover('show');
|
||||
$app.dom.txt_captcha.attr('data-content', "验证码为4位数字和字母的组合,请重新填写!").focus().select().popover('show');
|
||||
return;
|
||||
}
|
||||
|
||||
$app.dom.find.btn_submit.attr('disabled', 'disabled');
|
||||
if ($app.options.force_strong) {
|
||||
if (!tp_check_strong_password(str_new_password)) {
|
||||
$app.show_op_box('error', tp_error_msg(TPE_FAILED, '抱歉,不能使用弱密码!'));
|
||||
$app.dom.txt_new_password.attr('data-content', "请设置强密码:至少8位,必须包含大写字母、小写字母以及数字!").focus().popover('show');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$app.dom.btn_submit.attr('disabled', 'disabled');
|
||||
$tp.ajax_post_json('/auth/verify-captcha', {captcha: str_captcha},
|
||||
function (ret) {
|
||||
if (ret.code === TPE_OK) {
|
||||
// 验证成功
|
||||
$app.hide_op_box();
|
||||
$app.show_op_box('wait', '<i class="fa fa-circle-o-notch fa-spin"></i> 正在发送密码重置确认函,请稍候...');
|
||||
$app.do_send_reset_email(str_username, str_email, str_captcha);
|
||||
$app.show_op_box('wait', '<i class="fa fa-circle-o-notch fa-spin"></i> 正在修改密码,请稍候...');
|
||||
$app.do_change_password(str_password, str_new_password, str_captcha);
|
||||
}
|
||||
else {
|
||||
$app.dom.find.btn_submit.removeAttr('disabled');
|
||||
$app.dom.btn_submit.removeAttr('disabled');
|
||||
$app.hide_op_box();
|
||||
$app.show_op_box('error', tp_error_msg(ret.code, ret.message));
|
||||
$app.dom.captcha_image.attr('src', '/auth/captcha?h=28&rnd=' + Math.random());
|
||||
$app.dom.input_captcha.focus().select().val('');
|
||||
$app.dom.img_captcha.attr('src', '/auth/captcha?h=28&rnd=' + Math.random());
|
||||
$app.dom.txt_captcha.focus().select().val('');
|
||||
}
|
||||
},
|
||||
function () {
|
||||
$app.hide_op_box();
|
||||
$app.show_op_box('error', '很抱歉,无法连接服务器!请稍后再试一次!');
|
||||
$app.dom.find.btn_submit.removeAttr('disabled');
|
||||
$app.dom.btn_submit.removeAttr('disabled');
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
$app.do_send_reset_email = function (str_username, str_email, str_captcha) {
|
||||
$app.do_change_password = function (str_password, str_new_password, str_captcha) {
|
||||
// var str_username = $app.options.username;
|
||||
$tp.ajax_post_json('/user/do-reset-password', {
|
||||
mode: 3,
|
||||
username: str_username,
|
||||
email: str_email,
|
||||
mode: 6,
|
||||
username: $app.options.username,
|
||||
password: str_password,
|
||||
new_password: str_new_password,
|
||||
captcha: str_captcha
|
||||
},
|
||||
function (ret) {
|
||||
$app.dom.btn_submit.removeAttr('disabled');
|
||||
if (ret.code === TPE_OK) {
|
||||
$app.dom.find.btn_submit.slideUp('fast');
|
||||
$app.show_op_box('success', '密码重置确认函已发送,请注意查收!');
|
||||
} else {
|
||||
$app.dom.find.btn_submit.removeAttr('disabled');
|
||||
$app.hide_op_box();
|
||||
var msg = '';
|
||||
if (ret.code === TPE_NOT_EXISTS)
|
||||
msg = tp_error_msg(ret.code, '用户不存在,请检查输入的用户和电子邮件地址是否匹配!');
|
||||
else
|
||||
msg = tp_error_msg(ret.code, ret.message);
|
||||
$app.show_op_box('error', msg);
|
||||
}
|
||||
},
|
||||
function () {
|
||||
$app.dom.find.btn_submit.removeAttr('disabled');
|
||||
$app.hide_op_box();
|
||||
$app.show_op_box('error', '网络故障,密码重置确认函发送失败!');
|
||||
},
|
||||
15000
|
||||
);
|
||||
};
|
||||
|
||||
$app.on_set_new_password = function () {
|
||||
$app.hide_op_box();
|
||||
var str_password = $app.dom.set_password.input_password.val();
|
||||
|
||||
if (str_password.length === 0) {
|
||||
$app.show_op_box('error', '密码未填写!');
|
||||
$app.dom.set_password.input_password.attr('data-content', "请设置您的新密码!").focus().popover('show');
|
||||
return;
|
||||
}
|
||||
|
||||
if ($app.options.force_strong) {
|
||||
if (!tp_check_strong_password(str_password)) {
|
||||
$app.show_op_box('error', tp_error_msg(TPE_FAILED, '抱歉,不能使用弱密码!'));
|
||||
$app.dom.set_password.input_password.attr('data-content', "请设置强密码:至少8位,必须包含大写字母、小写字母以及数字!").focus().popover('show');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$tp.ajax_post_json('/user/do-reset-password', {
|
||||
mode: 4,
|
||||
token: $app.options.token,
|
||||
password: str_password
|
||||
},
|
||||
function (ret) {
|
||||
$app.dom.find.btn_submit.removeAttr('disabled');
|
||||
if (ret.code === TPE_OK) {
|
||||
$app.show_op_box('success', '密码已重置,正在转到登录界面!');
|
||||
$app.show_op_box('success', '密码已修改,正在转到登录界面!');
|
||||
setTimeout(function () {
|
||||
window.location.href = '/';
|
||||
}, 2000);
|
||||
} else {
|
||||
var msg = '';
|
||||
if (ret.code === TPE_NOT_EXISTS)
|
||||
msg = tp_error_msg(ret.code, '无效的密码重置链接!');
|
||||
else
|
||||
msg = tp_error_msg(ret.code, ret.message);
|
||||
$app.show_op_box('error', msg);
|
||||
$app.show_op_box('error', tp_error_msg(ret.code, ret.message));
|
||||
}
|
||||
},
|
||||
function () {
|
||||
$app.dom.find.btn_submit.removeAttr('disabled');
|
||||
$app.hide_op_box();
|
||||
$app.show_op_box('error', '网络故障,密码重置失败!');
|
||||
$app.show_op_box('error', '网络故障,密码修改失败!');
|
||||
}
|
||||
);
|
||||
};
|
||||
|
|
|
@ -176,7 +176,7 @@ $app.on_table_groups_cell_created = function (tbl, row_id, col_key, cell_obj) {
|
|||
$app.dlg_edit_group.show_edit(_row_id);
|
||||
});
|
||||
cell_obj.find('[data-btn-remove]').click(function () {
|
||||
console.log(_row_id);
|
||||
// console.log(_row_id);
|
||||
$app.on_btn_remove_group_click(_row_id);
|
||||
});
|
||||
}
|
||||
|
@ -274,7 +274,7 @@ $app.on_table_groups_render_created = function (render) {
|
|||
if (_.isUndefined(fields.members))
|
||||
return '';
|
||||
|
||||
console.log(fields.members);
|
||||
// console.log(fields.members);
|
||||
|
||||
var ret = [];
|
||||
for (var i = 0; i < fields.members.length; ++i) {
|
||||
|
@ -538,7 +538,7 @@ $app.create_dlg_edit_group = function () {
|
|||
};
|
||||
|
||||
dlg.on_save = function () {
|
||||
console.log('---save.');
|
||||
// console.log('---save.');
|
||||
dlg.hide_error();
|
||||
if (!dlg.check_input())
|
||||
return;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
$app.on_init = function (cb_stack) {
|
||||
|
||||
console.log($app.options);
|
||||
// console.log($app.options);
|
||||
|
||||
$app.dom = {
|
||||
btn_refresh_user_list: $('#btn-refresh-user-list'),
|
||||
|
@ -233,7 +233,7 @@ $app.on_table_users_cell_created = function (tbl, row_id, col_key, cell_obj) {
|
|||
if (action === 'edit') {
|
||||
$app.dlg_edit_user.show_edit(row_id);
|
||||
} else if (action === 'reset-password') {
|
||||
console.log(user);
|
||||
// console.log(user);
|
||||
if(user.type === TP_USER_TYPE_LDAP)
|
||||
return;
|
||||
$app.dlg_reset_password.show_edit(row_id);
|
||||
|
@ -464,8 +464,8 @@ $app.on_btn_select_file_click = function () {
|
|||
$app.dom.upload_file_message.hide();
|
||||
// var dom_file_name = $('#upload-file-name');
|
||||
|
||||
console.log(btn_file_selector[0]);
|
||||
console.log(btn_file_selector[0].files);
|
||||
// console.log(btn_file_selector[0]);
|
||||
// console.log(btn_file_selector[0].files);
|
||||
|
||||
var file = null;
|
||||
if (btn_file_selector[0].files && btn_file_selector[0].files[0]) {
|
||||
|
@ -474,7 +474,7 @@ $app.on_btn_select_file_click = function () {
|
|||
file = btn_file_selector[0].files.item(0);
|
||||
}
|
||||
|
||||
console.log(file);
|
||||
// console.log(file);
|
||||
|
||||
if (file === null) {
|
||||
$app.dom.upload_file_info.html('请点击图标,选择要上传的文件!');
|
||||
|
@ -527,7 +527,7 @@ $app.on_btn_do_upload_click = function () {
|
|||
|
||||
var ret = JSON.parse(data);
|
||||
|
||||
console.log('import ret', ret);
|
||||
// console.log('import ret', ret);
|
||||
|
||||
if (ret.code === TPE_OK) {
|
||||
$app.dom.upload_file_message
|
||||
|
@ -931,7 +931,7 @@ $app.create_dlg_edit_user = function () {
|
|||
|
||||
dlg.show_edit = function (row_id) {
|
||||
var user = $app.table_users.get_row(row_id);
|
||||
console.log(user);
|
||||
// console.log(user);
|
||||
dlg.init_fields(user);
|
||||
dlg.dom.dialog.modal({backdrop: 'static'});
|
||||
};
|
||||
|
@ -1406,7 +1406,7 @@ $app.create_dlg_ldap_config = function () {
|
|||
dlg.dom.btn_list_attr.removeAttr('disabled');
|
||||
if (ret.code === TPE_OK) {
|
||||
$tp.notify_success('列举LDAP用户属性成功!');
|
||||
console.log(ret.data);
|
||||
// console.log(ret.data);
|
||||
$app.dlg_ldap_list_attr_result.show(ret.data.attributes);
|
||||
} else {
|
||||
$tp.notify_error('列举LDAP用户属性失败:' + tp_error_msg(ret.code, ret.message));
|
||||
|
@ -1435,7 +1435,7 @@ $app.create_dlg_ldap_config = function () {
|
|||
function (ret) {
|
||||
dlg.dom.btn_test.removeAttr('disabled');
|
||||
if (ret.code === TPE_OK) {
|
||||
console.log(ret.data);
|
||||
// console.log(ret.data);
|
||||
$tp.notify_success('LDAP连接测试成功!');
|
||||
$app.dlg_ldap_test_result.show(ret.data);
|
||||
} else {
|
||||
|
@ -1547,7 +1547,7 @@ $app.create_dlg_ldap_test_result = function () {
|
|||
var dn;
|
||||
for (dn in data) {
|
||||
h.push('<tr>');
|
||||
console.log(data[dn]);
|
||||
// console.log(data[dn]);
|
||||
_mktd(h, data[dn]['username']);
|
||||
_mktd(h, data[dn]['surname']);
|
||||
_mktd(h, data[dn]['email']);
|
||||
|
@ -1727,7 +1727,7 @@ $app.create_dlg_ldap_import = function () {
|
|||
function (ret) {
|
||||
dlg.dom.btn_refresh.removeAttr('disabled');
|
||||
if (ret.code === TPE_OK) {
|
||||
console.log(ret.data);
|
||||
// console.log(ret.data);
|
||||
|
||||
var _d = [];
|
||||
for (var i = 0; i < ret.data.length; ++i) {
|
||||
|
@ -1755,7 +1755,7 @@ $app.create_dlg_ldap_import = function () {
|
|||
return;
|
||||
}
|
||||
|
||||
console.log(items);
|
||||
// console.log(items);
|
||||
|
||||
dlg.dom.btn_import.attr('disabled', 'disabled');
|
||||
$tp.ajax_post_json('/system/do-ldap-import', {ldap_users: items},
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<div id="msg-slogan" style="display: none;"></div>
|
||||
</div>
|
||||
|
||||
<div id="auth-box-container" style="display: none;" class="col-md-6">
|
||||
<div id="auth-box-container" style="display: anone;" class="col-md-6">
|
||||
<div id="auth-box" class="auth-box auth-box-lg">
|
||||
<div class="header">
|
||||
<a id="login-type-password" class="title selected" href="javascript:;">账号/密码登录</a>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<%!
|
||||
import time
|
||||
import app.app_ver as app_ver
|
||||
page_icon_class_ = ''
|
||||
page_title_ = []
|
||||
page_id_ = []
|
||||
|
@ -96,10 +97,10 @@
|
|||
|
||||
<script type="text/javascript">
|
||||
$app.active_menu(${self.attr.page_id_});
|
||||
$tp.assist.ver_require = "${app_ver.TP_ASSIST_REQUIRE_VER}";
|
||||
</script>
|
||||
|
||||
<%block name="embed_js" />
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -54,10 +54,3 @@
|
|||
<!-- end of box -->
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<%block name="embed_js">
|
||||
<script type="text/javascript">
|
||||
## ywl.add_page_options(${page_param});
|
||||
</script>
|
||||
</%block>
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
<p class="input-addon-desc">验证码,点击图片可更换</p>
|
||||
|
||||
<div style="margin:20px 0;">
|
||||
<button type="button" class="btn btn-primary" data-field="btn-submit" style="width:100%;"><i class="fa fa-check fa-fw"></i> 确定修改</button>
|
||||
<button type="button" class="btn btn-primary" id="btn-submit" style="width:100%;"><i class="fa fa-check fa-fw"></i> 确定修改</button>
|
||||
<div id="message" style="display: none;"></div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
# -*- coding: utf8 -*-
|
||||
TP_SERVER_VER = "3.2.0"
|
||||
# -*- coding: utf8 -*-
|
||||
TP_SERVER_VER = "3.2.1"
|
||||
TP_ASSIST_REQUIRE_VER = "3.1.0"
|
||||
|
|
|
@ -259,7 +259,7 @@ class DoSaveCfgHandler(TPBaseJsonHandler):
|
|||
else:
|
||||
return self.write_json(err)
|
||||
|
||||
#增加urlprotocol的配置
|
||||
# 增加 url-protocol 的配置
|
||||
if 'global' in args:
|
||||
processed = True
|
||||
_cfg = args['global']
|
||||
|
|
|
@ -748,6 +748,42 @@ class DoResetPasswordHandler(TPBaseJsonHandler):
|
|||
return self.write_json(TPE_USER_AUTH)
|
||||
user_id = user_info['id']
|
||||
|
||||
elif mode == 6:
|
||||
# 用户密码过期,在登录前进行修改
|
||||
try:
|
||||
username = args['username']
|
||||
current_password = args['password']
|
||||
password = args['new_password']
|
||||
captcha = args['captcha']
|
||||
except:
|
||||
return self.write_json(TPE_PARAM)
|
||||
|
||||
code = self.get_session('captcha')
|
||||
if code is None:
|
||||
return self.write_json(TPE_CAPTCHA_EXPIRED, '验证码已失效')
|
||||
if code.lower() != captcha.lower():
|
||||
return self.write_json(TPE_CAPTCHA_MISMATCH, '验证码错误')
|
||||
|
||||
self.del_session('captcha')
|
||||
|
||||
err, user_info = user.get_by_username(username)
|
||||
if err != TPE_OK:
|
||||
return self.write_json(err)
|
||||
|
||||
# xxx 如果是密码过期而在登录前修改密码,需要额外判断用户是否已经被锁定
|
||||
# 如果用户被禁用或锁定,在登录时会被拒绝,因此此处仍然允许其修改密码
|
||||
# if user_info['state'] != TP_STATE_NORMAL:
|
||||
# if user_info['state'] == TP_STATE_LOCKED:
|
||||
# return self.write_json(TPE_USER_LOCKED)
|
||||
# elif user_info['state'] == TP_STATE_DISABLED:
|
||||
# return self.write_json(TPE_USER_DISABLED)
|
||||
# else:
|
||||
# return self.write_json(TPE_FAILED)
|
||||
|
||||
if not tp_password_verify(current_password, user_info['password']):
|
||||
return self.write_json(TPE_USER_AUTH)
|
||||
user_id = user_info['id']
|
||||
|
||||
else:
|
||||
return self.write_json(TPE_PARAM)
|
||||
|
||||
|
@ -774,7 +810,7 @@ class DoResetPasswordHandler(TPBaseJsonHandler):
|
|||
|
||||
return self.write_json(err, msg)
|
||||
|
||||
elif mode == 2 or mode == 4 or mode == 5:
|
||||
elif mode == 2 or mode == 4 or mode == 5 or mode == 6:
|
||||
if len(password) == 0:
|
||||
return self.write_json(TPE_PARAM)
|
||||
|
||||
|
@ -784,14 +820,14 @@ class DoResetPasswordHandler(TPBaseJsonHandler):
|
|||
return self.write_json(TPE_FAILED, '密码强度太弱!强密码需要至少8个英文字符,必须包含大写字母、小写字母和数字。')
|
||||
|
||||
password = tp_password_generate_secret(password)
|
||||
err = user.set_password(self, user_id, password)
|
||||
err = user.set_password(self, mode, user_id, password)
|
||||
|
||||
if mode == 4 and err == TPE_OK:
|
||||
user.remove_reset_token(token)
|
||||
|
||||
# 非用户自行修改密码的情况,都默认重置身份认证
|
||||
if mode != 5 and err == TPE_OK:
|
||||
print("reset oath secret")
|
||||
if not (mode == 5 or mode == 6) and err == TPE_OK:
|
||||
# print("reset oath secret")
|
||||
user.update_oath_secret(self, user_id, '')
|
||||
|
||||
self.write_json(err)
|
||||
|
|
|
@ -457,7 +457,7 @@ def set_role_for_users(handler, users, role_id):
|
|||
return TPE_OK
|
||||
|
||||
|
||||
def set_password(handler, user_id, password):
|
||||
def set_password(handler, mode, user_id, password):
|
||||
db = get_db()
|
||||
|
||||
operator = handler.get_current_user()
|
||||
|
@ -476,15 +476,19 @@ def set_password(handler, user_id, password):
|
|||
if len(surname) == 0:
|
||||
surname = name
|
||||
|
||||
sql = 'UPDATE `{}user` SET password="{password}" WHERE id={user_id};' \
|
||||
''.format(db.table_prefix, password=password, user_id=user_id)
|
||||
_time_now = tp_timestamp_utc_now()
|
||||
|
||||
sql = 'UPDATE `{}user` SET `password`="{password}", `last_chpass`={last_chpass} WHERE `id`={user_id};' \
|
||||
''.format(db.table_prefix, password=password, last_chpass=_time_now, user_id=user_id)
|
||||
db_ret = db.exec(sql)
|
||||
if not db_ret:
|
||||
return TPE_DATABASE
|
||||
|
||||
if operator['id'] == 0:
|
||||
syslog.sys_log({'username': name, 'surname': surname}, handler.request.remote_ip, TPE_OK,
|
||||
"用户 {} 通过邮件方式重置了密码".format(name))
|
||||
if mode in [3, 4, 5, 6]:
|
||||
if mode == 6:
|
||||
syslog.sys_log({'username': name, 'surname': surname}, handler.request.remote_ip, TPE_OK, "用户 {} 修改了过期的密码".format(name))
|
||||
else:
|
||||
syslog.sys_log({'username': name, 'surname': surname}, handler.request.remote_ip, TPE_OK, "用户 {} 通过邮件方式重置了密码".format(name))
|
||||
else:
|
||||
syslog.sys_log(operator, handler.request.remote_ip, TPE_OK, "为用户 {} 手动重置了密码".format(name))
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ Minor: 次版本号。如果两个程序集的名称和主版本号相同,而
|
|||
Revision: 修订号。主版本号和次版本号都相同但修订号不同的程序集应是完全可互换的。
|
||||
这适用于修复以前发布的程序集中的错误或安全漏洞。
|
||||
|
||||
TP_SERVER 3.2.0 # 整个服务端打包的版本
|
||||
TP_SERVER 3.2.1 # 整个服务端打包的版本
|
||||
TP_TPCORE 3.2.0 # 核心服务 tp_core 的版本
|
||||
TP_TPWEB 3.1.0 # web服务 tp_web 的版本(一般除非升级Python,否则不会变化)
|
||||
TP_ASSIST 3.2.0 # 助手版本
|
||||
|
||||
TP_ASSIST_REQUIRE 3.1.0 # 适配的助手最低版本
|
||||
|
|