作者 郭盛
1 个管道 的构建 通过 耗费 7 秒

添加接口

正在显示 61 个修改的文件 包含 3418 行增加61 行删除

要显示太多修改。

为保证性能只显示 61 of 61+ 个文件。

<?php
namespace addons\crontab;
use app\common\library\Menu;
use think\Addons;
/**
* 定时任务
*/
class Crontab extends Addons
{
/**
* 插件安装方法
* @return bool
*/
public function install()
{
$menu = [
[
'name' => 'general/crontab',
'title' => '定时任务',
'icon' => 'fa fa-tasks',
'remark' => '类似于Linux的Crontab定时任务,可以按照设定的时间进行任务的执行,目前支持三种任务:请求URL、执行SQL、执行Shell',
'sublist' => [
['name' => 'general/crontab/index', 'title' => '查看'],
['name' => 'general/crontab/add', 'title' => '添加'],
['name' => 'general/crontab/edit', 'title' => '编辑 '],
['name' => 'general/crontab/del', 'title' => '删除'],
['name' => 'general/crontab/multi', 'title' => '批量更新'],
]
]
];
Menu::create($menu, 'general');
return true;
}
/**
* 插件卸载方法
* @return bool
*/
public function uninstall()
{
Menu::delete('general/crontab');
return true;
}
/**
* 插件启用方法
*/
public function enable()
{
Menu::enable('general/crontab');
}
/**
* 插件禁用方法
*/
public function disable()
{
Menu::disable('general/crontab');
}
}
... ...
<?php
namespace app\admin\controller\general;
use app\common\controller\Backend;
use Cron\CronExpression;
/**
* 定时任务
*
* @icon fa fa-tasks
* @remark 类似于Linux的Crontab定时任务,可以按照设定的时间进行任务的执行
*/
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('typeList', \app\admin\model\Crontab::getTypeList());
$this->assignconfig('typeList', \app\admin\model\Crontab::getTypeList());
}
/**
* 查看
*/
public function index()
{
if ($this->request->isAjax()) {
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
$time = time();
foreach ($list as $k => &$v) {
$cron = CronExpression::factory($v['schedule']);
$v['nexttime'] = $time > $v['endtime'] ? __('None') : $cron->getNextRunDate()->getTimestamp();
}
$result = array("total" => $total, "rows" => $list);
return json($result);
}
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)) {
$this->success();
} else {
$this->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) {
}
$this->success("", null, ['futuretime' => $time]);
}
}
... ...
<?php
namespace app\admin\controller\general;
use app\common\controller\Backend;
/**
* 定时任务
*
* @icon fa fa-tasks
* @remark 类似于Linux的Crontab定时任务,可以按照设定的时间进行任务的执行
*/
class CrontabLog extends Backend
{
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = model('CrontabLog');
$this->view->assign('statusList', $this->model->getStatusList());
$this->assignconfig('statusList', $this->model->getStatusList());
}
/**
* 查看
*/
public function index()
{
if ($this->request->isAjax()) {
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
$list = collection($list)->toArray();
$result = array("total" => $total, "rows" => $list);
return json($result);
}
return $this->view->fetch();
}
public function detail($ids = null)
{
$row = $this->model->get($ids);
if (!$row) {
$this->error(__('No Results were found'));
}
$this->view->assign("row", $row);
return $this->view->fetch();
}
}
... ...
<?php
return [
'Title' => '任务标题',
'Maximums' => '最多执行',
'Sleep' => '延迟秒数',
'Schedule' => '执行周期',
'Executes' => '执行次数',
'Completed' => '已完成',
'Expired' => '已过期',
'Hidden' => '已禁用',
'Logs' => '日志信息',
'Crontab rules' => 'Crontab规则',
'No limit' => '无限制',
'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 次的执行时间',
];
... ...
<?php
return [
'Title' => '任务标题',
'Crontab_id' => '定时任务ID',
'Success' => '成功',
'Failure' => '失败',
'Content' => '返回结果',
'Result' => '执行结果',
'Complete time' => '完成时间',
'Execute time' => '最后执行时间',
];
... ...
<?php
namespace app\admin\model;
use think\Model;
class Crontab extends Model
{
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
// 定义字段类型
protected $type = [
];
// 追加属性
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;
}
protected function setEndtimeAttr($value)
{
return $value && !is_numeric($value) ? strtotime($value) : $value;
}
protected function setExecutetimeAttr($value)
{
return $value && !is_numeric($value) ? strtotime($value) : $value;
}
}
... ...
<?php
namespace app\admin\model;
use think\Model;
class CrontabLog extends Model
{
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = false;
protected $updateTime = false;
// 定义字段类型
protected $type = [
];
// 追加属性
protected $append = [
];
public function getStatusList()
{
return ['normal' => __('Normal'), 'hidden' => __('Hidden')];
}
public function getStatusTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
$list = $this->getStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
}
... ...
<style type="text/css">
#schedulepicker {
padding-top:7px;
}
</style>
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label for="name" class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="title" name="row[title]" value="" data-rule="required" />
</div>
</div>
<div class="form-group">
<label for="name" class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('row[type]', $typeList, null, ['class'=>'form-control', 'data-rule'=>'required'])}
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Content')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea name="row[content]" id="conent" cols="30" rows="5" class="form-control" data-rule="required"></textarea>
</div>
</div>
<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 class="input-group margin-bottom-sm">
<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)"/>
<span class="input-group-btn">
<a href="https://www.fastadmin.net/store/crontab.html" target="_blank" class="btn btn-default"><i class="fa fa-info-circle"></i> {:__('Crontab rules')}</a>
</span>
<span class="msg-box n-right"></span>
</div>
<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">
<label for="maximums" class="control-label col-xs-12 col-sm-2">{:__('Maximums')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="number" class="form-control" id="maximums" name="row[maximums]" value="0" data-rule="required" size="6" />
</div>
</div>
<div class="form-group">
<label for="begintime" class="control-label col-xs-12 col-sm-2">{:__('Begin time')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control datetimepicker" id="begintime" name="row[begintime]" value="" data-rule="{:__('Begin time')}:required" size="6" />
</div>
</div>
<div class="form-group">
<label for="endtime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control datetimepicker" id="endtime" name="row[endtime]" value="" data-rule="{:__('End time')}:required;match(gte, row[begintime], datetime)" size="6" />
</div>
</div>
<div class="form-group">
<label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control" id="weigh" name="row[weigh]" value="0" data-rule="required" size="6" />
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div>
</div>
<div class="form-group hide 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 disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<style type="text/css">
#schedulepicker {
padding-top: 7px;
}
</style>
<form id="edit-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label for="name" class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="title" name="row[title]" value="{$row.title}" data-rule="required"/>
</div>
</div>
<div class="form-group">
<label for="name" class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('row[type]', $typeList, $row['type'], ['class'=>'form-control', 'data-rule'=>'required'])}
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Content')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea name="row[content]" id="conent" cols="30" rows="5" class="form-control" data-rule="required">{$row.content}</textarea>
</div>
</div>
<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 class="input-group margin-bottom-sm">
<input type="text" class="form-control" id="schedule" style="font-size:12px;font-family: Verdana;word-spacing:23px;" name="row[schedule]" value="{$row.schedule}" data-rule="required; remote(general/crontab/check_schedule)"/>
<span class="input-group-btn">
<a href="https://www.fastadmin.net/store/crontab.html" target="_blank" class="btn btn-default"><i class="fa fa-info-circle"></i> {:__('Crontab rules')}</a>
</span>
<span class="msg-box n-right"></span>
</div>
<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">
<label for="maximums" class="control-label col-xs-12 col-sm-2">{:__('Maximums')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="number" class="form-control" id="maximums" name="row[maximums]" value="{$row.maximums}" data-rule="required" size="6"/>
</div>
</div>
<div class="form-group">
<label for="begintime" class="control-label col-xs-12 col-sm-2">{:__('Begin time')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control datetimepicker" id="begintime" name="row[begintime]" value="{$row.begintime|datetime}" data-rule="{:__('Begin time')}:required" size="6"/>
</div>
</div>
<div class="form-group">
<label for="endtime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control datetimepicker" id="endtime" name="row[endtime]" value="{$row.endtime|datetime}" data-rule="{:__('End time')}:required;match(gte, row[begintime], datetime)" size="6"/>
</div>
</div>
<div class="form-group">
<label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control" id="weigh" name="row[weigh]" value="{$row.weigh}" data-rule="required" size="6"/>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'completed'=>__('Completed'), 'expired'=>__('Expired'), 'hidden'=>__('Hidden')], $row['status'])}
</div>
</div>
<div class="form-group hide 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 disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<div class="panel panel-default panel-intro">
<div class="panel-heading">
{:build_heading(null,FALSE)}
<ul class="nav nav-tabs" data-field="type">
<li class="active"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li>
{foreach name="typeList" item="vo"}
<li><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li>
{/foreach}
</ul>
</div>
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{:build_toolbar('refresh,add,edit,del')}
</div>
<table id="table" class="table table-striped table-bordered table-hover"
data-operate-edit="{:$auth->check('general/crontab/edit')}"
data-operate-del="{:$auth->check('general/crontab/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
... ...
<style type="text/css">
#schedulepicker {
padding-top:7px;
}
</style>
<form id="edit-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Content')}:</label>
<div class="col-xs-12 col-sm-10">
<textarea name="row[content]" id="conent" cols="30" style="width:100%;" rows="20" class="form-control" data-rule="required" readonly>{$row.content|htmlentities}</textarea>
</div>
</div>
<div class="form-group">
<label for="executetime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control datetimepicker" id="executetime" name="row[executetime]" value="{$row.executetime|datetime}" data-rule="{:__('End time')}:required;match(gte, row[begintime], datetime)" size="6" disabled />
</div>
</div>
<div class="form-group">
<label for="completetime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control datetimepicker" id="completetime" name="row[completetime]" value="{$row.completetime|datetime}" data-rule="{:__('End time')}:required;match(gte, row[begintime], datetime)" size="6" disabled />
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
<div style="padding-top:8px;">
{if $row['status']=='success'}<span class="label label-success">{:__('Success')}</span>{else/}<span class="label label-danger">{:__('Failure')}</span>{/if}
</div>
</div>
</div>
<div class="form-group hide layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="button" class="btn btn-success btn-embossed" onclick="parent.Layer.close(parent.Layer.getFrameIndex(window.name))">{:__('Close')}</button>
</div>
</div>
</form>
... ...
<div class="panel panel-default panel-intro">
<div class="panel-heading">
{:build_heading(null,FALSE)}
<ul class="nav nav-tabs" data-field="status">
<li class="active"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li>
{foreach name="statusList" item="vo"}
<li><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li>
{/foreach}
</ul>
</div>
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{:build_toolbar('refresh,del')}
</div>
<table id="table" class="table table-striped table-bordered table-hover"
data-operate-detail="{:$auth->check('general/crontab/detail')}"
data-operate-del="{:$auth->check('general/crontab/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
... ...
<?php
return [
];
... ...
<?php
namespace addons\crontab\controller;
use addons\crontab\model\Crontab;
use Cron\CronExpression;
use fast\Http;
use think\Controller;
use think\Db;
use think\Exception;
use think\Log;
/**
* 定时任务接口
*
* 以Crontab方式每分钟定时执行,且只可以Cli方式运行
* @internal
*/
class Autotask extends Controller
{
/**
* 初始化方法,最前且始终执行
*/
public function _initialize()
{
// 只可以以cli方式执行
if (!$this->request->isCli()) {
$this->error('Autotask script only work at client!');
}
parent::_initialize();
// 清除错误
error_reporting(0);
// 设置永不超时
set_time_limit(0);
}
/**
* 执行定时任务
*/
public function index()
{
$time = time();
$logDir = LOG_PATH . 'crontab/';
if (!is_dir($logDir)) {
mkdir($logDir, 0755);
}
//筛选未过期且未完成的任务
$crontabList = Crontab::where('status', '=', 'normal')->order('weigh desc,id desc')->select();
$execTime = time();
foreach ($crontabList as $crontab) {
$update = [];
$execute = false;
if ($time < $crontab['begintime']) {
//任务未开始
continue;
}
if ($crontab['maximums'] && $crontab['executes'] > $crontab['maximums']) {
//任务已超过最大执行次数
$update['status'] = 'completed';
} else {
if ($crontab['endtime'] > 0 && $time > $crontab['endtime']) {
//任务已过期
$update['status'] = 'expired';
} else {
//重复执行
//如果未到执行时间则继续循环
$cron = CronExpression::factory($crontab['schedule']);
if (!$cron->isDue(date("YmdHi", $execTime)) || date("YmdHi", $execTime) === date("YmdHi", $crontab['executetime'])) {
continue;
}
$execute = true;
}
}
// 如果允许执行
if ($execute) {
$update['executetime'] = $time;
$update['executes'] = $crontab['executes'] + 1;
$update['status'] = ($crontab['maximums'] > 0 && $update['executes'] >= $crontab['maximums']) ? 'completed' : 'normal';
}
// 如果需要更新状态
if (!$update) {
continue;
}
// 更新状态
$crontab->save($update);
// 将执行放在后面是为了避免超时导致多次执行
if (!$execute) {
continue;
}
$result = false;
$message = '';
try {
if ($crontab['type'] == 'url') {
if (substr($crontab['content'], 0, 1) == "/") {
// 本地项目URL
$message = shell_exec('php ' . ROOT_PATH . 'public/index.php ' . $crontab['content']);
$result = $message ? true : false;
} else {
$arr = explode(" ", $crontab['content']);
$url = $arr[0];
$params = isset($arr[1]) ? $arr[1] : '';
$method = isset($arr[2]) ? $arr[2] : 'POST';
try {
// 远程异步调用URL
$ret = Http::sendRequest($url, $params, $method);
$result = $ret['ret'];
$message = $ret['msg'];
} catch (\Exception $e) {
$message = $e->getMessage();
}
}
} elseif ($crontab['type'] == 'sql') {
$ret = $this->sql($crontab['content']);
$result = $ret['ret'];
$message = $ret['msg'];
} elseif ($crontab['type'] == 'shell') {
// 执行Shell
$message = shell_exec($crontab['content']);
$result = $message ? true : false;
}
} catch (\Exception $e) {
$message = $e->getMessage();
}
$log = [
'crontab_id' => $crontab['id'],
'executetime' => $time,
'completetime' => time(),
'content' => $message,
'status' => $result ? 'success' : 'failure',
];
Db::name("crontab_log")->insert($log);
}
return "Execute completed!\n";
}
/**
* 执行SQL语句
*/
protected function sql($sql)
{
//这里需要强制重连数据库,使用已有的连接会报2014错误
$connect = Db::connect([], true);
$connect->execute("select 1");
// 执行SQL
$sqlquery = str_replace('__PREFIX__', config('database.prefix'), $sql);
$sqls = preg_split("/;[ \t]{0,}\n/i", $sqlquery);
$result = false;
$message = '';
$connect->startTrans();
try {
foreach ($sqls as $key => $val) {
if (trim($val) == '' || substr($val, 0, 2) == '--' || substr($val, 0, 2) == '/*') {
continue;
}
$message .= "\nSQL:{$val}\n";
$val = rtrim($val, ';');
if (preg_match("/^(select|explain)(.*)/i ", $val)) {
$count = $connect->execute($val);
if ($count > 0) {
$resultlist = Db::query($val);
} else {
$resultlist = [];
}
$message .= "Total:{$count}\n";
$j = 1;
foreach ($resultlist as $m => $n) {
$message .= "\n";
$message .= "Row:{$j}\n";
foreach ($n as $k => $v) {
$message .= "{$k}{$v}\n";
}
$j++;
}
} else {
$count = $connect->getPdo()->exec($val);
$message = "Affected rows:{$count}";
}
}
$connect->commit();
$result = true;
} catch (\PDOException $e) {
$message = $e->getMessage();
$connect->rollback();
$result = false;
}
return ['ret' => $result, 'msg' => $message];
}
}
... ...
<?php
namespace addons\crontab\controller;
use think\addons\Controller;
class Index extends Controller
{
public function index()
{
$this->error("当前插件暂无前台页面");
}
}
... ...
name = crontab
title = 定时任务
intro = 便捷的后台定时任务管理
author = Karson
website = https://www.fastadmin.net
version = 1.0.5
state = 1
url = /addons/crontab
... ...
CREATE TABLE IF NOT EXISTS `__PREFIX__crontab` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
`type` varchar(10) NOT NULL DEFAULT '' COMMENT '事件类型',
`title` varchar(100) NOT NULL DEFAULT '' COMMENT '事件标题',
`content` text NOT NULL COMMENT '事件内容',
`schedule` varchar(100) NOT NULL DEFAULT '' COMMENT 'Crontab格式',
`sleep` tinyint(1) UNSIGNED NOT NULL DEFAULT '0' COMMENT '延迟秒数执行',
`maximums` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '最大执行次数 0为不限',
`executes` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '已经执行的次数',
`createtime` int(10) DEFAULT NULL COMMENT '创建时间',
`updatetime` int(10) DEFAULT NULL COMMENT '更新时间',
`begintime` int(10) DEFAULT NULL COMMENT '开始时间',
`endtime` int(10) DEFAULT NULL COMMENT '结束时间',
`executetime` int(10) DEFAULT NULL COMMENT '最后执行时间',
`weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重',
`status` enum('completed','expired','hidden','normal') NOT NULL DEFAULT 'normal' COMMENT '状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='定时任务表';
BEGIN;
INSERT INTO `__PREFIX__crontab` (`id`, `type`, `title`, `content`, `schedule`, `sleep`, `maximums`, `executes`, `createtime`, `updatetime`, `begintime`, `endtime`, `executetime`, `weigh`, `status`) VALUES
(1, 'url', '请求百度', 'https://www.baidu.com', '* * * * *', 0, 0, 0, 1497070825, 1501253101, 1483200000, 1830268800, 1501253101, 1, 'normal'),
(2, 'sql', '查询一条SQL', 'SELECT 1;', '* * * * *', 0, 0, 0, 1497071095, 1501253101, 1483200000, 1830268800, 1501253101, 2, 'normal');
COMMIT;
CREATE TABLE IF NOT EXISTS `__PREFIX__crontab_log` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`crontab_id` int(10) DEFAULT NULL COMMENT '任务ID',
`executetime` int(10) DEFAULT NULL COMMENT '执行时间',
`completetime` int(10) DEFAULT NULL COMMENT '结束时间',
`content` text COMMENT '执行结果',
`status` enum('success','failure') DEFAULT 'failure' COMMENT '状态',
PRIMARY KEY (`id`),
KEY `crontab_id` (`crontab_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='定时任务日志表';
\ No newline at end of file
... ...
<?php
namespace addons\crontab\model;
use think\Model;
class Crontab extends Model
{
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
// 定义字段类型
protected $type = [
];
// 追加属性
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;
}
protected function setEndtimeAttr($value)
{
return $value && !is_numeric($value) ? strtotime($value) : $value;
}
protected function setExecutetimeAttr($value)
{
return $value && !is_numeric($value) ? strtotime($value) : $value;
}
}
... ...
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
// 初始化表格参数配置
Table.api.init({
extend: {
index_url: 'general/crontab/index',
add_url: 'general/crontab/add',
edit_url: 'general/crontab/edit',
del_url: 'general/crontab/del',
multi_url: 'general/crontab/multi',
table: 'crontab'
}
});
var table = $("#table");
// 初始化表格
table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
sortName: 'weigh',
columns: [
[
{field: 'state', checkbox: true,},
{field: 'id', title: 'ID'},
{field: 'type', title: __('Type'), searchList: Config.typeList, formatter: Table.api.formatter.label},
{field: 'title', title: __('Title')},
{field: 'maximums', title: __('Maximums'), formatter: Controller.api.formatter.maximums},
{field: 'executes', title: __('Executes')},
{field: 'begintime', title: __('Begin time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange'},
{field: 'endtime', title: __('End time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange'},
{field: 'nexttime', title: __('Next execute time'), formatter: Controller.api.formatter.nexttime, operate: false, addclass: 'datetimerange', sortable: true},
{field: 'executetime', title: __('Execute time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{field: 'weigh', title: __('Weigh')},
{field: 'status', title: __('Status'), formatter: Table.api.formatter.status},
{
field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate,
buttons: [
{
name: "detail",
icon: "fa fa-list",
title: function (row, index) {
return __('Logs') + "[" + row['title'] + "]";
},
text: __('Logs'),
classname: "btn btn-xs btn-info btn-dialog",
url: "general/crontab_log/index?crontab_id={ids}",
}
]
}
]
]
});
// 为表格绑定事件
Table.api.bindevent(table);
},
add: function () {
Controller.api.bindevent();
},
edit: function () {
Controller.api.bindevent();
},
api: {
bindevent: function () {
$('#schedule').on('valid.field', function (e, result) {
$("#pickdays").trigger("change");
});
Form.api.bindevent($("form[role=form]"));
$(document).on("change", "#pickdays", function () {
Fast.api.ajax({url: "general/crontab/get_schedule_future", data: {schedule: $("#schedule").val(), days: $(this).val()}}, function (data, ret) {
if (typeof data.futuretime !== 'undefined' && $.isArray(data.futuretime)) {
var result = [];
$.each(data.futuretime, function (i, j) {
result.push("<li class='list-group-item'>" + j + "<span class='badge'>" + (i + 1) + "</span></li>");
});
$("#scheduleresult").html(result.join(""));
} else {
$("#scheduleresult").html("");
}
return false;
});
});
$("#pickdays").trigger("change");
},
formatter: {
nexttime: function (value, row, index) {
if (isNaN(value)) {
return value;
} else {
return Table.api.formatter.datetime.call(this, value, row, index);
}
},
maximums: function (value, row, index) {
return value === 0 ? __('No limit') : value;
}
}
}
};
return Controller;
});
\ No newline at end of file
... ...
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
// 初始化表格参数配置
Table.api.init({
extend: {
index_url: 'general/crontab_log/index',
add_url: 'general/crontab_log/add',
edit_url: '',
del_url: 'general/crontab_log/del',
multi_url: 'general/crontab_log/multi',
table: 'crontab'
}
});
var table = $("#table");
// 初始化表格
table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
sortName: 'id',
columns: [
[
{field: 'state', checkbox: true,},
{field: 'id', title: 'ID'},
{field: 'crontab_id', title: __('Crontab_id'), formatter: Table.api.formatter.search},
{field: 'executetime', title: __('Execute time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{field: 'completetime', title: __('Complete time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{field: 'status', title: __('Status'), searchList: Config.statusList, custom: {success: 'success', failure: 'danger'}, formatter: Table.api.formatter.status},
{
field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate,
buttons: [
{
name: "detail",
text: __("Result"),
classname: "btn btn-xs btn-info btn-dialog",
icon: "fa fa-file",
url: "general/crontab_log/detail",
extend: "data-window='parent'"
}
]
}
]
]
});
// 为表格绑定事件
Table.api.bindevent(table);
},
add: function () {
Controller.api.bindevent();
},
edit: function () {
Controller.api.bindevent();
},
api: {
bindevent: function () {
Form.api.bindevent($("form[role=form]"));
},
}
};
return Controller;
});
\ No newline at end of file
... ...
<?php
namespace app\admin\controller;
use app\common\controller\Backend;
/**
* 收款码图片
*
* @icon fa fa-circle-o
*/
class Payimage extends Backend
{
/**
* Payimage模型对象
* @var \app\admin\model\Payimage
*/
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = new \app\admin\model\Payimage;
}
/**
* 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
* 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
* 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
*/
}
... ...
<?php
namespace app\admin\controller;
use app\common\controller\Backend;
/**
* 开通会员天数设置
*
* @icon fa fa-circle-o
*/
class Vipdaynum extends Backend
{
/**
* Vipdaynum模型对象
* @var \app\admin\model\Vipdaynum
*/
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = new \app\admin\model\Vipdaynum;
}
/**
* 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
* 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
* 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
*/
}
... ...
<?php
namespace app\admin\controller;
use app\common\controller\Backend;
use think\Db;
/**
* 开通会员订单
*
* @icon fa fa-circle-o
*/
class Viporder extends Backend
{
/**
* Viporder模型对象
* @var \app\admin\model\Viporder
*/
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = new \app\admin\model\Viporder;
}
/**
* 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
* 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
* 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
*/
/**
* 查看
*/
public function index()
{
//设置过滤方法
$this->request->filter(['strip_tags']);
if ($this->request->isAjax()) {
//如果发送的来源是Selectpage,则转发到Selectpage
if ($this->request->request('keyField')) {
return $this->selectpage();
}
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
$list = collection($list)->toArray();
foreach ($list as &$v){
$v['user_id'] = Db::name('user')->where('id',$v['user_id'])->value('username');
}
$result = array("total" => $total, "rows" => $list);
return json($result);
}
return $this->view->fetch();
}
/**
* 编辑
*/
public function edit($ids = null)
{
$row = $this->model->get($ids);
if (!$row) {
$this->error(__('No Results were found'));
}
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) {
if (!in_array($row[$this->dataLimitField], $adminIds)) {
$this->error(__('You have no permission'));
}
}
if ($this->request->isPost()) {
$params = $this->request->post("row/a");
if ($params) {
$params = $this->preExcludeFields($params);
//查询用户的个人资料
$data = Db::name('viporder')->where('id',$ids)->find();
$user = Db::name('user')->where('id',$data['user_id'])->find();
if($params['status'] == 1){
//审核通过
//判断用户是否已经是会员
if($user['identity'] == 1){
$update['identity'] = 2;
$update['expirationtime'] = time()+86400*$data['daynum'];
}else{
$update['expirationtime'] = $user['expirationtime']+86400*$data['daynum'];
}
Db::name('user')->where('id',$data['user_id'])->update($update);
}
$result = false;
Db::startTrans();
try {
//是否采用模型验证
if ($this->modelValidate) {
$name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
$validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate;
$row->validateFailException(true)->validate($validate);
}
$result = $row->allowField(true)->save($params);
Db::commit();
} catch (ValidateException $e) {
Db::rollback();
$this->error($e->getMessage());
} catch (PDOException $e) {
Db::rollback();
$this->error($e->getMessage());
} catch (Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($result !== false) {
$this->success();
} else {
$this->error(__('No rows were updated'));
}
}
$this->error(__('Parameter %s can not be empty', ''));
}
$this->view->assign("row", $row);
return $this->view->fetch();
}
}
... ...
<?php
namespace app\admin\controller\general;
use app\common\controller\Backend;
use Cron\CronExpression;
/**
* 定时任务
*
* @icon fa fa-tasks
* @remark 类似于Linux的Crontab定时任务,可以按照设定的时间进行任务的执行
*/
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('typeList', \app\admin\model\Crontab::getTypeList());
$this->assignconfig('typeList', \app\admin\model\Crontab::getTypeList());
}
/**
* 查看
*/
public function index()
{
if ($this->request->isAjax()) {
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
$time = time();
foreach ($list as $k => &$v) {
$cron = CronExpression::factory($v['schedule']);
$v['nexttime'] = $time > $v['endtime'] ? __('None') : $cron->getNextRunDate()->getTimestamp();
}
$result = array("total" => $total, "rows" => $list);
return json($result);
}
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)) {
$this->success();
} else {
$this->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) {
}
$this->success("", null, ['futuretime' => $time]);
}
}
... ...
<?php
namespace app\admin\controller\general;
use app\common\controller\Backend;
/**
* 定时任务
*
* @icon fa fa-tasks
* @remark 类似于Linux的Crontab定时任务,可以按照设定的时间进行任务的执行
*/
class CrontabLog extends Backend
{
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = model('CrontabLog');
$this->view->assign('statusList', $this->model->getStatusList());
$this->assignconfig('statusList', $this->model->getStatusList());
}
/**
* 查看
*/
public function index()
{
if ($this->request->isAjax()) {
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
$list = collection($list)->toArray();
$result = array("total" => $total, "rows" => $list);
return json($result);
}
return $this->view->fetch();
}
public function detail($ids = null)
{
$row = $this->model->get($ids);
if (!$row) {
$this->error(__('No Results were found'));
}
$this->view->assign("row", $row);
return $this->view->fetch();
}
}
... ...
<?php
return [
'Title' => '任务标题',
'Maximums' => '最多执行',
'Sleep' => '延迟秒数',
'Schedule' => '执行周期',
'Executes' => '执行次数',
'Completed' => '已完成',
'Expired' => '已过期',
'Hidden' => '已禁用',
'Logs' => '日志信息',
'Crontab rules' => 'Crontab规则',
'No limit' => '无限制',
'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 次的执行时间',
];
... ...
<?php
return [
'Title' => '任务标题',
'Crontab_id' => '定时任务ID',
'Success' => '成功',
'Failure' => '失败',
'Content' => '返回结果',
'Result' => '执行结果',
'Complete time' => '完成时间',
'Execute time' => '最后执行时间',
];
... ...
<?php
return [
'Id' => 'id',
'Image' => '微信收款码',
'Aliimage' => '支付宝收款码',
'Createtime' => '创建时间',
'Updatetime' => '修改时间'
];
... ...
<?php
return [
'Id' => 'id',
'Day_num' => '开通会员天数',
'Createtime' => '创建时间',
'Updatetime' => '修改时间'
];
... ...
<?php
return [
'Id' => 'id',
'User_id' => '用户id',
'Order_num' => '订单号后四位',
'Type' => '支付方式(1微信支付2支付宝支付)',
'Daynum' => '开通时长',
'Status' => '审核状态0待审核1审核通过2审核未通过',
'Createtime' => '创建时间',
'Updatetime' => '修改时间'
];
... ...
<?php
namespace app\admin\model;
use think\Model;
class Crontab extends Model
{
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
// 定义字段类型
protected $type = [
];
// 追加属性
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;
}
protected function setEndtimeAttr($value)
{
return $value && !is_numeric($value) ? strtotime($value) : $value;
}
protected function setExecutetimeAttr($value)
{
return $value && !is_numeric($value) ? strtotime($value) : $value;
}
}
... ...
<?php
namespace app\admin\model;
use think\Model;
class CrontabLog extends Model
{
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = false;
protected $updateTime = false;
// 定义字段类型
protected $type = [
];
// 追加属性
protected $append = [
];
public function getStatusList()
{
return ['normal' => __('Normal'), 'hidden' => __('Hidden')];
}
public function getStatusTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
$list = $this->getStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
}
... ...
<?php
namespace app\admin\model;
use think\Model;
class Payimage extends Model
{
// 表名
protected $name = 'payimage';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
protected $deleteTime = false;
// 追加属性
protected $append = [
];
}
... ...
<?php
namespace app\admin\model;
use think\Model;
class Vipdaynum extends Model
{
// 表名
protected $name = 'vipdaynum';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
protected $deleteTime = false;
// 追加属性
protected $append = [
];
}
... ...
<?php
namespace app\admin\model;
use think\Model;
class Viporder extends Model
{
// 表名
protected $name = 'viporder';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
protected $deleteTime = false;
// 追加属性
protected $append = [
];
}
... ...
<?php
namespace app\admin\validate;
use think\Validate;
class Payimage extends Validate
{
/**
* 验证规则
*/
protected $rule = [
];
/**
* 提示消息
*/
protected $message = [
];
/**
* 验证场景
*/
protected $scene = [
'add' => [],
'edit' => [],
];
}
... ...
<?php
namespace app\admin\validate;
use think\Validate;
class Vipdaynum extends Validate
{
/**
* 验证规则
*/
protected $rule = [
];
/**
* 提示消息
*/
protected $message = [
];
/**
* 验证场景
*/
protected $scene = [
'add' => [],
'edit' => [],
];
}
... ...
<?php
namespace app\admin\validate;
use think\Validate;
class Viporder extends Validate
{
/**
* 验证规则
*/
protected $rule = [
];
/**
* 提示消息
*/
protected $message = [
];
/**
* 验证场景
*/
protected $scene = [
'add' => [],
'edit' => [],
];
}
... ...
<style type="text/css">
#schedulepicker {
padding-top:7px;
}
</style>
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label for="name" class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="title" name="row[title]" value="" data-rule="required" />
</div>
</div>
<div class="form-group">
<label for="name" class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('row[type]', $typeList, null, ['class'=>'form-control', 'data-rule'=>'required'])}
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Content')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea name="row[content]" id="conent" cols="30" rows="5" class="form-control" data-rule="required"></textarea>
</div>
</div>
<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 class="input-group margin-bottom-sm">
<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)"/>
<span class="input-group-btn">
<a href="https://www.fastadmin.net/store/crontab.html" target="_blank" class="btn btn-default"><i class="fa fa-info-circle"></i> {:__('Crontab rules')}</a>
</span>
<span class="msg-box n-right"></span>
</div>
<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">
<label for="maximums" class="control-label col-xs-12 col-sm-2">{:__('Maximums')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="number" class="form-control" id="maximums" name="row[maximums]" value="0" data-rule="required" size="6" />
</div>
</div>
<div class="form-group">
<label for="begintime" class="control-label col-xs-12 col-sm-2">{:__('Begin time')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control datetimepicker" id="begintime" name="row[begintime]" value="" data-rule="{:__('Begin time')}:required" size="6" />
</div>
</div>
<div class="form-group">
<label for="endtime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control datetimepicker" id="endtime" name="row[endtime]" value="" data-rule="{:__('End time')}:required;match(gte, row[begintime], datetime)" size="6" />
</div>
</div>
<div class="form-group">
<label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control" id="weigh" name="row[weigh]" value="0" data-rule="required" size="6" />
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div>
</div>
<div class="form-group hide 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 disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<style type="text/css">
#schedulepicker {
padding-top: 7px;
}
</style>
<form id="edit-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label for="name" class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="title" name="row[title]" value="{$row.title}" data-rule="required"/>
</div>
</div>
<div class="form-group">
<label for="name" class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('row[type]', $typeList, $row['type'], ['class'=>'form-control', 'data-rule'=>'required'])}
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Content')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea name="row[content]" id="conent" cols="30" rows="5" class="form-control" data-rule="required">{$row.content}</textarea>
</div>
</div>
<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 class="input-group margin-bottom-sm">
<input type="text" class="form-control" id="schedule" style="font-size:12px;font-family: Verdana;word-spacing:23px;" name="row[schedule]" value="{$row.schedule}" data-rule="required; remote(general/crontab/check_schedule)"/>
<span class="input-group-btn">
<a href="https://www.fastadmin.net/store/crontab.html" target="_blank" class="btn btn-default"><i class="fa fa-info-circle"></i> {:__('Crontab rules')}</a>
</span>
<span class="msg-box n-right"></span>
</div>
<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">
<label for="maximums" class="control-label col-xs-12 col-sm-2">{:__('Maximums')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="number" class="form-control" id="maximums" name="row[maximums]" value="{$row.maximums}" data-rule="required" size="6"/>
</div>
</div>
<div class="form-group">
<label for="begintime" class="control-label col-xs-12 col-sm-2">{:__('Begin time')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control datetimepicker" id="begintime" name="row[begintime]" value="{$row.begintime|datetime}" data-rule="{:__('Begin time')}:required" size="6"/>
</div>
</div>
<div class="form-group">
<label for="endtime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control datetimepicker" id="endtime" name="row[endtime]" value="{$row.endtime|datetime}" data-rule="{:__('End time')}:required;match(gte, row[begintime], datetime)" size="6"/>
</div>
</div>
<div class="form-group">
<label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control" id="weigh" name="row[weigh]" value="{$row.weigh}" data-rule="required" size="6"/>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'completed'=>__('Completed'), 'expired'=>__('Expired'), 'hidden'=>__('Hidden')], $row['status'])}
</div>
</div>
<div class="form-group hide 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 disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<div class="panel panel-default panel-intro">
<div class="panel-heading">
{:build_heading(null,FALSE)}
<ul class="nav nav-tabs" data-field="type">
<li class="active"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li>
{foreach name="typeList" item="vo"}
<li><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li>
{/foreach}
</ul>
</div>
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{:build_toolbar('refresh,add,edit,del')}
</div>
<table id="table" class="table table-striped table-bordered table-hover"
data-operate-edit="{:$auth->check('general/crontab/edit')}"
data-operate-del="{:$auth->check('general/crontab/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
... ...
<style type="text/css">
#schedulepicker {
padding-top:7px;
}
</style>
<form id="edit-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Content')}:</label>
<div class="col-xs-12 col-sm-10">
<textarea name="row[content]" id="conent" cols="30" style="width:100%;" rows="20" class="form-control" data-rule="required" readonly>{$row.content|htmlentities}</textarea>
</div>
</div>
<div class="form-group">
<label for="executetime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control datetimepicker" id="executetime" name="row[executetime]" value="{$row.executetime|datetime}" data-rule="{:__('End time')}:required;match(gte, row[begintime], datetime)" size="6" disabled />
</div>
</div>
<div class="form-group">
<label for="completetime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control datetimepicker" id="completetime" name="row[completetime]" value="{$row.completetime|datetime}" data-rule="{:__('End time')}:required;match(gte, row[begintime], datetime)" size="6" disabled />
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
<div style="padding-top:8px;">
{if $row['status']=='success'}<span class="label label-success">{:__('Success')}</span>{else/}<span class="label label-danger">{:__('Failure')}</span>{/if}
</div>
</div>
</div>
<div class="form-group hide layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="button" class="btn btn-success btn-embossed" onclick="parent.Layer.close(parent.Layer.getFrameIndex(window.name))">{:__('Close')}</button>
</div>
</div>
</form>
... ...
<div class="panel panel-default panel-intro">
<div class="panel-heading">
{:build_heading(null,FALSE)}
<ul class="nav nav-tabs" data-field="status">
<li class="active"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li>
{foreach name="statusList" item="vo"}
<li><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li>
{/foreach}
</ul>
</div>
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{:build_toolbar('refresh,del')}
</div>
<table id="table" class="table table-striped table-bordered table-hover"
data-operate-detail="{:$auth->check('general/crontab/detail')}"
data-operate-del="{:$auth->check('general/crontab/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
... ...
... ... @@ -6,6 +6,18 @@
<textarea id="c-content" class="form-control editor" rows="5" name="row[content]" cols="50"></textarea>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('会员权益')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea id="c-desc" class="form-control editor" rows="5" name="row[desc]" cols="50"></textarea>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('操作说明')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea id="c-explain" class="form-control editor" rows="5" name="row[explain]" cols="50"></textarea>
</div>
</div>
<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">
... ...
... ... @@ -6,6 +6,18 @@
<textarea id="c-content" class="form-control editor" rows="5" name="row[content]" cols="50">{$row.content|htmlentities}</textarea>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('会员权益')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea id="c-desc" class="form-control editor" rows="5" name="row[desc]" cols="50">{$row.desc|htmlentities}</textarea>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('操作说明')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea id="c-explain" class="form-control editor" rows="5" name="row[explain]" cols="50">{$row.explain|htmlentities}</textarea>
</div>
</div>
<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">
... ...
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Image')}:</label>
<div class="col-xs-12 col-sm-8">
<div class="input-group">
<input id="c-image" class="form-control" size="50" name="row[image]" type="text">
<div class="input-group-addon no-border no-padding">
<span><button type="button" id="plupload-image" class="btn btn-danger plupload" data-input-id="c-image" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp" data-multiple="false" data-preview-id="p-image"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-image" class="btn btn-primary fachoose" data-input-id="c-image" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
</div>
<span class="msg-box n-right" for="c-image"></span>
</div>
<ul class="row list-inline plupload-preview" id="p-image"></ul>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Aliimage')}:</label>
<div class="col-xs-12 col-sm-8">
<div class="input-group">
<input id="c-aliimage" class="form-control" size="50" name="row[aliimage]" type="text">
<div class="input-group-addon no-border no-padding">
<span><button type="button" id="plupload-aliimage" class="btn btn-danger plupload" data-input-id="c-aliimage" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp" data-multiple="false" data-preview-id="p-aliimage"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-aliimage" class="btn btn-primary fachoose" data-input-id="c-aliimage" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
</div>
<span class="msg-box n-right" for="c-aliimage"></span>
</div>
<ul class="row list-inline plupload-preview" id="p-aliimage"></ul>
</div>
</div>
<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 disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Image')}:</label>
<div class="col-xs-12 col-sm-8">
<div class="input-group">
<input id="c-image" class="form-control" size="50" name="row[image]" type="text" value="{$row.image|htmlentities}">
<div class="input-group-addon no-border no-padding">
<span><button type="button" id="plupload-image" class="btn btn-danger plupload" data-input-id="c-image" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp" data-multiple="false" data-preview-id="p-image"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-image" class="btn btn-primary fachoose" data-input-id="c-image" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
</div>
<span class="msg-box n-right" for="c-image"></span>
</div>
<ul class="row list-inline plupload-preview" id="p-image"></ul>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Aliimage')}:</label>
<div class="col-xs-12 col-sm-8">
<div class="input-group">
<input id="c-aliimage" class="form-control" size="50" name="row[aliimage]" type="text" value="{$row.aliimage|htmlentities}">
<div class="input-group-addon no-border no-padding">
<span><button type="button" id="plupload-aliimage" class="btn btn-danger plupload" data-input-id="c-aliimage" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp" data-multiple="false" data-preview-id="p-aliimage"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-aliimage" class="btn btn-primary fachoose" data-input-id="c-aliimage" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
</div>
<span class="msg-box n-right" for="c-aliimage"></span>
</div>
<ul class="row list-inline plupload-preview" id="p-aliimage"></ul>
</div>
</div>
<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 disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
<a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a>
<!--<a href="javascript:;" class="btn btn-success btn-add {:$auth->check('payimage/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>-->
<a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('payimage/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a>
<!--<a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('payimage/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>-->
<!--<a href="javascript:;" class="btn btn-danger btn-import {:$auth->check('payimage/import')?'':'hide'}" title="{:__('Import')}" id="btn-import-file" data-url="ajax/upload" data-mimetype="csv,xls,xlsx" data-multiple="false"><i class="fa fa-upload"></i> {:__('Import')}</a>-->
<!--<div class="dropdown btn-group {:$auth->check('payimage/multi')?'':'hide'}">-->
<!--<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 table-nowrap"
data-operate-edit="{:$auth->check('payimage/edit')}"
data-operate-del="{:$auth->check('payimage/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
... ...
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Day_num')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-day_num" class="form-control" name="row[day_num]" type="number">
</div>
</div>
<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 disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Day_num')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-day_num" class="form-control" name="row[day_num]" type="number" value="{$row.day_num|htmlentities}">
</div>
</div>
<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 disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
<a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a>
<!--<a href="javascript:;" class="btn btn-success btn-add {:$auth->check('vipdaynum/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>-->
<a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('vipdaynum/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a>
<!--<a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('vipdaynum/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>-->
<!--<a href="javascript:;" class="btn btn-danger btn-import {:$auth->check('vipdaynum/import')?'':'hide'}" title="{:__('Import')}" id="btn-import-file" data-url="ajax/upload" data-mimetype="csv,xls,xlsx" data-multiple="false"><i class="fa fa-upload"></i> {:__('Import')}</a>-->
<!--<div class="dropdown btn-group {:$auth->check('vipdaynum/multi')?'':'hide'}">-->
<!--<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 table-nowrap"
data-operate-edit="{:$auth->check('vipdaynum/edit')}"
data-operate-del="{:$auth->check('vipdaynum/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
... ...
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('User_id')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-user_id" data-rule="required" data-source="user/user/index" data-field="nickname" class="form-control selectpage" name="row[user_id]" type="text" value="">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Order_num')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-order_num" class="form-control" name="row[order_num]" type="text">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-type" class="form-control" name="row[type]" type="number">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Daynum')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-daynum" class="form-control" name="row[daynum]" type="number">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-status" class="form-control" name="row[status]" type="number" value="0">
</div>
</div>
<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 disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<!--<div class="form-group">-->
<!--<label class="control-label col-xs-12 col-sm-2">{:__('User_id')}:</label>-->
<!--<div class="col-xs-12 col-sm-8">-->
<!--<input id="c-user_id" data-rule="required" data-source="user/user/index" data-field="nickname" class="form-control selectpage" name="row[user_id]" type="text" value="{$row.user_id|htmlentities}">-->
<!--</div>-->
<!--</div>-->
<!--<div class="form-group">-->
<!--<label class="control-label col-xs-12 col-sm-2">{:__('Order_num')}:</label>-->
<!--<div class="col-xs-12 col-sm-8">-->
<!--<input id="c-order_num" class="form-control" name="row[order_num]" type="text" value="{$row.order_num|htmlentities}">-->
<!--</div>-->
<!--</div>-->
<!--<div class="form-group">-->
<!--<label class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label>-->
<!--<div class="col-xs-12 col-sm-8">-->
<!--<input id="c-type" class="form-control" name="row[type]" type="number" value="{$row.type|htmlentities}">-->
<!--</div>-->
<!--</div>-->
<!--<div class="form-group">-->
<!--<label class="control-label col-xs-12 col-sm-2">{:__('Daynum')}:</label>-->
<!--<div class="col-xs-12 col-sm-8">-->
<!--<input id="c-daynum" class="form-control" name="row[daynum]" type="number" value="{$row.daynum|htmlentities}">-->
<!--</div>-->
<!--</div>-->
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('审核状态')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['0'=>'待审核','1'=>'通过','2'=>'未通过'], $row['status'])}
</div>
</div>
<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 disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
<a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a>
<!--<a href="javascript:;" class="btn btn-success btn-add {:$auth->check('viporder/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>-->
<a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('viporder/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a>
<!--<a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('viporder/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>-->
<!--<a href="javascript:;" class="btn btn-danger btn-import {:$auth->check('viporder/import')?'':'hide'}" title="{:__('Import')}" id="btn-import-file" data-url="ajax/upload" data-mimetype="csv,xls,xlsx" data-multiple="false"><i class="fa fa-upload"></i> {:__('Import')}</a>-->
<!--<div class="dropdown btn-group {:$auth->check('viporder/multi')?'':'hide'}">-->
<!--<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 table-nowrap"
data-operate-edit="{:$auth->check('viporder/edit')}"
data-operate-del="{:$auth->check('viporder/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
... ...
... ... @@ -2,6 +2,7 @@
namespace app\api\controller;
use app\admin\controller\general\Attachment;
use app\common\controller\Api;
use app\common\model\Area;
use app\common\model\Version;
... ... @@ -47,75 +48,68 @@ class Common extends Api
*/
public function upload()
{
Config::set('default_return_type', 'json');
$config = get_addon_config('qiniu');
$file = $this->request->file('file');
if (empty($file)) {
$this->error(__('No file upload or server upload limit exceeded'));
if (!$file || !$file->isValid()) {
$this->error("请上传有效的文件");
}
$fileInfo = $file->getInfo();
//判断是否已经存在附件
$sha1 = $file->hash();
$upload = Config::get('upload');
$filePath = $file->getRealPath() ?: $file->getPathname();
preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches);
preg_match('/(\d+)(\w+)/', $config['maxsize'], $matches);
$type = strtolower($matches[2]);
$typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];
$size = (int)$upload['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0);
$fileInfo = $file->getInfo();
$size = (int)$config['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0);
$suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
$suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file';
$suffix = $suffix ? $suffix : 'file';
$md5 = md5_file($filePath);
$search = ['$(year)', '$(mon)', '$(day)', '$(etag)', '$(ext)'];
$replace = [date("Y"), date("m"), date("d"), $md5, '.' . $suffix];
$object = ltrim(str_replace($search, $replace, $config['savekey']), '/');
$mimetypeArr = explode(',', strtolower($upload['mimetype']));
$mimetypeArr = explode(',', strtolower($config['mimetype']));
$typeArr = explode('/', $fileInfo['type']);
//禁止上传PHP和HTML文件
if (in_array($fileInfo['type'], ['text/x-php', 'text/html']) || in_array($suffix, ['php', 'html', 'htm'])) {
$this->error(__('Uploaded file format is limited'));
//检查文件大小
if (!$file->checkSize($size)) {
$this->error("起过最大可上传文件限制");
}
//验证文件后缀
if ($upload['mimetype'] !== '*' &&
if ($config['mimetype'] !== '*' &&
(
!in_array($suffix, $mimetypeArr)
|| (stripos($typeArr[0] . '/', $upload['mimetype']) !== false && (!in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr)))
|| (stripos($typeArr[0] . '/', $config['mimetype']) !== false && (!in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr)))
)
) {
$this->error(__('Uploaded file format is limited'));
$this->error(__('上传格式限制'));
}
//验证是否为图片文件
$imagewidth = $imageheight = 0;
if (in_array($fileInfo['type'], ['image/gif', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/png', 'image/webp']) || in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'webp'])) {
$imgInfo = getimagesize($fileInfo['tmp_name']);
if (!$imgInfo || !isset($imgInfo[0]) || !isset($imgInfo[1])) {
$this->error(__('Uploaded file is not a valid image'));
}
$imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth;
$imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
}
$replaceArr = [
'{year}' => date("Y"),
'{mon}' => date("m"),
'{day}' => date("d"),
'{hour}' => date("H"),
'{min}' => date("i"),
'{sec}' => date("s"),
'{random}' => Random::alnum(16),
'{random32}' => Random::alnum(32),
'{filename}' => $suffix ? substr($fileInfo['name'], 0, strripos($fileInfo['name'], '.')) : $fileInfo['name'],
'{suffix}' => $suffix,
'{.suffix}' => $suffix ? '.' . $suffix : '',
'{filemd5}' => md5_file($fileInfo['tmp_name']),
];
$savekey = $upload['savekey'];
$savekey = str_replace(array_keys($replaceArr), array_values($replaceArr), $savekey);
$savekey = '/' . $object;
$uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1);
$fileName = substr($savekey, strripos($savekey, '/') + 1);
//
$splInfo = $file->validate(['size' => $size])->move(ROOT_PATH . '/public' . $uploadDir, $fileName);
//先上传到本地
$splInfo = $file->move(ROOT_PATH . '/public' . $uploadDir, $fileName);
if ($splInfo) {
$extparam = $this->request->post();
$filePath = $splInfo->getRealPath() ?: $splInfo->getPathname();
$sha1 = sha1_file($filePath);
$imagewidth = $imageheight = 0;
if (in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf'])) {
$imgInfo = getimagesize($splInfo->getPathname());
$imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth;
$imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
}
$params = array(
'admin_id' => 0,
'user_id' => (int)$this->auth->id,
'admin_id' => session('admin.id'),
// 'user_id' => $this->auth->id,
'filesize' => $fileInfo['size'],
'imagewidth' => $imagewidth,
'imageheight' => $imageheight,
... ... @@ -126,17 +120,45 @@ class Common extends Api
'uploadtime' => time(),
'storage' => 'local',
'sha1' => $sha1,
'extparam' => json_encode($extparam),
);
$attachment = model("attachment");
$attachment->data(array_filter($params));
$attachment->save();
\think\Hook::listen("upload_after", $attachment);
$this->success(__('Upload successful'), [
'url' => $uploadDir . $splInfo->getSaveName()
$attachment = \app\common\model\Attachment::create(array_filter($params), true);
$policy = array(
'saveKey' => ltrim($savekey, '/'),
);
$auth = new \addons\qiniu\library\Auth($config['app_key'], $config['secret_key']);
$token = $auth->uploadToken($config['bucket'], null, $config['expire'], $policy);
$multipart = [
['name' => 'token', 'contents' => $token],
[
'name' => 'file',
'contents' => fopen($filePath, 'r'),
'filename' => $fileName,
]
];
try {
$client = new \GuzzleHttp\Client();
$res = $client->request('POST', $config['uploadurl'], [
'multipart' => $multipart
]);
$code = $res->getStatusCode();
//成功不做任何操作
} catch (\GuzzleHttp\Exception\ClientException $e) {
$attachment->delete();
unlink($filePath);
$this->error("上传失败");
}
$url = '/' . $object;
//上传成功后将存储变更为qiniu
$attachment->storage = 'qiniu';
$attachment->save();
$this->success("上传成功", $url);
} else {
// 上传失败获取错误信息
$this->error($file->getError());
$this->error('上传失败');
}
return;
}
}
... ...
... ... @@ -10,7 +10,10 @@ namespace app\api\controller;
use app\common\controller\Api;
use Qiniu\Storage\UploadManager;
use think\Db;
use Qiniu\Auth;
/**
... ... @@ -30,13 +33,14 @@ class Create extends Api
* @ApiRoute (/api/create/publish_folder)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="id", type="inter", required=true, description="父级文件夹id")
* @ApiParams (name="id", type="inter", required=true, description="父级文件夹id首页为0")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
}
]
}
... ... @@ -74,4 +78,698 @@ class Create extends Api
}
}
/**
* @ApiTitle (发布图片)
* @ApiSummary (发布图片)
* @ApiMethod (POST)
* @ApiRoute (/api/create/publish_pic)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="images", type="string", required=true, description="图片内容")
* @ApiParams (name="folder_id", type="inter", required=true, description="存储位置id 首页为0")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
}
})
*/
public function publish_pic()
{
$user_id = $this->auth->id;
$user = Db::name('user')->where('id',$user_id)->field('id,identity,audit')->find();
//判断用户身份是否审核通过
if($user['audit'] != 1){
$this->error('身份身份通过才可发布!');
}
//判断用户身份是否有发布的权限
if($user['identity'] == 1){
$this->error('您的权限不足');
}
$folder_id = $this->request->param('folder_id');
$images = $this->request->param('images');
if(empty($images)){
$this->error('缺少必要参数');
}
//判断图片大小
$image = explode(',',$images);
$count = count($image);
if($count > 9){
$this->error('最多上传9张图片');
}
//添加发布的文件数据表
$res['user_id'] = $user_id;
$res['type'] = 2;
$res['name'] = date('YmdHis');
$res['folder_id'] = $folder_id;
$res['images'] = $images;
$res['createtime'] = time();
$res['updatetime'] = time();
$data = Db::name('savemes')->insertGetId($res);
if(empty($data)){
$this->error('发布图片失败');
}else{
$this->success('发布图片成功');
}
}
/**
* @ApiTitle (发布视频)
* @ApiSummary (发布视频)
* @ApiMethod (POST)
* @ApiRoute (/api/create/publish_video)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="video", type="string", required=true, description="视频内容")
* @ApiParams (name="folder_id", type="inter", required=true, description="存储位置id 首页为0")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
}
})
*/
public function publish_video()
{
$user_id = $this->auth->id;
$user = Db::name('user')->where('id',$user_id)->field('id,identity,audit')->find();
//判断用户身份是否审核通过
if($user['audit'] != 1){
$this->error('身份身份通过才可发布!');
}
//判断用户身份是否有发布的权限
if($user['identity'] == 1){
$this->error('您的权限不足');
}
$folder_id = $this->request->param('folder_id');
$video = $this->request->param('video');
if(empty($video)){
$this->error('缺少必要参数');
}
//添加发布的文件数据表
$res['user_id'] = $user_id;
$res['type'] = 3;
$res['name'] = date('YmdHis');
$res['folder_id'] = $folder_id;
$res['video'] = $video;
$res['createtime'] = time();
$res['updatetime'] = time();
$data = Db::name('savemes')->insertGetId($res);
if(empty($data)){
$this->error('发布视频失败');
}else{
$this->success('发布视频成功');
}
}
/**
* @ApiTitle (发布笔记)
* @ApiSummary (发布笔记)
* @ApiMethod (POST)
* @ApiRoute (/api/create/publish_note)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="content", type="string", required=true, description="笔记内容")
* @ApiParams (name="folder_id", type="inter", required=true, description="存储位置id 首页为0")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
}
})
*/
public function publish_note()
{
$user_id = $this->auth->id;
$user = Db::name('user')->where('id',$user_id)->field('id,identity,audit')->find();
//判断用户身份是否审核通过
if($user['audit'] != 1){
$this->error('身份身份通过才可发布!');
}
//判断用户身份是否有发布的权限
if($user['identity'] == 1){
$this->error('您的权限不足');
}
$folder_id = $this->request->param('folder_id');
$content = $_POST['content'];
if(empty($content)){
$this->error('缺少必要参数');
}
//添加发布的文件数据表
$res['user_id'] = $user_id;
$res['type'] = 1;
$res['name'] = date('YmdHis');
$res['folder_id'] = $folder_id;
$res['content'] = $content;
$res['createtime'] = time();
$res['updatetime'] = time();
$data = Db::name('savemes')->insertGetId($res);
if(empty($data)){
$this->error('发布笔记失败');
}else{
$this->success('发布笔记成功');
}
}
/**
* @ApiTitle (文佳列表)
* @ApiSummary (上传列表)
* @ApiMethod (POST)
* @ApiRoute (/api/create/publish_list)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
"id": //id,
"user_id": //用户id,
"type": //类型1笔记2图片3视频,
"folder_id": //所在位置id,
"name": //名称,
"images": //图片,
"video": //视频地址,
"content": //内容,
"is_open": //是否公开1公开2私密,
"is_up": //是否上架1上架2下架,
"uptime": //下架时间,
"createtime": //创建时间,
"updatetime": //修改时间,
"video_image": //视频封面图
}
]
}
})
*/
public function publish_list()
{
$qiniu = get_addon_config('qiniu')['cdnurl'];
$user_id = $this->auth->id;
$data = Db::name('savemes')
->where('user_id',$user_id)
->order('type asc')
->select();
foreach ($data as &$v){
if($v['type'] == 3){
$v['video'] = $qiniu.$v['video'];
// 获取视频第一帧图片
$video_info = json_decode(file_get_contents($v['video'] . '?avinfo'), true);
$v['video_image'] = $this->get_video_first_image($v['video'], $video_info);
}elseif ($v['type'] == 2){
$v['images'] = explode(',',$v['images']);
foreach ($v['images'] as &$val){
$val = $qiniu.$val;
}
}
}
$this->success('success',$data);
}
public function get_video_first_image($video_url,$video_info){
if(empty($video_info['streams'][0]['width'])) {
$width = $video_info['streams'][1]['width'];
$height = $video_info['streams'][1]['height'];
} else {
$width = $video_info['streams'][0]['width'];
$height = $video_info['streams'][0]['height'];
}
return $video_url.'?vframe/jpg/offset/1/w/'.$width.'/h/'.$height;
}
/**
* @ApiTitle (笔记详情)
* @ApiSummary (笔记详情)
* @ApiMethod (POST)
* @ApiRoute (/api/create/note_detail)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="id", type="inter", required=true, description="笔记id")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
"id": //id,
"user_id": //用户id,
"folder_id": //存储位置0为首页,
"name": //名称,
"content": //内容,
"is_open": //是否公开1公开2私密,
"is_up": //是否上架1上架2下架,
"uptime": //下架时间,
"collect_num": //收藏数量,
"createtime": "//创建时间",
"is_mine"://是否为本人1是2否
"is_collect"://是否收藏过1是2否
}
})
*/
public function note_detail()
{
$user_id = $this->auth->id;
$id = $this->request->param('id');
if(empty($id)){
$this->error('缺少必要参数');
}
$data = Db::name('savemes')->field('updatetime,images,video,type',true)->where('type',1)->where('id',$id)->find();
if(empty($data)){
$this->error('参数有误');
}
//是否本人打开
if($data['user_id'] == $user_id){
$data['is_mine'] = 1;
}else{
$data['is_mine'] = 2;
}
//是否收藏过
$collect = Db::name('collect')->where('user_id',$user_id)->where('savemes_id',$id)->find();
if(empty($collect)){
$data['is_collect'] = 2;
}else{
$data['is_collect'] = 1;
}
$data['createtime'] = date('Y-m-d H:i:s',$data['createtime']);
$this->success('success',$data);
}
/**
* @ApiTitle (收藏/取消收藏)
* @ApiSummary (收藏/取消收藏)
* @ApiMethod (POST)
* @ApiRoute (/api/create/collect)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="id", type="inter", required=true, description="文件id")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
}
})
*/
public function collect()
{
$user_id = $this->auth->id;
$id = $this->request->param('id');
if(empty($id)){
$this->error('缺少必要参数');
}
$data = Db::name('collect')->where('user_id',$user_id)->where('savemes_id',$id)->find();
if(empty($data)){
$res['user_id'] = $user_id;
$res['savemes_id'] = $id;
$res['createtime'] = time();
$res['updatetime'] = time();
$info = Db::name('collect')->insertGetId($res);
if(empty($info)){
$this->error('收藏失败');
}else{
$this->success('收藏成功');
}
}else{
$info = Db::name('collect')->where('user_id',$user_id)->where('savemes_id',$id)->delete();
if(empty($info)){
$this->error('取消收藏失败');
}else{
$this->success('取消收藏成功');
}
}
}
//批量操作
/**
* @ApiTitle (文件删除)
* @ApiSummary (文件删除)
* @ApiMethod (POST)
* @ApiRoute (/api/create/del)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="ids", type="inter", required=true, description="文件ids字符串")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
}
})
*/
public function del()
{
$user_id = $this->auth->id;
$ids = $this->request->param('ids');
if(empty($ids)){
$this->error('缺少必要参数');
}
$arr_ids = explode(',',$ids);
//删除文件
Db::startTrans();
try{
Db::name('savemes')->whereIn('id',$arr_ids)->delete();
Db::name('collect')->whereIn('savemes_id',$arr_ids)->delete();
Db::name('rotor')->whereIn('savemes_id',$arr_ids)->delete();
Db::commit();
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
}
$this->success('删除成功');
}
/**
* @ApiTitle (设为公开)
* @ApiSummary (设为公开)
* @ApiMethod (POST)
* @ApiRoute (/api/create/set_gong)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="ids", type="inter", required=true, description="文件ids字符串")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
}
})
*/
public function set_gong()
{
$user_id = $this->auth->id;
$ids = $this->request->param('ids');
if(empty($ids)){
$this->error('缺少必要参数');
}
$arr_ids = explode(',',$ids);
//设置为公开
Db::startTrans();
try{
Db::name('savemes')->whereIn('id',$arr_ids)->update(['is_open'=>1]);
Db::name('rotor')->whereIn('savemes_id',$arr_ids)->update(['is_open'=>1]);
Db::commit();
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
}
$this->success('设置成功');
}
/**
* @ApiTitle (设为私密)
* @ApiSummary (设为私密)
* @ApiMethod (POST)
* @ApiRoute (/api/create/set_si)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="ids", type="inter", required=true, description="文件ids字符串")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
}
})
*/
public function set_si()
{
$user_id = $this->auth->id;
$ids = $this->request->param('ids');
if(empty($ids)){
$this->error('缺少必要参数');
}
$arr_ids = explode(',',$ids);
//设置为公开
Db::startTrans();
try{
Db::name('savemes')->whereIn('id',$arr_ids)->update(['is_open'=>2]);
Db::name('rotor')->whereIn('savemes_id',$arr_ids)->update(['is_open'=>2]);
Db::commit();
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
}
$this->success('设置成功');
}
/**
* @ApiTitle (全部上架)
* @ApiSummary (全部上架)
* @ApiMethod (POST)
* @ApiRoute (/api/create/all_up)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="ids", type="inter", required=true, description="文件ids字符串")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
}
})
*/
public function all_up()
{
$user_id = $this->auth->id;
$ids = $this->request->param('ids');
if(empty($ids)){
$this->error('缺少必要参数');
}
$arr_ids = explode(',',$ids);
//全部上架
Db::startTrans();
try{
Db::name('savemes')->whereIn('id',$arr_ids)->update(['is_up'=>1,'uptime'=>0]);
Db::name('rotor')->whereIn('savemes_id',$arr_ids)->update(['is_up'=>1]);
Db::commit();
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
}
$this->success('成功');
}
/**
* @ApiTitle (全部下架)
* @ApiSummary (全部下架)
* @ApiMethod (POST)
* @ApiRoute (/api/create/all_down)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="ids", type="inter", required=true, description="文件ids字符串")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
}
})
*/
public function all_down()
{
$user_id = $this->auth->id;
$ids = $this->request->param('ids');
if(empty($ids)){
$this->error('缺少必要参数');
}
$arr_ids = explode(',',$ids);
//全部上架
Db::startTrans();
try{
Db::name('savemes')->whereIn('id',$arr_ids)->update(['is_up'=>2,'uptime'=>time()]);
Db::name('rotor')->whereIn('savemes_id',$arr_ids)->update(['is_up'=>2]);
Db::commit();
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
}
$this->success('成功');
}
/**
* @ApiTitle (移动到)
* @ApiSummary (移动到)
* @ApiMethod (POST)
* @ApiRoute (/api/create/all_move)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="ids", type="inter", required=true, description="文件ids字符串")
* @ApiParams (name="move_id", type="inter", required=true, description="移动的目标id首页为0")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
}
})
*/
public function all_move()
{
$user_id = $this->auth->id;
$ids = $this->request->param('ids');
if(empty($ids)){
$this->error('缺少必要参数');
}
$arr_ids = explode(',',$ids);
$move_id = $this->request->param('move_id');
if(empty($move_id)){
$this->error('缺少必要参数');
}
//全部上架
$data = Db::name('savemes')->whereIn('id',$arr_ids)->update(['folder_id'=>$move_id]);
if(empty($data)){
$this->error('失败');
}else{
$this->success('成功');
}
}
/**
* @ApiTitle (下载)
* @ApiSummary (下载)
* @ApiMethod (POST)
* @ApiRoute (/api/create/download)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="ids", type="inter", required=true, description="文件ids字符串")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
"info"://下载的文件
}
})
*/
public function download()
{
$qiniu = get_addon_config('qiniu')['cdnurl'];
$user_id = $this->auth->id;
$ids = $this->request->param('ids');
if(empty($ids)){
$this->error('缺少必要参数');
}
$arr_ids = explode(',',$ids);
$data = Db::name('savemes')->field('id,type,images,video')->whereIn('id',$arr_ids)->select();
$arr = [];
foreach ($data as &$v){
//判断是否有笔记
if($v['type'] == 1){
$this->error('笔记不能下载');
}
if($v['type'] == 2){
$v['video'] = '';
$v['images'] = explode(',',$v['images']);
foreach ($v['images'] as &$val){
$qiuniu_url = $qiniu.$val;
$a = file_get_contents($qiuniu_url);
$path = './uploads/'.explode('/',$val)[2].'/';
if(!file_exists($path)) {
mkdir($path,0777,true);
}
file_put_contents('.'.$val,$a);
$val = request()->domain().$val;
array_push($arr,$val);
}
}
if($v['type'] == 3){
$v['images'] = '';
$qiuniu_url = $qiniu.$v['video'];
$a = file_get_contents($qiuniu_url);
$path = './uploads/'.explode('/',$v['video'])[2].'/';
if(!file_exists($path)) {
mkdir($path,0777,true);
}
file_put_contents('.'.$v['video'],$a);
$v['video'] = request()->domain().$v['video'];
array_push($arr,$v['video']);
}
}
$this->success('success',['info'=>$arr]);
}
/**
* @ApiTitle (重命名)
* @ApiSummary (重命名)
* @ApiMethod (POST)
* @ApiRoute (/api/create/rename)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="id", type="inter", required=true, description="文件id")
* @ApiParams (name="type", type="inter", required=true, description="类型1文件2文件夹")
* @ApiParams (name="name", type="string", required=true, description="修改后的名称")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
}
})
*/
public function rename()
{
$user_id = $this->auth->id;
$id = $this->request->param('id');
$name = $this->request->param('name');
$type = $this->request->param('type');
if(empty($id) || empty($name) || empty($type)){
$this->error('缺少必要参数');
}
if($type == 1){
$data = Db::name('savemes')->where('id',$id)->find();
if($data['user_id'] != $user_id){
$this->error('没有权限重命名');
}
$res = Db::name('savemes')->where('id',$id)->update(['name'=>$name]);
}elseif ($type == 2){
$data = Db::name('folder')->where('id',$id)->find();
if($data['user_id'] != $user_id){
$this->error('没有权限重命名');
}
$res = Db::name('folder')->where('id',$id)->update(['folder_name'=>$name]);
}
if(empty($res)){
$this->error('重命名失败');
}else{
$this->success('重命名成功');
}
}
}
\ No newline at end of file
... ...
... ... @@ -13,7 +13,29 @@ class Index extends Api
protected $noNeedLogin = ['*'];
protected $noNeedRight = ['*'];
/**
* @ApiTitle (APP启动页)
* @ApiSummary (APP启动页)
* @ApiMethod (POST)
* @ApiRoute (/api/index/flash)
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
"image": //启动页图片,
}
})
*/
public function flash()
{
$qiniu = get_addon_config('qiniu')['cdnurl'];
$data = Db::name('flash')->where('id',1)->field('image')->find();
$data['image'] = $qiniu.$data['image'];
$this->success('success',$data);
}
/**
... ... @@ -35,6 +57,7 @@ class Index extends Api
"user_id": //用户id,
"folder_name": //文件夹名称,
"pid": //父级文件夹id,
"is_open": //是否公开1公开2私密
"is_up": //1上架2下架
"createtime": //创建时间,
"updatetime": //修改时间
... ...
... ... @@ -358,8 +358,8 @@ class Login extends Api
}
/**
* @ApiTitle (用户协议)
* @ApiSummary (用户协议)
* @ApiTitle (文案)
* @ApiSummary (文案)
* @ApiMethod (POST)
* @ApiRoute (/api/login/official)
*
... ... @@ -369,13 +369,15 @@ class Login extends Api
"time": "1553839125",
"data": {
"id"://id
"content"://内容
"content"://用户协议
"desc"://会员权益
"explain"://操作说明
}
})
*/
public function official()
{
$data = Db::name('official')->where('id',1)->field('id,content')->find();
$data = Db::name('official')->where('id',1)->field('id,content,desc,explain')->find();
$this->success('success',$data);
}
... ...
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2020/7/10
* Time: 17:32
*/
namespace app\api\controller;
use app\common\controller\Api;
use think\Db;
/**
* 开通会员
*/
class Order extends Api
{
protected $noNeedLogin = [''];
protected $noNeedRight = ['*'];
/**
* @ApiTitle (收款码图片)
* @ApiSummary (收款码图片)
* @ApiMethod (POST)
* @ApiRoute (/api/order/payimage)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="type", type="inter", required=true, description="类型1微信2支付")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
"image": //图片地址
}
]
}
})
*/
public function payimage()
{
$qiniu = get_addon_config('qiniu')['cdnurl'];
$user_id = $this->auth->id;
$type = $this->request->param('type');
if(empty($type)){
$this->error('缺少必要参数');
}
$data = Db::name('payimage')->where('id',1)->find();
if($type == 1){
$this->success('success',['image'=>$qiniu.$data['image']]);
}else{
$this->success('success',['image'=>$qiniu.$data['aliimage']]);
}
}
/**
* @ApiTitle (开通会员订单)
* @ApiSummary (开通会员订单)
* @ApiMethod (POST)
* @ApiRoute (/api/order/index)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="type", type="inter", required=true, description="支付方式1微信2支付宝")
* @ApiParams (name="order_num", type="inter", required=true, description="订单后四位")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
"order_id"://订单id
}
]
}
})
*/
public function index()
{
$user_id = $this->auth->id;
$type = $this->request->param('type');
$order_num = $this->request->param('order_num');
if(empty($type) || empty($order_num)){
$this->error('缺少必要参数');
}
$vipdaynum = Db::name('vipdaynum')->where('id',1)->value('day_num');
$res['user_id'] = $user_id;
$res['order_num'] = $order_num;
$res['type'] = $type;
$res['daynum'] = $vipdaynum;
$res['createtime'] = time();
$res['updatetime'] = time();
$data = Db::name('viporder')->insertGetId($res);
if(empty($data)){
$this->error('开通失败');
}else{
$this->success('开通成功',['oder_id'=>$data]);
}
}
/**
* @ApiTitle (我的订阅)
* @ApiSummary (我的订阅)
* @ApiMethod (POST)
* @ApiRoute (/api/order/myattention)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
*
* @ApiParams (name="page", type="inter", required=false, description="当前页(默认1)")
* @ApiParams (name="pageNum", type="inter", required=false, description="每页显示数据个数(默认10)")
*
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
"id"://订阅ID
"user_id": //用户id,
"to_user_id"://订阅的用户id
"createtime"://创建时间
"username"://用户名
"avatar"://头像
"createtime"://创建时间
"updatetime"://修改时间
}
})
*/
public function myattention()
{
$qiniu = get_addon_config('qiniu')['cdnurl'];
$user_id = $this->auth->id;
$page = $this->request->param('page', 1, 'intval');
$pageNum = $this->request->param('pageNum', 10, 'intval');
$data = Db::name('subscribe')
->alias('a')
->join('user b','a.to_user_id = b.id')
->where('a.user_id',$user_id)
->field('a.*,b.username,b.avatar')
->order('a.id desc')
->page($page,$pageNum)
->select();
foreach ($data as &$v){
$v['avatar'] = $qiniu.$v['avatar'];
}
$this->success('success',$data);
}
/**
* @ApiTitle (订阅/取消订阅)
* @ApiSummary (订阅/取消订阅)
* @ApiMethod (POST)
* @ApiRoute (/api/order/ding)
*
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
*
* @ApiParams (name="to_user_id", type="inter", required=true, description="订阅人id")
*
* @ApiReturn({
"code": 1,
"msg": "成功",
"time": "1571492001",
"data": {
}
})
*/
public function ding()
{
$user_id = $this->auth->id;
$to_user_id = $this->request->param('to_user_id');
if(empty($to_user_id)){
$this->error('缺少必要参数');
}
$data = Db::name('subscribe')->where('user_id',$user_id)->where('to_user_id',$to_user_id)->find();
if(empty($data)){
$res['user_id'] = $user_id;
$res['to_user_id'] = $to_user_id;
$res['createtime'] = time();
$res['updatetime'] = time();
$arr = Db::name('subscribe')->insertGetId($res);
if(empty($arr)){
$this->error('订阅失败');
}else{
$this->success('订阅成功');
}
}else{
$arr = Db::name('subscribe')->where('user_id',$user_id)->where('to_user_id',$to_user_id)->delete();
if(empty($arr)){
$this->error('取消订阅失败');
}else{
$this->success('取消订阅成功');
}
}
}
}
\ No newline at end of file
... ...
... ... @@ -317,4 +317,7 @@ class User extends Api
$this->error($this->auth->getError());
}
}
}
... ...
... ... @@ -24,7 +24,8 @@
"phpmailer/phpmailer": "~6.0.6",
"karsonzhang/fastadmin-addons": "~1.1.9",
"overtrue/pinyin": "~3.0",
"phpoffice/phpspreadsheet": "^1.2"
"phpoffice/phpspreadsheet": "^1.2",
"qiniu/php-sdk": "^7.2"
},
"config": {
"preferred-install": "dist"
... ...