作者 Karson

新增定时任务预期执行

新增CSS中fixed-footer类
新增Install时的权限检测
新增loadlang加载语言包方法
修复上传超出大小限制时的提示文字
修复后台部分语言文字
修复定时任务类型为SQL时的BUG
移除自动生成JS中主键的state字段

... ... @@ -553,7 +553,7 @@ class Crud extends Command
if ($v['COLUMN_KEY'] == 'PRI' && !$priDefined)
{
$priDefined = TRUE;
$javascriptList[] = "{field: 'state', checkbox: true}";
$javascriptList[] = "{checkbox: true}";
}
//构造JS列信息
$javascriptList[] = $this->getJsColumn($field, $v['DATA_TYPE']);
... ... @@ -708,7 +708,6 @@ class Crud extends Command
return;
$fieldList = $this->getFieldListName($field);
$methodName = 'get' . ucfirst($fieldList);
unset($v);
foreach ($itemArr as $k => &$v)
{
$v = "__('" . ucfirst($v) . "')";
... ...
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
{%addList%}
<div class="form-group hide layer-footer">
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed">{:__('OK')}</button>
... ...
<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
{%editList%}
<div class="form-group hide layer-footer">
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed">{:__('OK')}</button>
... ...
... ... @@ -279,27 +279,7 @@ CREATE TABLE `fa_crontab` (
-- Records of `fa_crontab`
-- ----------------------------
BEGIN;
INSERT INTO `fa_crontab` VALUES ('1', 'url', '请求URL', 'http://www.fastadmin.net', '* * * * 0-2', '0', '0', '0', '1497070825', '1497070825', '1483200000', '1546272000', '0', '0', 'normal'), ('2', 'url', '执行SQL', 'SELECT 1;', '* * * * 0-2', '0', '0', '0', '1497071095', '1497071095', '1483200000', '1546272000', '0', '0', 'normal');
COMMIT;
-- ----------------------------
-- Table structure for `fa_func`
-- ----------------------------
DROP TABLE IF EXISTS `fa_func`;
CREATE TABLE `fa_func` (
`f_id` int(10) NOT NULL AUTO_INCREMENT,
`f_title` varchar(50) NOT NULL COMMENT '标题',
`createtime` int(10) NOT NULL DEFAULT '0',
`updatetime` int(10) NOT NULL DEFAULT '0',
`status` varchar(30) NOT NULL DEFAULT '',
PRIMARY KEY (`f_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='函数表';
-- ----------------------------
-- Records of `fa_func`
-- ----------------------------
BEGIN;
INSERT INTO `fa_func` VALUES ('1', 'test', '1495811783', '1495811783', 'hidden'), ('2', 'test2fff', '1495811787', '1495813304', 'hidden'), ('3', 'fds', '1495813308', '1495813308', 'normal');
INSERT INTO `fa_crontab` VALUES ('1', 'url', '请求FastAdmin', 'http://www.fastadmin.net', '* * * * *', '0', '0', '0', '1497070825', '1497070825', '1483200000', '1546272000', '0', '0', 'normal'), ('2', 'sql', '查询一条SQL', 'SELECT 1;', '* * * * *', '0', '0', '0', '1497071095', '1497071095', '1483200000', '1546272000', '0', '0', 'normal');
COMMIT;
-- ----------------------------
... ...
... ... @@ -139,10 +139,9 @@ class Ajax extends Backend
public function lang()
{
header('Content-Type: application/javascript');
$modulename = $this->request->module();
$callback = $this->request->get('callback');
$controllername = input("controllername");
Lang::load(APP_PATH . $modulename . '/lang/' . Lang::detect() . '/' . str_replace('.', '/', $controllername) . '.php');
$this->loadlang($controllername);
//强制输出JSON Object
$result = 'define(' . json_encode(Lang::get(), JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE) . ');';
return $result;
... ... @@ -153,6 +152,7 @@ class Ajax extends Backend
*/
public function roletree()
{
$this->loadlang('auth/group');
$model = model('AuthGroup');
$id = $this->request->post("id");
$pid = $this->request->post("pid");
... ... @@ -206,6 +206,11 @@ class Ajax extends Backend
{
$this->code = -1;
$file = $this->request->file('file');
if (!$file)
{
$this->msg = "未上传文件或超出服务器上传限制";
return;
}
//判断是否已经存在附件
$sha1 = $file->hash();
... ...
... ... @@ -3,6 +3,7 @@
namespace app\admin\controller\general;
use app\common\controller\Backend;
use Cron\CronExpression;
/**
* 定时任务
... ... @@ -14,16 +15,13 @@ class Crontab extends Backend
{
protected $model = null;
protected $noNeedRight = ['check_schedule', 'get_schedule_future'];
public function _initialize()
{
parent::_initialize();
$this->model = model('Crontab');
$this->view->assign('typedata', [
'url' => __('Request Url'),
'sql' => __('Execute Sql Script'),
'shell' => __('Execute Shell'),
]);
$this->view->assign('typedata', \app\common\model\Crontab::getTypeList());
}
/**
... ... @@ -44,6 +42,11 @@ class Crontab extends Backend
->order($sort, $order)
->limit($offset, $limit)
->select();
foreach ($list as $k => &$v)
{
$cron = CronExpression::factory($v['schedule']);
$v['nexttime'] = $cron->getNextRunDate()->getTimestamp();
}
$result = array("total" => $total, "rows" => $list);
return json($result);
... ... @@ -51,4 +54,47 @@ class Crontab extends Backend
return $this->view->fetch();
}
/**
* 判断Crontab格式是否正确
* @internal
*/
public function check_schedule()
{
$row = $this->request->post("row/a");
$schedule = isset($row['schedule']) ? $row['schedule'] : '';
if (CronExpression::isValidExpression($schedule))
{
return json(['ok' => '']);
}
else
{
return json(['error' => __('Crontab format invalid')]);
}
}
/**
* 根据Crontab表达式读取未来七次的时间
* @internal
*/
public function get_schedule_future()
{
$time = [];
$schedule = $this->request->post('schedule');
$days = (int) $this->request->post('days');
try
{
$cron = CronExpression::factory($schedule);
for ($i = 0; $i < $days; $i++)
{
$time[] = $cron->getNextRunDate(null, $i)->format('Y-m-d H:i:s');
}
}
catch (\Exception $e)
{
}
return json(['futuretime' => $time]);
}
}
... ...
... ... @@ -3,5 +3,7 @@
return [
'The parent group can not be its own child' => '父组别不能是自身的子组别',
'The parent group can not found' => '父组别未找到',
'Group not found' => '组别未找到',
'Can not change the parent to child' => '父组别不能是它的子组别',
'You can not delete group that contain child group and administrators' => '你不能删除含有子组和管理员的组',
];
... ...
<?php
return [
'Title' => '任务标题',
'Maximums' => '最多执行',
'Sleep' => '延迟秒数',
'Schedule' => '执行周期',
'Executes' => '执行次数',
'Execute time' => '执行时间',
'Request Url' => '请求URL',
'Execute Sql Script' => '执行SQL',
'Execute Shell' => '执行Shell',
'Title' => '任务标题',
'Maximums' => '最多执行',
'Sleep' => '延迟秒数',
'Schedule' => '执行周期',
'Executes' => '执行次数',
'Execute time' => '最后执行时间',
'Request Url' => '请求URL',
'Execute Sql Script' => '执行SQL',
'Execute Shell' => '执行Shell',
'Crontab format invalid' => 'Crontab格式错误',
'Next execute time' => '下次预计时间',
'The next %s times the execution time' => '接下来 %s 次的执行时间',
];
... ...
... ... @@ -7,13 +7,6 @@
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{:build_toolbar()}
<div class="dropdown btn-group">
<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>
<ul class="dropdown-menu text-left" role="menu">
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=normal"><i class="fa fa-eye"></i> {:__('Set to normal')}</a></li>
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=hidden"><i class="fa fa-eye-slash"></i> {:__('Set to hidden')}</a></li>
</ul>
</div>
</div>
<table id="table" class="table table-striped table-bordered table-hover" width="100%">
</table>
... ...
... ... @@ -25,14 +25,19 @@
<div class="form-group">
<label for="schedule" class="control-label col-xs-12 col-sm-2">{:__('Schedule')}:</label>
<div class="col-xs-12 col-sm-8">
<div id="schedulepicker"></div>
<input type="text" class="form-control hide" id="schedule" name="row[schedule]" value="" data-rule="required" />
</div>
</div>
<div class="form-group">
<label for="sleep" class="control-label col-xs-12 col-sm-2">{:__('sleep')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="number" class="form-control" id="sleep" name="row[sleep]" value="0" data-rule="required" size="6" />
<input type="text" class="form-control" id="schedule" style="font-size:12px;font-family: Verdana;word-spacing:23px;" name="row[schedule]" value="* * * * *" data-rule="required; remote(general/crontab/check_schedule)" />
<div id="schedulepicker">
<pre><code>* * * * *
- - - - -
| | | | +--- day of week (0 - 7) (Sunday=0 or 7)
| | | +-------- month (1 - 12)
| | +------------- day of month (1 - 31)
| +------------------ hour (0 - 23)
+----------------------- min (0 - 59)</code></pre>
<h5>{:__('The next %s times the execution time', '<input type="number" id="pickdays" class="form-control text-center" value="7" style="display: inline-block;width:80px;">')}</h5>
<ol id="scheduleresult" class="list-group">
</ol>
</div>
</div>
</div>
<div class="form-group">
... ...
... ... @@ -25,14 +25,19 @@
<div class="form-group">
<label for="schedule" class="control-label col-xs-12 col-sm-2">{:__('Schedule')}:</label>
<div class="col-xs-12 col-sm-8">
<div id="schedulepicker"></div>
<input type="text" class="form-control hide" id="schedule" name="row[schedule]" value="{$row.schedule}" data-rule="required" />
</div>
</div>
<div class="form-group">
<label for="sleep" class="control-label col-xs-12 col-sm-2">{:__('sleep')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="number" class="form-control" id="sleep" name="row[sleep]" value="{$row.sleep}" data-rule="required" size="6" />
<input type="text" class="form-control" id="schedule" style="font-size:12px;font-family: Verdana;word-spacing:23px;" name="row[schedule]" value="* * * * *" data-rule="required; remote(general/crontab/check_schedule)" />
<div id="schedulepicker">
<pre><code>* * * * *
- - - - -
| | | | +--- day of week (0 - 7) (Sunday=0 or 7)
| | | +-------- month (1 - 12)
| | +------------- day of month (1 - 31)
| +------------------ hour (0 - 23)
+----------------------- min (0 - 59)</code></pre>
<h5>{:__('The next %s times the execution time', '<input type="number" id="pickdays" class="form-control text-center" value="7" style="display: inline-block;width:80px;">')}</h5>
<ol id="scheduleresult" class="list-group">
</ol>
</div>
</div>
</div>
<div class="form-group">
... ...
... ... @@ -70,7 +70,7 @@
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div>
</div>
<div class="form-group hide layer-footer">
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed">{:__('OK')}</button>
... ...
<style>
.content {
padding-bottom:50px;
}
</style>
<form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
... ... @@ -48,7 +54,7 @@
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div>
</div>
<div class="form-group hide layer-footer">
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed">{:__('OK')}</button>
... ...
... ... @@ -28,7 +28,7 @@
{foreach $value as $key => $vo}
<dd class="form-inline">
<input type="text" name="field[{$key}]" class="form-control" id="field-{$key}" value="{$key}" size="10" />
<input type="text" name="value[{$key}]" class="form-control" id="value-{$key}" value="{$vo}" size="40" />
<input type="text" name="value[{$key}]" class="form-control" id="value-{$key}" value="{:is_array($vo)?'':$vo}" size="40" />
<span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span>
<span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span>
</dd>
... ...
... ... @@ -165,13 +165,22 @@ class Backend extends Controller
'referer' => Session::get("referer")
];
Lang::load(APP_PATH . $modulename . '/lang/' . $lang . '/' . str_replace('.', '/', $controllername) . '.php');
$this->loadlang($controllername);
$this->assign('site', $site);
$this->assign('config', $config);
$this->assign('admin', Session::get('admin'));
}
/**
* 加载语言文件
* @param string $name
*/
protected function loadlang($name)
{
Lang::load(APP_PATH . $this->request->module() . '/lang/' . Lang::detect() . '/' . str_replace('.', '/', $name) . '.php');
}
/**
* 生成查询所需要的条件,排序方式
... ...
... ... @@ -62,9 +62,18 @@ class Frontend extends Controller
'moduleurl' => url("/{$modulename}", '', false),
'language' => $lang
];
Lang::load(APP_PATH . $modulename . '/lang/' . $lang . '/' . str_replace('.', '/', $controllername) . '.php');
$this->loadlang($controllername);
$this->assign('site', Config::get("site"));
$this->assign('config', $config);
}
/**
* 加载语言文件
* @param string $name
*/
protected function loadlang($name)
{
Lang::load(APP_PATH . $this->request->module() . '/lang/' . Lang::detect() . '/' . str_replace('.', '/', $name) . '.php');
}
}
... ...
... ... @@ -17,8 +17,25 @@ class Crontab extends Model
];
// 追加属性
protected $append = [
'type_text'
];
public static function getTypeList()
{
return [
'url' => __('Request Url'),
'sql' => __('Execute Sql Script'),
'shell' => __('Execute Shell'),
];
}
public function getTypeTextAttr($value, $data)
{
$typelist = self::getTypeList();
$value = $value ? $value : $data['type'];
return $value && isset($typelist[$value]) ? $typelist[$value] : $value;
}
protected function setBegintimeAttr($value)
{
return $value && !is_numeric($value) ? strtotime($value) : $value;
... ...
... ... @@ -24,10 +24,9 @@ class Ajax extends Frontend
public function lang()
{
header('Content-Type: application/javascript');
$modulename = $this->request->module();
$callback = $this->request->get('callback');
$controllername = input("controllername");
Lang::load(APP_PATH . $modulename . '/lang/' . Lang::detect() . '/' . str_replace('.', '/', $controllername) . '.php');
$this->loadlang($controllername);
//强制输出JSON Object
$result = 'define(' . json_encode(Lang::get(), JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE) . ');';
return $result;
... ...
... ... @@ -112,13 +112,16 @@ class Autotask extends Controller
}
else if ($crontab['type'] == 'sql')
{
//这里需要强制重连数据库,使用已有的连接会报2014错误
$connect = Db::connect([], true);
$connect->execute("select 1");
// 执行SQL
Db::getPdo()->exec($crontab['content']);
$connect->getPdo()->exec($crontab['content']);
}
else if ($crontab['type'] == 'shell')
{
// 执行Shell
exec( $crontab['content'] . ' >> ' . $logDir . date("Y-m-d") . '.log 2>&1 &');
exec($crontab['content'] . ' >> ' . $logDir . date("Y-m-d") . '.log 2>&1 &');
}
}
catch (Exception $e)
... ...
... ... @@ -19,7 +19,8 @@
"topthink/framework": "^5.0",
"overtrue/wechat": "~3.1",
"endroid/qrcode": "^1.9",
"topthink/think-captcha": "^1.0"
"topthink/think-captcha": "^1.0",
"mtdowling/cron-expression": "^1.2"
},
"config": {
"preferred-install": "dist"
... ...
... ... @@ -100,6 +100,19 @@ body.is-dialog {
.searchit {
border-bottom: 1px dashed #3c8dbc;
}
/* 固定的底部按钮 */
.fixed-footer {
position: fixed;
bottom: 0;
background-color: #ecf0f1;
width: 100%;
margin-bottom: 0;
padding: 10px;
}
/* 包裹在layer外层 */
.layer-footer {
display: none;
}
table.table-template {
overflow: hidden;
}
... ...
... ... @@ -140,11 +140,12 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'moment'], function ($
zIndex: Backend.api.layer.zIndex,
skin: 'layui-layer-noborder',
success: function (layero, index) {
var that = this;
//$(layero).removeClass("layui-layer-border");
Backend.api.layer.setTop(layero);
var frame = Backend.api.layer.getChildFrame('html', index);
var layerfooter = frame.find(".layer-footer");
Backend.api.layerfooter(layero, index);
Backend.api.layerfooter(layero, index, that);
//绑定事件
if (layerfooter.size() > 0) {
... ... @@ -155,7 +156,7 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'moment'], function ($
var target = layerfooter[0];
// 创建观察者对象
var observer = new MutationObserver(function (mutations) {
Backend.api.layerfooter(layero, index);
Backend.api.layerfooter(layero, index, that);
mutations.forEach(function (mutation) {
});
});
... ... @@ -170,7 +171,7 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'moment'], function ($
}, options ? options : {}));
return false;
},
layerfooter: function (layero, index) {
layerfooter: function (layero, index, that) {
var frame = Backend.api.layer.getChildFrame('html', index);
var layerfooter = frame.find(".layer-footer");
if (layerfooter.size() > 0) {
... ... @@ -188,11 +189,11 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'moment'], function ($
var oldheg = heg + titHeight + btnHeight;
var maxheg = 600;
if (frame.outerWidth() < 768) {
maxheg = $(window).height() - 28;
if (frame.outerWidth() < 768 || that.area[0].indexOf("%") > -1) {
maxheg = $(window).height();
}
// 如果有.layer-footer或窗口小于600则重新排
if (layerfooter.size() > 0 || oldheg < maxheg) {
if (layerfooter.size() > 0 || oldheg < maxheg || that.area[0].indexOf("%") > -1) {
var footerHeight = layero.find('.layui-layer-footer').outerHeight() || 0;
footerHeight = 0;
if (oldheg >= maxheg) {
... ... @@ -374,6 +375,10 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'moment'], function ($
Toastr.error(__('Operation failed'));
}
});
//修复含有fixed-footer类的body边距
if ($(".fixed-footer").size() > 0) {
$(document.body).css("padding-bottom", $(".fixed-footer").height());
}
}
};
//将Layer暴露到全局中去
... ...
... ... @@ -24,12 +24,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
[
{field: 'state', checkbox: true, },
{field: 'id', title: 'ID'},
{field: 'type', title: __('Type')},
{field: 'type_text', title: __('Type'), operate:false},
{field: 'title', title: __('Title')},
{field: 'maximums', title: __('Maximums')},
{field: 'executes', title: __('Executes')},
{field: 'begintime', title: __('Begin time'), formatter: Table.api.formatter.datetime},
{field: 'endtime', title: __('End time'), formatter: Table.api.formatter.datetime},
{field: 'nexttime', title: __('Next execute time'), formatter: Table.api.formatter.datetime, operate:false},
{field: 'executetime', title: __('Execute time'), formatter: Table.api.formatter.datetime},
{field: 'weigh', title: __('Weigh')},
{field: 'status', title: __('Status'), formatter: Table.api.formatter.status},
... ... @@ -49,22 +50,23 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
},
api: {
bindevent: function () {
$('#schedule').on('valid.field', function (e, result) {
$("#pickdays").trigger("change");
});
Form.api.bindevent($("form[role=form]"));
//拖拽排序
require(['crontab'], function () {
$('#schedulepicker').jqCron({
lang: 'cn',
default_value: '* * * * 0-2',
multiple_dom: true,
multiple_month: true,
multiple_mins: true,
multiple_dow: true,
multiple_time_hours: true,
multiple_time_minutes: true,
no_reset_button: false,
bind_to: $("#schedule")
});
$(document).on("change", "#pickdays", function () {
$("#scheduleresult").html(__('Loading'));
$.post("general/crontab/get_schedule_future", {schedule: $("#schedule").val(), days:$(this).val()}, function (ret) {
$("#scheduleresult").html("");
if (typeof ret.futuretime !== 'undefined' && $.isArray(ret.futuretime)) {
$.each(ret.futuretime, function (i, j) {
$("#scheduleresult").append("<li class='list-group-item'>" + j + "<span class='badge'>" + (i + 1) + "</span></li>");
});
}
}, 'json');
});
$("#pickdays").trigger("change");
}
}
};
... ...
... ... @@ -6551,11 +6551,12 @@ define('backend',['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'moment'], f
zIndex: Backend.api.layer.zIndex,
skin: 'layui-layer-noborder',
success: function (layero, index) {
var that = this;
//$(layero).removeClass("layui-layer-border");
Backend.api.layer.setTop(layero);
var frame = Backend.api.layer.getChildFrame('html', index);
var layerfooter = frame.find(".layer-footer");
Backend.api.layerfooter(layero, index);
Backend.api.layerfooter(layero, index, that);
//绑定事件
if (layerfooter.size() > 0) {
... ... @@ -6566,7 +6567,7 @@ define('backend',['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'moment'], f
var target = layerfooter[0];
// 创建观察者对象
var observer = new MutationObserver(function (mutations) {
Backend.api.layerfooter(layero, index);
Backend.api.layerfooter(layero, index, that);
mutations.forEach(function (mutation) {
});
});
... ... @@ -6581,7 +6582,7 @@ define('backend',['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'moment'], f
}, options ? options : {}));
return false;
},
layerfooter: function (layero, index) {
layerfooter: function (layero, index, that) {
var frame = Backend.api.layer.getChildFrame('html', index);
var layerfooter = frame.find(".layer-footer");
if (layerfooter.size() > 0) {
... ... @@ -6599,11 +6600,11 @@ define('backend',['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'moment'], f
var oldheg = heg + titHeight + btnHeight;
var maxheg = 600;
if (frame.outerWidth() < 768) {
maxheg = $(window).height() - 28;
if (frame.outerWidth() < 768 || that.area[0].indexOf("%") > -1) {
maxheg = $(window).height();
}
// 如果有.layer-footer或窗口小于600则重新排
if (layerfooter.size() > 0 || oldheg < maxheg) {
if (layerfooter.size() > 0 || oldheg < maxheg || that.area[0].indexOf("%") > -1) {
var footerHeight = layero.find('.layui-layer-footer').outerHeight() || 0;
footerHeight = 0;
if (oldheg >= maxheg) {
... ... @@ -6785,6 +6786,10 @@ define('backend',['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'moment'], f
Toastr.error(__('Operation failed'));
}
});
//修复含有fixed-footer类的body边距
if ($(".fixed-footer").size() > 0) {
$(document.body).css("padding-bottom", $(".fixed-footer").height());
}
}
};
//将Layer暴露到全局中去
... ... @@ -8544,7 +8549,7 @@ define('upload',['jquery', 'bootstrap', 'backend', 'plupload', 'dragsort', 'temp
UploadProgress: function (up, file) {
//这里可以改成其它的表现形式
//document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = '<span>' + file.percent + "%</span>";
$(that).prop("disabled", true).html("<i class='fa fa-upload'></i> 上传" + file.percent + "%");
$(that).prop("disabled", true).html("<i class='fa fa-upload'></i> " + __('Upload') + file.percent + "%");
},
FileUploaded: function (up, file, info) {
var options = this.getOption();
... ...
... ... @@ -66,7 +66,7 @@ define(['jquery', 'bootstrap', 'backend', 'plupload', 'dragsort', 'template'], f
UploadProgress: function (up, file) {
//这里可以改成其它的表现形式
//document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = '<span>' + file.percent + "%</span>";
$(that).prop("disabled", true).html("<i class='fa fa-upload'></i> 上传" + file.percent + "%");
$(that).prop("disabled", true).html("<i class='fa fa-upload'></i> " + __('Upload') + file.percent + "%");
},
FileUploaded: function (up, file, info) {
var options = this.getOption();
... ...
... ... @@ -123,6 +123,19 @@ body.is-dialog {
.searchit{
border-bottom:1px dashed @link-color;
}
/* 固定的底部按钮 */
.fixed-footer {
position: fixed;
bottom:0;
background-color: #ecf0f1;
width:100%;
margin-bottom:0;
padding:10px;
}
/* 包裹在layer外层 */
.layer-footer {
display:none;
}
table.table-template{
overflow:hidden;
... ...
... ... @@ -43,6 +43,10 @@ if (is_file($lockFile))
{
$errInfo = "当前已经安装{$sitename},如果需要重新安装,请手动移除application/admin/command/Install/install.lock文件";
}
else if (!is_writeable($lockFile))
{
$errInfo = "当前权限不足,无法写入锁定文件application/admin/command/Install/install.lock";
}
else if (version_compare(PHP_VERSION, '5.5.0', '<'))
{
$errInfo = "当前版本(" . PHP_VERSION . ")过低,请使用PHP5.5以上版本";
... ... @@ -62,7 +66,7 @@ else
{
if (!is_dir(ROOT_PATH . $v))
{
$errInfo = '请先下载扩展资源包覆盖后再安装,<a href="' . $link['qqun'] . '" target="_blank">群共享下载</a> <a href="' . $link['osc'] . '" target="_blank">码云下载</a>';
$errInfo = '请先下载完整包覆盖后再安装,<a href="' . $link['qqun'] . '" target="_blank">群共享下载</a> <a href="' . $link['osc'] . '" target="_blank">码云下载</a>';
break;
}
}
... ...