正在显示
61 个修改的文件
包含
3418 行增加
和
61 行删除
addons/crontab/Crontab.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\crontab; | ||
4 | + | ||
5 | +use app\common\library\Menu; | ||
6 | +use think\Addons; | ||
7 | + | ||
8 | +/** | ||
9 | + * 定时任务 | ||
10 | + */ | ||
11 | +class Crontab extends Addons | ||
12 | +{ | ||
13 | + | ||
14 | + /** | ||
15 | + * 插件安装方法 | ||
16 | + * @return bool | ||
17 | + */ | ||
18 | + public function install() | ||
19 | + { | ||
20 | + $menu = [ | ||
21 | + [ | ||
22 | + 'name' => 'general/crontab', | ||
23 | + 'title' => '定时任务', | ||
24 | + 'icon' => 'fa fa-tasks', | ||
25 | + 'remark' => '类似于Linux的Crontab定时任务,可以按照设定的时间进行任务的执行,目前支持三种任务:请求URL、执行SQL、执行Shell', | ||
26 | + 'sublist' => [ | ||
27 | + ['name' => 'general/crontab/index', 'title' => '查看'], | ||
28 | + ['name' => 'general/crontab/add', 'title' => '添加'], | ||
29 | + ['name' => 'general/crontab/edit', 'title' => '编辑 '], | ||
30 | + ['name' => 'general/crontab/del', 'title' => '删除'], | ||
31 | + ['name' => 'general/crontab/multi', 'title' => '批量更新'], | ||
32 | + ] | ||
33 | + ] | ||
34 | + ]; | ||
35 | + Menu::create($menu, 'general'); | ||
36 | + return true; | ||
37 | + } | ||
38 | + | ||
39 | + /** | ||
40 | + * 插件卸载方法 | ||
41 | + * @return bool | ||
42 | + */ | ||
43 | + public function uninstall() | ||
44 | + { | ||
45 | + Menu::delete('general/crontab'); | ||
46 | + return true; | ||
47 | + } | ||
48 | + | ||
49 | + /** | ||
50 | + * 插件启用方法 | ||
51 | + */ | ||
52 | + public function enable() | ||
53 | + { | ||
54 | + Menu::enable('general/crontab'); | ||
55 | + } | ||
56 | + | ||
57 | + /** | ||
58 | + * 插件禁用方法 | ||
59 | + */ | ||
60 | + public function disable() | ||
61 | + { | ||
62 | + Menu::disable('general/crontab'); | ||
63 | + } | ||
64 | + | ||
65 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\controller\general; | ||
4 | + | ||
5 | +use app\common\controller\Backend; | ||
6 | +use Cron\CronExpression; | ||
7 | + | ||
8 | +/** | ||
9 | + * 定时任务 | ||
10 | + * | ||
11 | + * @icon fa fa-tasks | ||
12 | + * @remark 类似于Linux的Crontab定时任务,可以按照设定的时间进行任务的执行 | ||
13 | + */ | ||
14 | +class Crontab extends Backend | ||
15 | +{ | ||
16 | + | ||
17 | + protected $model = null; | ||
18 | + protected $noNeedRight = ['check_schedule', 'get_schedule_future']; | ||
19 | + | ||
20 | + public function _initialize() | ||
21 | + { | ||
22 | + parent::_initialize(); | ||
23 | + $this->model = model('Crontab'); | ||
24 | + $this->view->assign('typeList', \app\admin\model\Crontab::getTypeList()); | ||
25 | + $this->assignconfig('typeList', \app\admin\model\Crontab::getTypeList()); | ||
26 | + } | ||
27 | + | ||
28 | + /** | ||
29 | + * 查看 | ||
30 | + */ | ||
31 | + public function index() | ||
32 | + { | ||
33 | + if ($this->request->isAjax()) { | ||
34 | + list($where, $sort, $order, $offset, $limit) = $this->buildparams(); | ||
35 | + $total = $this->model | ||
36 | + ->where($where) | ||
37 | + ->order($sort, $order) | ||
38 | + ->count(); | ||
39 | + | ||
40 | + $list = $this->model | ||
41 | + ->where($where) | ||
42 | + ->order($sort, $order) | ||
43 | + ->limit($offset, $limit) | ||
44 | + ->select(); | ||
45 | + $time = time(); | ||
46 | + foreach ($list as $k => &$v) { | ||
47 | + $cron = CronExpression::factory($v['schedule']); | ||
48 | + $v['nexttime'] = $time > $v['endtime'] ? __('None') : $cron->getNextRunDate()->getTimestamp(); | ||
49 | + } | ||
50 | + $result = array("total" => $total, "rows" => $list); | ||
51 | + | ||
52 | + return json($result); | ||
53 | + } | ||
54 | + return $this->view->fetch(); | ||
55 | + } | ||
56 | + | ||
57 | + /** | ||
58 | + * 判断Crontab格式是否正确 | ||
59 | + * @internal | ||
60 | + */ | ||
61 | + public function check_schedule() | ||
62 | + { | ||
63 | + $row = $this->request->post("row/a"); | ||
64 | + $schedule = isset($row['schedule']) ? $row['schedule'] : ''; | ||
65 | + if (CronExpression::isValidExpression($schedule)) { | ||
66 | + $this->success(); | ||
67 | + } else { | ||
68 | + $this->error(__('Crontab format invalid')); | ||
69 | + } | ||
70 | + } | ||
71 | + | ||
72 | + /** | ||
73 | + * 根据Crontab表达式读取未来七次的时间 | ||
74 | + * @internal | ||
75 | + */ | ||
76 | + public function get_schedule_future() | ||
77 | + { | ||
78 | + $time = []; | ||
79 | + $schedule = $this->request->post('schedule'); | ||
80 | + $days = (int)$this->request->post('days'); | ||
81 | + try { | ||
82 | + $cron = CronExpression::factory($schedule); | ||
83 | + for ($i = 0; $i < $days; $i++) { | ||
84 | + $time[] = $cron->getNextRunDate(null, $i)->format('Y-m-d H:i:s'); | ||
85 | + } | ||
86 | + } catch (\Exception $e) { | ||
87 | + | ||
88 | + } | ||
89 | + | ||
90 | + $this->success("", null, ['futuretime' => $time]); | ||
91 | + } | ||
92 | + | ||
93 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\controller\general; | ||
4 | + | ||
5 | +use app\common\controller\Backend; | ||
6 | + | ||
7 | +/** | ||
8 | + * 定时任务 | ||
9 | + * | ||
10 | + * @icon fa fa-tasks | ||
11 | + * @remark 类似于Linux的Crontab定时任务,可以按照设定的时间进行任务的执行 | ||
12 | + */ | ||
13 | +class CrontabLog extends Backend | ||
14 | +{ | ||
15 | + | ||
16 | + protected $model = null; | ||
17 | + | ||
18 | + public function _initialize() | ||
19 | + { | ||
20 | + parent::_initialize(); | ||
21 | + $this->model = model('CrontabLog'); | ||
22 | + $this->view->assign('statusList', $this->model->getStatusList()); | ||
23 | + $this->assignconfig('statusList', $this->model->getStatusList()); | ||
24 | + } | ||
25 | + | ||
26 | + /** | ||
27 | + * 查看 | ||
28 | + */ | ||
29 | + public function index() | ||
30 | + { | ||
31 | + if ($this->request->isAjax()) { | ||
32 | + list($where, $sort, $order, $offset, $limit) = $this->buildparams(); | ||
33 | + $total = $this->model | ||
34 | + ->where($where) | ||
35 | + ->order($sort, $order) | ||
36 | + ->count(); | ||
37 | + | ||
38 | + $list = $this->model | ||
39 | + ->where($where) | ||
40 | + ->order($sort, $order) | ||
41 | + ->limit($offset, $limit) | ||
42 | + ->select(); | ||
43 | + $list = collection($list)->toArray(); | ||
44 | + $result = array("total" => $total, "rows" => $list); | ||
45 | + | ||
46 | + return json($result); | ||
47 | + } | ||
48 | + return $this->view->fetch(); | ||
49 | + } | ||
50 | + | ||
51 | + public function detail($ids = null) | ||
52 | + { | ||
53 | + $row = $this->model->get($ids); | ||
54 | + if (!$row) { | ||
55 | + $this->error(__('No Results were found')); | ||
56 | + } | ||
57 | + $this->view->assign("row", $row); | ||
58 | + return $this->view->fetch(); | ||
59 | + } | ||
60 | + | ||
61 | +} |
1 | +<?php | ||
2 | + | ||
3 | +return [ | ||
4 | + 'Title' => '任务标题', | ||
5 | + 'Maximums' => '最多执行', | ||
6 | + 'Sleep' => '延迟秒数', | ||
7 | + 'Schedule' => '执行周期', | ||
8 | + 'Executes' => '执行次数', | ||
9 | + 'Completed' => '已完成', | ||
10 | + 'Expired' => '已过期', | ||
11 | + 'Hidden' => '已禁用', | ||
12 | + 'Logs' => '日志信息', | ||
13 | + 'Crontab rules' => 'Crontab规则', | ||
14 | + 'No limit' => '无限制', | ||
15 | + 'Execute time' => '最后执行时间', | ||
16 | + 'Request Url' => '请求URL', | ||
17 | + 'Execute Sql Script' => '执行SQL', | ||
18 | + 'Execute Shell' => '执行Shell', | ||
19 | + 'Crontab format invalid' => 'Crontab格式错误', | ||
20 | + 'Next execute time' => '下次预计时间', | ||
21 | + 'The next %s times the execution time' => '接下来 %s 次的执行时间', | ||
22 | +]; |
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\model; | ||
4 | + | ||
5 | +use think\Model; | ||
6 | + | ||
7 | +class Crontab extends Model | ||
8 | +{ | ||
9 | + | ||
10 | + // 开启自动写入时间戳字段 | ||
11 | + protected $autoWriteTimestamp = 'int'; | ||
12 | + // 定义时间戳字段名 | ||
13 | + protected $createTime = 'createtime'; | ||
14 | + protected $updateTime = 'updatetime'; | ||
15 | + // 定义字段类型 | ||
16 | + protected $type = [ | ||
17 | + ]; | ||
18 | + // 追加属性 | ||
19 | + protected $append = [ | ||
20 | + 'type_text' | ||
21 | + ]; | ||
22 | + | ||
23 | + public static function getTypeList() | ||
24 | + { | ||
25 | + return [ | ||
26 | + 'url' => __('Request Url'), | ||
27 | + 'sql' => __('Execute Sql Script'), | ||
28 | + 'shell' => __('Execute Shell'), | ||
29 | + ]; | ||
30 | + } | ||
31 | + | ||
32 | + public function getTypeTextAttr($value, $data) | ||
33 | + { | ||
34 | + $typelist = self::getTypeList(); | ||
35 | + $value = $value ? $value : $data['type']; | ||
36 | + return $value && isset($typelist[$value]) ? $typelist[$value] : $value; | ||
37 | + } | ||
38 | + | ||
39 | + protected function setBegintimeAttr($value) | ||
40 | + { | ||
41 | + return $value && !is_numeric($value) ? strtotime($value) : $value; | ||
42 | + } | ||
43 | + | ||
44 | + protected function setEndtimeAttr($value) | ||
45 | + { | ||
46 | + return $value && !is_numeric($value) ? strtotime($value) : $value; | ||
47 | + } | ||
48 | + | ||
49 | + protected function setExecutetimeAttr($value) | ||
50 | + { | ||
51 | + return $value && !is_numeric($value) ? strtotime($value) : $value; | ||
52 | + } | ||
53 | + | ||
54 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\model; | ||
4 | + | ||
5 | +use think\Model; | ||
6 | + | ||
7 | +class CrontabLog extends Model | ||
8 | +{ | ||
9 | + | ||
10 | + // 开启自动写入时间戳字段 | ||
11 | + protected $autoWriteTimestamp = 'int'; | ||
12 | + // 定义时间戳字段名 | ||
13 | + protected $createTime = false; | ||
14 | + protected $updateTime = false; | ||
15 | + // 定义字段类型 | ||
16 | + protected $type = [ | ||
17 | + ]; | ||
18 | + // 追加属性 | ||
19 | + protected $append = [ | ||
20 | + ]; | ||
21 | + | ||
22 | + public function getStatusList() | ||
23 | + { | ||
24 | + return ['normal' => __('Normal'), 'hidden' => __('Hidden')]; | ||
25 | + } | ||
26 | + | ||
27 | + public function getStatusTextAttr($value, $data) | ||
28 | + { | ||
29 | + $value = $value ? $value : (isset($data['status']) ? $data['status'] : ''); | ||
30 | + $list = $this->getStatusList(); | ||
31 | + return isset($list[$value]) ? $list[$value] : ''; | ||
32 | + } | ||
33 | + | ||
34 | +} |
1 | +<style type="text/css"> | ||
2 | + #schedulepicker { | ||
3 | + padding-top:7px; | ||
4 | + } | ||
5 | +</style> | ||
6 | +<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action=""> | ||
7 | + <div class="form-group"> | ||
8 | + <label for="name" class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label> | ||
9 | + <div class="col-xs-12 col-sm-8"> | ||
10 | + <input type="text" class="form-control" id="title" name="row[title]" value="" data-rule="required" /> | ||
11 | + </div> | ||
12 | + </div> | ||
13 | + <div class="form-group"> | ||
14 | + <label for="name" class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label> | ||
15 | + <div class="col-xs-12 col-sm-8"> | ||
16 | + {:build_select('row[type]', $typeList, null, ['class'=>'form-control', 'data-rule'=>'required'])} | ||
17 | + </div> | ||
18 | + </div> | ||
19 | + <div class="form-group"> | ||
20 | + <label for="content" class="control-label col-xs-12 col-sm-2">{:__('Content')}:</label> | ||
21 | + <div class="col-xs-12 col-sm-8"> | ||
22 | + <textarea name="row[content]" id="conent" cols="30" rows="5" class="form-control" data-rule="required"></textarea> | ||
23 | + </div> | ||
24 | + </div> | ||
25 | + <div class="form-group"> | ||
26 | + <label for="schedule" class="control-label col-xs-12 col-sm-2">{:__('Schedule')}:</label> | ||
27 | + <div class="col-xs-12 col-sm-8"> | ||
28 | + <div class="input-group margin-bottom-sm"> | ||
29 | + <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)"/> | ||
30 | + <span class="input-group-btn"> | ||
31 | + <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> | ||
32 | + </span> | ||
33 | + <span class="msg-box n-right"></span> | ||
34 | + </div> | ||
35 | + <div id="schedulepicker"> | ||
36 | + <pre><code>* * * * * | ||
37 | +- - - - - | ||
38 | +| | | | +--- day of week (0 - 7) (Sunday=0 or 7) | ||
39 | +| | | +-------- month (1 - 12) | ||
40 | +| | +------------- day of month (1 - 31) | ||
41 | +| +------------------ hour (0 - 23) | ||
42 | ++----------------------- min (0 - 59)</code></pre> | ||
43 | + <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> | ||
44 | + <ol id="scheduleresult" class="list-group"> | ||
45 | + </ol> | ||
46 | + </div> | ||
47 | + </div> | ||
48 | + </div> | ||
49 | + <div class="form-group"> | ||
50 | + <label for="maximums" class="control-label col-xs-12 col-sm-2">{:__('Maximums')}:</label> | ||
51 | + <div class="col-xs-12 col-sm-4"> | ||
52 | + <input type="number" class="form-control" id="maximums" name="row[maximums]" value="0" data-rule="required" size="6" /> | ||
53 | + </div> | ||
54 | + </div> | ||
55 | + <div class="form-group"> | ||
56 | + <label for="begintime" class="control-label col-xs-12 col-sm-2">{:__('Begin time')}:</label> | ||
57 | + <div class="col-xs-12 col-sm-4"> | ||
58 | + <input type="text" class="form-control datetimepicker" id="begintime" name="row[begintime]" value="" data-rule="{:__('Begin time')}:required" size="6" /> | ||
59 | + </div> | ||
60 | + </div> | ||
61 | + <div class="form-group"> | ||
62 | + <label for="endtime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label> | ||
63 | + <div class="col-xs-12 col-sm-4"> | ||
64 | + <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" /> | ||
65 | + </div> | ||
66 | + </div> | ||
67 | + <div class="form-group"> | ||
68 | + <label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label> | ||
69 | + <div class="col-xs-12 col-sm-4"> | ||
70 | + <input type="text" class="form-control" id="weigh" name="row[weigh]" value="0" data-rule="required" size="6" /> | ||
71 | + </div> | ||
72 | + </div> | ||
73 | + <div class="form-group"> | ||
74 | + <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> | ||
75 | + <div class="col-xs-12 col-sm-8"> | ||
76 | + {:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])} | ||
77 | + </div> | ||
78 | + </div> | ||
79 | + <div class="form-group hide layer-footer"> | ||
80 | + <label class="control-label col-xs-12 col-sm-2"></label> | ||
81 | + <div class="col-xs-12 col-sm-8"> | ||
82 | + <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> | ||
83 | + <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> | ||
84 | + </div> | ||
85 | + </div> | ||
86 | + | ||
87 | +</form> |
1 | +<style type="text/css"> | ||
2 | + #schedulepicker { | ||
3 | + padding-top: 7px; | ||
4 | + } | ||
5 | +</style> | ||
6 | +<form id="edit-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action=""> | ||
7 | + <div class="form-group"> | ||
8 | + <label for="name" class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label> | ||
9 | + <div class="col-xs-12 col-sm-8"> | ||
10 | + <input type="text" class="form-control" id="title" name="row[title]" value="{$row.title}" data-rule="required"/> | ||
11 | + </div> | ||
12 | + </div> | ||
13 | + <div class="form-group"> | ||
14 | + <label for="name" class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label> | ||
15 | + <div class="col-xs-12 col-sm-8"> | ||
16 | + {:build_select('row[type]', $typeList, $row['type'], ['class'=>'form-control', 'data-rule'=>'required'])} | ||
17 | + </div> | ||
18 | + </div> | ||
19 | + <div class="form-group"> | ||
20 | + <label for="content" class="control-label col-xs-12 col-sm-2">{:__('Content')}:</label> | ||
21 | + <div class="col-xs-12 col-sm-8"> | ||
22 | + <textarea name="row[content]" id="conent" cols="30" rows="5" class="form-control" data-rule="required">{$row.content}</textarea> | ||
23 | + </div> | ||
24 | + </div> | ||
25 | + <div class="form-group"> | ||
26 | + <label for="schedule" class="control-label col-xs-12 col-sm-2">{:__('Schedule')}:</label> | ||
27 | + <div class="col-xs-12 col-sm-8"> | ||
28 | + <div class="input-group margin-bottom-sm"> | ||
29 | + <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)"/> | ||
30 | + <span class="input-group-btn"> | ||
31 | + <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> | ||
32 | + </span> | ||
33 | + <span class="msg-box n-right"></span> | ||
34 | + </div> | ||
35 | + | ||
36 | + <div id="schedulepicker"> | ||
37 | + <pre><code>* * * * * | ||
38 | +- - - - - | ||
39 | +| | | | +--- day of week (0 - 7) (Sunday=0 or 7) | ||
40 | +| | | +-------- month (1 - 12) | ||
41 | +| | +------------- day of month (1 - 31) | ||
42 | +| +------------------ hour (0 - 23) | ||
43 | ++----------------------- min (0 - 59)</code></pre> | ||
44 | + <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> | ||
45 | + <ol id="scheduleresult" class="list-group"> | ||
46 | + </ol> | ||
47 | + </div> | ||
48 | + </div> | ||
49 | + </div> | ||
50 | + <div class="form-group"> | ||
51 | + <label for="maximums" class="control-label col-xs-12 col-sm-2">{:__('Maximums')}:</label> | ||
52 | + <div class="col-xs-12 col-sm-4"> | ||
53 | + <input type="number" class="form-control" id="maximums" name="row[maximums]" value="{$row.maximums}" data-rule="required" size="6"/> | ||
54 | + </div> | ||
55 | + </div> | ||
56 | + <div class="form-group"> | ||
57 | + <label for="begintime" class="control-label col-xs-12 col-sm-2">{:__('Begin time')}:</label> | ||
58 | + <div class="col-xs-12 col-sm-4"> | ||
59 | + <input type="text" class="form-control datetimepicker" id="begintime" name="row[begintime]" value="{$row.begintime|datetime}" data-rule="{:__('Begin time')}:required" size="6"/> | ||
60 | + </div> | ||
61 | + </div> | ||
62 | + <div class="form-group"> | ||
63 | + <label for="endtime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label> | ||
64 | + <div class="col-xs-12 col-sm-4"> | ||
65 | + <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"/> | ||
66 | + </div> | ||
67 | + </div> | ||
68 | + <div class="form-group"> | ||
69 | + <label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label> | ||
70 | + <div class="col-xs-12 col-sm-4"> | ||
71 | + <input type="text" class="form-control" id="weigh" name="row[weigh]" value="{$row.weigh}" data-rule="required" size="6"/> | ||
72 | + </div> | ||
73 | + </div> | ||
74 | + <div class="form-group"> | ||
75 | + <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> | ||
76 | + <div class="col-xs-12 col-sm-8"> | ||
77 | + {:build_radios('row[status]', ['normal'=>__('Normal'), 'completed'=>__('Completed'), 'expired'=>__('Expired'), 'hidden'=>__('Hidden')], $row['status'])} | ||
78 | + </div> | ||
79 | + </div> | ||
80 | + <div class="form-group hide layer-footer"> | ||
81 | + <label class="control-label col-xs-12 col-sm-2"></label> | ||
82 | + <div class="col-xs-12 col-sm-8"> | ||
83 | + <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> | ||
84 | + <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> | ||
85 | + </div> | ||
86 | + </div> | ||
87 | + | ||
88 | +</form> |
1 | +<div class="panel panel-default panel-intro"> | ||
2 | + | ||
3 | + <div class="panel-heading"> | ||
4 | + {:build_heading(null,FALSE)} | ||
5 | + <ul class="nav nav-tabs" data-field="type"> | ||
6 | + <li class="active"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li> | ||
7 | + {foreach name="typeList" item="vo"} | ||
8 | + <li><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li> | ||
9 | + {/foreach} | ||
10 | + </ul> | ||
11 | + </div> | ||
12 | + | ||
13 | + <div class="panel-body"> | ||
14 | + <div id="myTabContent" class="tab-content"> | ||
15 | + <div class="tab-pane fade active in" id="one"> | ||
16 | + <div class="widget-body no-padding"> | ||
17 | + <div id="toolbar" class="toolbar"> | ||
18 | + {:build_toolbar('refresh,add,edit,del')} | ||
19 | + </div> | ||
20 | + <table id="table" class="table table-striped table-bordered table-hover" | ||
21 | + data-operate-edit="{:$auth->check('general/crontab/edit')}" | ||
22 | + data-operate-del="{:$auth->check('general/crontab/del')}" | ||
23 | + width="100%"> | ||
24 | + </table> | ||
25 | + </div> | ||
26 | + </div> | ||
27 | + | ||
28 | + </div> | ||
29 | + </div> | ||
30 | +</div> |
1 | +<style type="text/css"> | ||
2 | + #schedulepicker { | ||
3 | + padding-top:7px; | ||
4 | + } | ||
5 | +</style> | ||
6 | +<form id="edit-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action=""> | ||
7 | + <div class="form-group"> | ||
8 | + <label for="content" class="control-label col-xs-12 col-sm-2">{:__('Content')}:</label> | ||
9 | + <div class="col-xs-12 col-sm-10"> | ||
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> | ||
11 | + </div> | ||
12 | + </div> | ||
13 | + <div class="form-group"> | ||
14 | + <label for="executetime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label> | ||
15 | + <div class="col-xs-12 col-sm-4"> | ||
16 | + <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 /> | ||
17 | + </div> | ||
18 | + </div> | ||
19 | + <div class="form-group"> | ||
20 | + <label for="completetime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label> | ||
21 | + <div class="col-xs-12 col-sm-4"> | ||
22 | + <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 /> | ||
23 | + </div> | ||
24 | + </div> | ||
25 | + <div class="form-group"> | ||
26 | + <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> | ||
27 | + <div class="col-xs-12 col-sm-8"> | ||
28 | + <div style="padding-top:8px;"> | ||
29 | + {if $row['status']=='success'}<span class="label label-success">{:__('Success')}</span>{else/}<span class="label label-danger">{:__('Failure')}</span>{/if} | ||
30 | + </div> | ||
31 | + </div> | ||
32 | + </div> | ||
33 | + <div class="form-group hide layer-footer"> | ||
34 | + <label class="control-label col-xs-12 col-sm-2"></label> | ||
35 | + <div class="col-xs-12 col-sm-8"> | ||
36 | + <button type="button" class="btn btn-success btn-embossed" onclick="parent.Layer.close(parent.Layer.getFrameIndex(window.name))">{:__('Close')}</button> | ||
37 | + </div> | ||
38 | + </div> | ||
39 | + | ||
40 | +</form> |
1 | +<div class="panel panel-default panel-intro"> | ||
2 | + | ||
3 | + <div class="panel-heading"> | ||
4 | + {:build_heading(null,FALSE)} | ||
5 | + <ul class="nav nav-tabs" data-field="status"> | ||
6 | + <li class="active"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li> | ||
7 | + {foreach name="statusList" item="vo"} | ||
8 | + <li><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li> | ||
9 | + {/foreach} | ||
10 | + </ul> | ||
11 | + </div> | ||
12 | + | ||
13 | + <div class="panel-body"> | ||
14 | + <div id="myTabContent" class="tab-content"> | ||
15 | + <div class="tab-pane fade active in" id="one"> | ||
16 | + <div class="widget-body no-padding"> | ||
17 | + <div id="toolbar" class="toolbar"> | ||
18 | + {:build_toolbar('refresh,del')} | ||
19 | + </div> | ||
20 | + <table id="table" class="table table-striped table-bordered table-hover" | ||
21 | + data-operate-detail="{:$auth->check('general/crontab/detail')}" | ||
22 | + data-operate-del="{:$auth->check('general/crontab/del')}" | ||
23 | + width="100%"> | ||
24 | + </table> | ||
25 | + </div> | ||
26 | + </div> | ||
27 | + | ||
28 | + </div> | ||
29 | + </div> | ||
30 | +</div> |
addons/crontab/config.php
0 → 100644
addons/crontab/controller/Autotask.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\crontab\controller; | ||
4 | + | ||
5 | +use addons\crontab\model\Crontab; | ||
6 | +use Cron\CronExpression; | ||
7 | +use fast\Http; | ||
8 | +use think\Controller; | ||
9 | +use think\Db; | ||
10 | +use think\Exception; | ||
11 | +use think\Log; | ||
12 | + | ||
13 | +/** | ||
14 | + * 定时任务接口 | ||
15 | + * | ||
16 | + * 以Crontab方式每分钟定时执行,且只可以Cli方式运行 | ||
17 | + * @internal | ||
18 | + */ | ||
19 | +class Autotask extends Controller | ||
20 | +{ | ||
21 | + | ||
22 | + /** | ||
23 | + * 初始化方法,最前且始终执行 | ||
24 | + */ | ||
25 | + public function _initialize() | ||
26 | + { | ||
27 | + // 只可以以cli方式执行 | ||
28 | + if (!$this->request->isCli()) { | ||
29 | + $this->error('Autotask script only work at client!'); | ||
30 | + } | ||
31 | + | ||
32 | + parent::_initialize(); | ||
33 | + | ||
34 | + // 清除错误 | ||
35 | + error_reporting(0); | ||
36 | + | ||
37 | + // 设置永不超时 | ||
38 | + set_time_limit(0); | ||
39 | + } | ||
40 | + | ||
41 | + /** | ||
42 | + * 执行定时任务 | ||
43 | + */ | ||
44 | + public function index() | ||
45 | + { | ||
46 | + $time = time(); | ||
47 | + $logDir = LOG_PATH . 'crontab/'; | ||
48 | + if (!is_dir($logDir)) { | ||
49 | + mkdir($logDir, 0755); | ||
50 | + } | ||
51 | + //筛选未过期且未完成的任务 | ||
52 | + $crontabList = Crontab::where('status', '=', 'normal')->order('weigh desc,id desc')->select(); | ||
53 | + $execTime = time(); | ||
54 | + foreach ($crontabList as $crontab) { | ||
55 | + $update = []; | ||
56 | + $execute = false; | ||
57 | + if ($time < $crontab['begintime']) { | ||
58 | + //任务未开始 | ||
59 | + continue; | ||
60 | + } | ||
61 | + if ($crontab['maximums'] && $crontab['executes'] > $crontab['maximums']) { | ||
62 | + //任务已超过最大执行次数 | ||
63 | + $update['status'] = 'completed'; | ||
64 | + } else { | ||
65 | + if ($crontab['endtime'] > 0 && $time > $crontab['endtime']) { | ||
66 | + //任务已过期 | ||
67 | + $update['status'] = 'expired'; | ||
68 | + } else { | ||
69 | + //重复执行 | ||
70 | + //如果未到执行时间则继续循环 | ||
71 | + $cron = CronExpression::factory($crontab['schedule']); | ||
72 | + if (!$cron->isDue(date("YmdHi", $execTime)) || date("YmdHi", $execTime) === date("YmdHi", $crontab['executetime'])) { | ||
73 | + continue; | ||
74 | + } | ||
75 | + $execute = true; | ||
76 | + } | ||
77 | + } | ||
78 | + | ||
79 | + // 如果允许执行 | ||
80 | + if ($execute) { | ||
81 | + $update['executetime'] = $time; | ||
82 | + $update['executes'] = $crontab['executes'] + 1; | ||
83 | + $update['status'] = ($crontab['maximums'] > 0 && $update['executes'] >= $crontab['maximums']) ? 'completed' : 'normal'; | ||
84 | + } | ||
85 | + | ||
86 | + // 如果需要更新状态 | ||
87 | + if (!$update) { | ||
88 | + continue; | ||
89 | + } | ||
90 | + // 更新状态 | ||
91 | + $crontab->save($update); | ||
92 | + | ||
93 | + // 将执行放在后面是为了避免超时导致多次执行 | ||
94 | + if (!$execute) { | ||
95 | + continue; | ||
96 | + } | ||
97 | + $result = false; | ||
98 | + $message = ''; | ||
99 | + | ||
100 | + try { | ||
101 | + if ($crontab['type'] == 'url') { | ||
102 | + if (substr($crontab['content'], 0, 1) == "/") { | ||
103 | + // 本地项目URL | ||
104 | + $message = shell_exec('php ' . ROOT_PATH . 'public/index.php ' . $crontab['content']); | ||
105 | + $result = $message ? true : false; | ||
106 | + } else { | ||
107 | + $arr = explode(" ", $crontab['content']); | ||
108 | + $url = $arr[0]; | ||
109 | + $params = isset($arr[1]) ? $arr[1] : ''; | ||
110 | + $method = isset($arr[2]) ? $arr[2] : 'POST'; | ||
111 | + try { | ||
112 | + // 远程异步调用URL | ||
113 | + $ret = Http::sendRequest($url, $params, $method); | ||
114 | + $result = $ret['ret']; | ||
115 | + $message = $ret['msg']; | ||
116 | + } catch (\Exception $e) { | ||
117 | + $message = $e->getMessage(); | ||
118 | + } | ||
119 | + } | ||
120 | + | ||
121 | + } elseif ($crontab['type'] == 'sql') { | ||
122 | + $ret = $this->sql($crontab['content']); | ||
123 | + $result = $ret['ret']; | ||
124 | + $message = $ret['msg']; | ||
125 | + } elseif ($crontab['type'] == 'shell') { | ||
126 | + // 执行Shell | ||
127 | + $message = shell_exec($crontab['content']); | ||
128 | + $result = $message ? true : false; | ||
129 | + } | ||
130 | + } catch (\Exception $e) { | ||
131 | + $message = $e->getMessage(); | ||
132 | + } | ||
133 | + $log = [ | ||
134 | + 'crontab_id' => $crontab['id'], | ||
135 | + 'executetime' => $time, | ||
136 | + 'completetime' => time(), | ||
137 | + 'content' => $message, | ||
138 | + 'status' => $result ? 'success' : 'failure', | ||
139 | + ]; | ||
140 | + Db::name("crontab_log")->insert($log); | ||
141 | + } | ||
142 | + return "Execute completed!\n"; | ||
143 | + } | ||
144 | + | ||
145 | + /** | ||
146 | + * 执行SQL语句 | ||
147 | + */ | ||
148 | + protected function sql($sql) | ||
149 | + { | ||
150 | + //这里需要强制重连数据库,使用已有的连接会报2014错误 | ||
151 | + $connect = Db::connect([], true); | ||
152 | + $connect->execute("select 1"); | ||
153 | + | ||
154 | + // 执行SQL | ||
155 | + $sqlquery = str_replace('__PREFIX__', config('database.prefix'), $sql); | ||
156 | + $sqls = preg_split("/;[ \t]{0,}\n/i", $sqlquery); | ||
157 | + | ||
158 | + $result = false; | ||
159 | + $message = ''; | ||
160 | + $connect->startTrans(); | ||
161 | + try { | ||
162 | + foreach ($sqls as $key => $val) { | ||
163 | + if (trim($val) == '' || substr($val, 0, 2) == '--' || substr($val, 0, 2) == '/*') { | ||
164 | + continue; | ||
165 | + } | ||
166 | + $message .= "\nSQL:{$val}\n"; | ||
167 | + $val = rtrim($val, ';'); | ||
168 | + if (preg_match("/^(select|explain)(.*)/i ", $val)) { | ||
169 | + $count = $connect->execute($val); | ||
170 | + if ($count > 0) { | ||
171 | + $resultlist = Db::query($val); | ||
172 | + } else { | ||
173 | + $resultlist = []; | ||
174 | + } | ||
175 | + | ||
176 | + $message .= "Total:{$count}\n"; | ||
177 | + $j = 1; | ||
178 | + foreach ($resultlist as $m => $n) { | ||
179 | + $message .= "\n"; | ||
180 | + $message .= "Row:{$j}\n"; | ||
181 | + foreach ($n as $k => $v) { | ||
182 | + $message .= "{$k}:{$v}\n"; | ||
183 | + } | ||
184 | + $j++; | ||
185 | + } | ||
186 | + } else { | ||
187 | + $count = $connect->getPdo()->exec($val); | ||
188 | + $message = "Affected rows:{$count}"; | ||
189 | + } | ||
190 | + } | ||
191 | + $connect->commit(); | ||
192 | + $result = true; | ||
193 | + } catch (\PDOException $e) { | ||
194 | + $message = $e->getMessage(); | ||
195 | + $connect->rollback(); | ||
196 | + $result = false; | ||
197 | + } | ||
198 | + return ['ret' => $result, 'msg' => $message]; | ||
199 | + | ||
200 | + } | ||
201 | +} |
addons/crontab/controller/Index.php
0 → 100644
addons/crontab/info.ini
0 → 100644
addons/crontab/install.sql
0 → 100644
1 | +CREATE TABLE IF NOT EXISTS `__PREFIX__crontab` ( | ||
2 | + `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID', | ||
3 | + `type` varchar(10) NOT NULL DEFAULT '' COMMENT '事件类型', | ||
4 | + `title` varchar(100) NOT NULL DEFAULT '' COMMENT '事件标题', | ||
5 | + `content` text NOT NULL COMMENT '事件内容', | ||
6 | + `schedule` varchar(100) NOT NULL DEFAULT '' COMMENT 'Crontab格式', | ||
7 | + `sleep` tinyint(1) UNSIGNED NOT NULL DEFAULT '0' COMMENT '延迟秒数执行', | ||
8 | + `maximums` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '最大执行次数 0为不限', | ||
9 | + `executes` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '已经执行的次数', | ||
10 | + `createtime` int(10) DEFAULT NULL COMMENT '创建时间', | ||
11 | + `updatetime` int(10) DEFAULT NULL COMMENT '更新时间', | ||
12 | + `begintime` int(10) DEFAULT NULL COMMENT '开始时间', | ||
13 | + `endtime` int(10) DEFAULT NULL COMMENT '结束时间', | ||
14 | + `executetime` int(10) DEFAULT NULL COMMENT '最后执行时间', | ||
15 | + `weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重', | ||
16 | + `status` enum('completed','expired','hidden','normal') NOT NULL DEFAULT 'normal' COMMENT '状态', | ||
17 | + PRIMARY KEY (`id`) | ||
18 | +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='定时任务表'; | ||
19 | + | ||
20 | +BEGIN; | ||
21 | +INSERT INTO `__PREFIX__crontab` (`id`, `type`, `title`, `content`, `schedule`, `sleep`, `maximums`, `executes`, `createtime`, `updatetime`, `begintime`, `endtime`, `executetime`, `weigh`, `status`) VALUES | ||
22 | +(1, 'url', '请求百度', 'https://www.baidu.com', '* * * * *', 0, 0, 0, 1497070825, 1501253101, 1483200000, 1830268800, 1501253101, 1, 'normal'), | ||
23 | +(2, 'sql', '查询一条SQL', 'SELECT 1;', '* * * * *', 0, 0, 0, 1497071095, 1501253101, 1483200000, 1830268800, 1501253101, 2, 'normal'); | ||
24 | +COMMIT; | ||
25 | + | ||
26 | +CREATE TABLE IF NOT EXISTS `__PREFIX__crontab_log` ( | ||
27 | + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, | ||
28 | + `crontab_id` int(10) DEFAULT NULL COMMENT '任务ID', | ||
29 | + `executetime` int(10) DEFAULT NULL COMMENT '执行时间', | ||
30 | + `completetime` int(10) DEFAULT NULL COMMENT '结束时间', | ||
31 | + `content` text COMMENT '执行结果', | ||
32 | + `status` enum('success','failure') DEFAULT 'failure' COMMENT '状态', | ||
33 | + PRIMARY KEY (`id`), | ||
34 | + KEY `crontab_id` (`crontab_id`) | ||
35 | +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='定时任务日志表'; |
addons/crontab/model/Crontab.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\crontab\model; | ||
4 | + | ||
5 | +use think\Model; | ||
6 | + | ||
7 | +class Crontab extends Model | ||
8 | +{ | ||
9 | + | ||
10 | + // 开启自动写入时间戳字段 | ||
11 | + protected $autoWriteTimestamp = 'int'; | ||
12 | + // 定义时间戳字段名 | ||
13 | + protected $createTime = 'createtime'; | ||
14 | + protected $updateTime = 'updatetime'; | ||
15 | + // 定义字段类型 | ||
16 | + protected $type = [ | ||
17 | + ]; | ||
18 | + // 追加属性 | ||
19 | + protected $append = [ | ||
20 | + 'type_text' | ||
21 | + ]; | ||
22 | + | ||
23 | + public static function getTypeList() | ||
24 | + { | ||
25 | + return [ | ||
26 | + 'url' => __('Request Url'), | ||
27 | + 'sql' => __('Execute Sql Script'), | ||
28 | + 'shell' => __('Execute Shell'), | ||
29 | + ]; | ||
30 | + } | ||
31 | + | ||
32 | + public function getTypeTextAttr($value, $data) | ||
33 | + { | ||
34 | + $typelist = self::getTypeList(); | ||
35 | + $value = $value ? $value : $data['type']; | ||
36 | + return $value && isset($typelist[$value]) ? $typelist[$value] : $value; | ||
37 | + } | ||
38 | + | ||
39 | + protected function setBegintimeAttr($value) | ||
40 | + { | ||
41 | + return $value && !is_numeric($value) ? strtotime($value) : $value; | ||
42 | + } | ||
43 | + | ||
44 | + protected function setEndtimeAttr($value) | ||
45 | + { | ||
46 | + return $value && !is_numeric($value) ? strtotime($value) : $value; | ||
47 | + } | ||
48 | + | ||
49 | + protected function setExecutetimeAttr($value) | ||
50 | + { | ||
51 | + return $value && !is_numeric($value) ? strtotime($value) : $value; | ||
52 | + } | ||
53 | + | ||
54 | +} |
1 | +define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { | ||
2 | + | ||
3 | + var Controller = { | ||
4 | + index: function () { | ||
5 | + // 初始化表格参数配置 | ||
6 | + Table.api.init({ | ||
7 | + extend: { | ||
8 | + index_url: 'general/crontab/index', | ||
9 | + add_url: 'general/crontab/add', | ||
10 | + edit_url: 'general/crontab/edit', | ||
11 | + del_url: 'general/crontab/del', | ||
12 | + multi_url: 'general/crontab/multi', | ||
13 | + table: 'crontab' | ||
14 | + } | ||
15 | + }); | ||
16 | + | ||
17 | + var table = $("#table"); | ||
18 | + | ||
19 | + // 初始化表格 | ||
20 | + table.bootstrapTable({ | ||
21 | + url: $.fn.bootstrapTable.defaults.extend.index_url, | ||
22 | + sortName: 'weigh', | ||
23 | + columns: [ | ||
24 | + [ | ||
25 | + {field: 'state', checkbox: true,}, | ||
26 | + {field: 'id', title: 'ID'}, | ||
27 | + {field: 'type', title: __('Type'), searchList: Config.typeList, formatter: Table.api.formatter.label}, | ||
28 | + {field: 'title', title: __('Title')}, | ||
29 | + {field: 'maximums', title: __('Maximums'), formatter: Controller.api.formatter.maximums}, | ||
30 | + {field: 'executes', title: __('Executes')}, | ||
31 | + {field: 'begintime', title: __('Begin time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange'}, | ||
32 | + {field: 'endtime', title: __('End time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange'}, | ||
33 | + {field: 'nexttime', title: __('Next execute time'), formatter: Controller.api.formatter.nexttime, operate: false, addclass: 'datetimerange', sortable: true}, | ||
34 | + {field: 'executetime', title: __('Execute time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true}, | ||
35 | + {field: 'weigh', title: __('Weigh')}, | ||
36 | + {field: 'status', title: __('Status'), formatter: Table.api.formatter.status}, | ||
37 | + { | ||
38 | + field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate, | ||
39 | + buttons: [ | ||
40 | + { | ||
41 | + name: "detail", | ||
42 | + icon: "fa fa-list", | ||
43 | + title: function (row, index) { | ||
44 | + return __('Logs') + "[" + row['title'] + "]"; | ||
45 | + }, | ||
46 | + text: __('Logs'), | ||
47 | + classname: "btn btn-xs btn-info btn-dialog", | ||
48 | + url: "general/crontab_log/index?crontab_id={ids}", | ||
49 | + } | ||
50 | + ] | ||
51 | + } | ||
52 | + ] | ||
53 | + ] | ||
54 | + }); | ||
55 | + | ||
56 | + // 为表格绑定事件 | ||
57 | + Table.api.bindevent(table); | ||
58 | + }, | ||
59 | + add: function () { | ||
60 | + Controller.api.bindevent(); | ||
61 | + }, | ||
62 | + edit: function () { | ||
63 | + Controller.api.bindevent(); | ||
64 | + }, | ||
65 | + api: { | ||
66 | + bindevent: function () { | ||
67 | + $('#schedule').on('valid.field', function (e, result) { | ||
68 | + $("#pickdays").trigger("change"); | ||
69 | + }); | ||
70 | + Form.api.bindevent($("form[role=form]")); | ||
71 | + $(document).on("change", "#pickdays", function () { | ||
72 | + Fast.api.ajax({url: "general/crontab/get_schedule_future", data: {schedule: $("#schedule").val(), days: $(this).val()}}, function (data, ret) { | ||
73 | + if (typeof data.futuretime !== 'undefined' && $.isArray(data.futuretime)) { | ||
74 | + var result = []; | ||
75 | + $.each(data.futuretime, function (i, j) { | ||
76 | + result.push("<li class='list-group-item'>" + j + "<span class='badge'>" + (i + 1) + "</span></li>"); | ||
77 | + }); | ||
78 | + $("#scheduleresult").html(result.join("")); | ||
79 | + } else { | ||
80 | + $("#scheduleresult").html(""); | ||
81 | + } | ||
82 | + return false; | ||
83 | + }); | ||
84 | + }); | ||
85 | + $("#pickdays").trigger("change"); | ||
86 | + }, | ||
87 | + formatter: { | ||
88 | + nexttime: function (value, row, index) { | ||
89 | + if (isNaN(value)) { | ||
90 | + return value; | ||
91 | + } else { | ||
92 | + return Table.api.formatter.datetime.call(this, value, row, index); | ||
93 | + } | ||
94 | + }, | ||
95 | + maximums: function (value, row, index) { | ||
96 | + return value === 0 ? __('No limit') : value; | ||
97 | + } | ||
98 | + } | ||
99 | + } | ||
100 | + }; | ||
101 | + return Controller; | ||
102 | +}); |
1 | +define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { | ||
2 | + | ||
3 | + var Controller = { | ||
4 | + index: function () { | ||
5 | + // 初始化表格参数配置 | ||
6 | + Table.api.init({ | ||
7 | + extend: { | ||
8 | + index_url: 'general/crontab_log/index', | ||
9 | + add_url: 'general/crontab_log/add', | ||
10 | + edit_url: '', | ||
11 | + del_url: 'general/crontab_log/del', | ||
12 | + multi_url: 'general/crontab_log/multi', | ||
13 | + table: 'crontab' | ||
14 | + } | ||
15 | + }); | ||
16 | + | ||
17 | + var table = $("#table"); | ||
18 | + | ||
19 | + // 初始化表格 | ||
20 | + table.bootstrapTable({ | ||
21 | + url: $.fn.bootstrapTable.defaults.extend.index_url, | ||
22 | + sortName: 'id', | ||
23 | + columns: [ | ||
24 | + [ | ||
25 | + {field: 'state', checkbox: true,}, | ||
26 | + {field: 'id', title: 'ID'}, | ||
27 | + {field: 'crontab_id', title: __('Crontab_id'), formatter: Table.api.formatter.search}, | ||
28 | + {field: 'executetime', title: __('Execute time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true}, | ||
29 | + {field: 'completetime', title: __('Complete time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true}, | ||
30 | + {field: 'status', title: __('Status'), searchList: Config.statusList, custom: {success: 'success', failure: 'danger'}, formatter: Table.api.formatter.status}, | ||
31 | + { | ||
32 | + field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate, | ||
33 | + buttons: [ | ||
34 | + { | ||
35 | + name: "detail", | ||
36 | + text: __("Result"), | ||
37 | + classname: "btn btn-xs btn-info btn-dialog", | ||
38 | + icon: "fa fa-file", | ||
39 | + url: "general/crontab_log/detail", | ||
40 | + extend: "data-window='parent'" | ||
41 | + } | ||
42 | + ] | ||
43 | + } | ||
44 | + ] | ||
45 | + ] | ||
46 | + }); | ||
47 | + | ||
48 | + // 为表格绑定事件 | ||
49 | + Table.api.bindevent(table); | ||
50 | + }, | ||
51 | + add: function () { | ||
52 | + Controller.api.bindevent(); | ||
53 | + }, | ||
54 | + edit: function () { | ||
55 | + Controller.api.bindevent(); | ||
56 | + }, | ||
57 | + api: { | ||
58 | + bindevent: function () { | ||
59 | + Form.api.bindevent($("form[role=form]")); | ||
60 | + | ||
61 | + }, | ||
62 | + } | ||
63 | + }; | ||
64 | + return Controller; | ||
65 | +}); |
application/admin/controller/Payimage.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\controller; | ||
4 | + | ||
5 | +use app\common\controller\Backend; | ||
6 | + | ||
7 | +/** | ||
8 | + * 收款码图片 | ||
9 | + * | ||
10 | + * @icon fa fa-circle-o | ||
11 | + */ | ||
12 | +class Payimage extends Backend | ||
13 | +{ | ||
14 | + | ||
15 | + /** | ||
16 | + * Payimage模型对象 | ||
17 | + * @var \app\admin\model\Payimage | ||
18 | + */ | ||
19 | + protected $model = null; | ||
20 | + | ||
21 | + public function _initialize() | ||
22 | + { | ||
23 | + parent::_initialize(); | ||
24 | + $this->model = new \app\admin\model\Payimage; | ||
25 | + | ||
26 | + } | ||
27 | + | ||
28 | + /** | ||
29 | + * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 | ||
30 | + * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 | ||
31 | + * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 | ||
32 | + */ | ||
33 | + | ||
34 | + | ||
35 | +} |
application/admin/controller/Vipdaynum.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\controller; | ||
4 | + | ||
5 | +use app\common\controller\Backend; | ||
6 | + | ||
7 | +/** | ||
8 | + * 开通会员天数设置 | ||
9 | + * | ||
10 | + * @icon fa fa-circle-o | ||
11 | + */ | ||
12 | +class Vipdaynum extends Backend | ||
13 | +{ | ||
14 | + | ||
15 | + /** | ||
16 | + * Vipdaynum模型对象 | ||
17 | + * @var \app\admin\model\Vipdaynum | ||
18 | + */ | ||
19 | + protected $model = null; | ||
20 | + | ||
21 | + public function _initialize() | ||
22 | + { | ||
23 | + parent::_initialize(); | ||
24 | + $this->model = new \app\admin\model\Vipdaynum; | ||
25 | + | ||
26 | + } | ||
27 | + | ||
28 | + /** | ||
29 | + * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 | ||
30 | + * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 | ||
31 | + * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 | ||
32 | + */ | ||
33 | + | ||
34 | + | ||
35 | +} |
application/admin/controller/Viporder.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\controller; | ||
4 | + | ||
5 | +use app\common\controller\Backend; | ||
6 | +use think\Db; | ||
7 | + | ||
8 | +/** | ||
9 | + * 开通会员订单 | ||
10 | + * | ||
11 | + * @icon fa fa-circle-o | ||
12 | + */ | ||
13 | +class Viporder extends Backend | ||
14 | +{ | ||
15 | + | ||
16 | + /** | ||
17 | + * Viporder模型对象 | ||
18 | + * @var \app\admin\model\Viporder | ||
19 | + */ | ||
20 | + protected $model = null; | ||
21 | + | ||
22 | + public function _initialize() | ||
23 | + { | ||
24 | + parent::_initialize(); | ||
25 | + $this->model = new \app\admin\model\Viporder; | ||
26 | + | ||
27 | + } | ||
28 | + | ||
29 | + /** | ||
30 | + * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 | ||
31 | + * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 | ||
32 | + * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 | ||
33 | + */ | ||
34 | + | ||
35 | + /** | ||
36 | + * 查看 | ||
37 | + */ | ||
38 | + public function index() | ||
39 | + { | ||
40 | + //设置过滤方法 | ||
41 | + $this->request->filter(['strip_tags']); | ||
42 | + if ($this->request->isAjax()) { | ||
43 | + //如果发送的来源是Selectpage,则转发到Selectpage | ||
44 | + if ($this->request->request('keyField')) { | ||
45 | + return $this->selectpage(); | ||
46 | + } | ||
47 | + list($where, $sort, $order, $offset, $limit) = $this->buildparams(); | ||
48 | + $total = $this->model | ||
49 | + ->where($where) | ||
50 | + ->order($sort, $order) | ||
51 | + ->count(); | ||
52 | + | ||
53 | + $list = $this->model | ||
54 | + ->where($where) | ||
55 | + ->order($sort, $order) | ||
56 | + ->limit($offset, $limit) | ||
57 | + ->select(); | ||
58 | + | ||
59 | + $list = collection($list)->toArray(); | ||
60 | + foreach ($list as &$v){ | ||
61 | + $v['user_id'] = Db::name('user')->where('id',$v['user_id'])->value('username'); | ||
62 | + } | ||
63 | + $result = array("total" => $total, "rows" => $list); | ||
64 | + | ||
65 | + return json($result); | ||
66 | + } | ||
67 | + return $this->view->fetch(); | ||
68 | + } | ||
69 | + | ||
70 | + /** | ||
71 | + * 编辑 | ||
72 | + */ | ||
73 | + public function edit($ids = null) | ||
74 | + { | ||
75 | + $row = $this->model->get($ids); | ||
76 | + if (!$row) { | ||
77 | + $this->error(__('No Results were found')); | ||
78 | + } | ||
79 | + $adminIds = $this->getDataLimitAdminIds(); | ||
80 | + if (is_array($adminIds)) { | ||
81 | + if (!in_array($row[$this->dataLimitField], $adminIds)) { | ||
82 | + $this->error(__('You have no permission')); | ||
83 | + } | ||
84 | + } | ||
85 | + if ($this->request->isPost()) { | ||
86 | + $params = $this->request->post("row/a"); | ||
87 | + if ($params) { | ||
88 | + $params = $this->preExcludeFields($params); | ||
89 | + //查询用户的个人资料 | ||
90 | + $data = Db::name('viporder')->where('id',$ids)->find(); | ||
91 | + $user = Db::name('user')->where('id',$data['user_id'])->find(); | ||
92 | + if($params['status'] == 1){ | ||
93 | + //审核通过 | ||
94 | + //判断用户是否已经是会员 | ||
95 | + if($user['identity'] == 1){ | ||
96 | + $update['identity'] = 2; | ||
97 | + $update['expirationtime'] = time()+86400*$data['daynum']; | ||
98 | + }else{ | ||
99 | + $update['expirationtime'] = $user['expirationtime']+86400*$data['daynum']; | ||
100 | + } | ||
101 | + Db::name('user')->where('id',$data['user_id'])->update($update); | ||
102 | + } | ||
103 | + $result = false; | ||
104 | + Db::startTrans(); | ||
105 | + try { | ||
106 | + //是否采用模型验证 | ||
107 | + if ($this->modelValidate) { | ||
108 | + $name = str_replace("\\model\\", "\\validate\\", get_class($this->model)); | ||
109 | + $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate; | ||
110 | + $row->validateFailException(true)->validate($validate); | ||
111 | + } | ||
112 | + $result = $row->allowField(true)->save($params); | ||
113 | + Db::commit(); | ||
114 | + } catch (ValidateException $e) { | ||
115 | + Db::rollback(); | ||
116 | + $this->error($e->getMessage()); | ||
117 | + } catch (PDOException $e) { | ||
118 | + Db::rollback(); | ||
119 | + $this->error($e->getMessage()); | ||
120 | + } catch (Exception $e) { | ||
121 | + Db::rollback(); | ||
122 | + $this->error($e->getMessage()); | ||
123 | + } | ||
124 | + if ($result !== false) { | ||
125 | + $this->success(); | ||
126 | + } else { | ||
127 | + $this->error(__('No rows were updated')); | ||
128 | + } | ||
129 | + } | ||
130 | + $this->error(__('Parameter %s can not be empty', '')); | ||
131 | + } | ||
132 | + $this->view->assign("row", $row); | ||
133 | + return $this->view->fetch(); | ||
134 | + } | ||
135 | + | ||
136 | + | ||
137 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\controller\general; | ||
4 | + | ||
5 | +use app\common\controller\Backend; | ||
6 | +use Cron\CronExpression; | ||
7 | + | ||
8 | +/** | ||
9 | + * 定时任务 | ||
10 | + * | ||
11 | + * @icon fa fa-tasks | ||
12 | + * @remark 类似于Linux的Crontab定时任务,可以按照设定的时间进行任务的执行 | ||
13 | + */ | ||
14 | +class Crontab extends Backend | ||
15 | +{ | ||
16 | + | ||
17 | + protected $model = null; | ||
18 | + protected $noNeedRight = ['check_schedule', 'get_schedule_future']; | ||
19 | + | ||
20 | + public function _initialize() | ||
21 | + { | ||
22 | + parent::_initialize(); | ||
23 | + $this->model = model('Crontab'); | ||
24 | + $this->view->assign('typeList', \app\admin\model\Crontab::getTypeList()); | ||
25 | + $this->assignconfig('typeList', \app\admin\model\Crontab::getTypeList()); | ||
26 | + } | ||
27 | + | ||
28 | + /** | ||
29 | + * 查看 | ||
30 | + */ | ||
31 | + public function index() | ||
32 | + { | ||
33 | + if ($this->request->isAjax()) { | ||
34 | + list($where, $sort, $order, $offset, $limit) = $this->buildparams(); | ||
35 | + $total = $this->model | ||
36 | + ->where($where) | ||
37 | + ->order($sort, $order) | ||
38 | + ->count(); | ||
39 | + | ||
40 | + $list = $this->model | ||
41 | + ->where($where) | ||
42 | + ->order($sort, $order) | ||
43 | + ->limit($offset, $limit) | ||
44 | + ->select(); | ||
45 | + $time = time(); | ||
46 | + foreach ($list as $k => &$v) { | ||
47 | + $cron = CronExpression::factory($v['schedule']); | ||
48 | + $v['nexttime'] = $time > $v['endtime'] ? __('None') : $cron->getNextRunDate()->getTimestamp(); | ||
49 | + } | ||
50 | + $result = array("total" => $total, "rows" => $list); | ||
51 | + | ||
52 | + return json($result); | ||
53 | + } | ||
54 | + return $this->view->fetch(); | ||
55 | + } | ||
56 | + | ||
57 | + /** | ||
58 | + * 判断Crontab格式是否正确 | ||
59 | + * @internal | ||
60 | + */ | ||
61 | + public function check_schedule() | ||
62 | + { | ||
63 | + $row = $this->request->post("row/a"); | ||
64 | + $schedule = isset($row['schedule']) ? $row['schedule'] : ''; | ||
65 | + if (CronExpression::isValidExpression($schedule)) { | ||
66 | + $this->success(); | ||
67 | + } else { | ||
68 | + $this->error(__('Crontab format invalid')); | ||
69 | + } | ||
70 | + } | ||
71 | + | ||
72 | + /** | ||
73 | + * 根据Crontab表达式读取未来七次的时间 | ||
74 | + * @internal | ||
75 | + */ | ||
76 | + public function get_schedule_future() | ||
77 | + { | ||
78 | + $time = []; | ||
79 | + $schedule = $this->request->post('schedule'); | ||
80 | + $days = (int)$this->request->post('days'); | ||
81 | + try { | ||
82 | + $cron = CronExpression::factory($schedule); | ||
83 | + for ($i = 0; $i < $days; $i++) { | ||
84 | + $time[] = $cron->getNextRunDate(null, $i)->format('Y-m-d H:i:s'); | ||
85 | + } | ||
86 | + } catch (\Exception $e) { | ||
87 | + | ||
88 | + } | ||
89 | + | ||
90 | + $this->success("", null, ['futuretime' => $time]); | ||
91 | + } | ||
92 | + | ||
93 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\controller\general; | ||
4 | + | ||
5 | +use app\common\controller\Backend; | ||
6 | + | ||
7 | +/** | ||
8 | + * 定时任务 | ||
9 | + * | ||
10 | + * @icon fa fa-tasks | ||
11 | + * @remark 类似于Linux的Crontab定时任务,可以按照设定的时间进行任务的执行 | ||
12 | + */ | ||
13 | +class CrontabLog extends Backend | ||
14 | +{ | ||
15 | + | ||
16 | + protected $model = null; | ||
17 | + | ||
18 | + public function _initialize() | ||
19 | + { | ||
20 | + parent::_initialize(); | ||
21 | + $this->model = model('CrontabLog'); | ||
22 | + $this->view->assign('statusList', $this->model->getStatusList()); | ||
23 | + $this->assignconfig('statusList', $this->model->getStatusList()); | ||
24 | + } | ||
25 | + | ||
26 | + /** | ||
27 | + * 查看 | ||
28 | + */ | ||
29 | + public function index() | ||
30 | + { | ||
31 | + if ($this->request->isAjax()) { | ||
32 | + list($where, $sort, $order, $offset, $limit) = $this->buildparams(); | ||
33 | + $total = $this->model | ||
34 | + ->where($where) | ||
35 | + ->order($sort, $order) | ||
36 | + ->count(); | ||
37 | + | ||
38 | + $list = $this->model | ||
39 | + ->where($where) | ||
40 | + ->order($sort, $order) | ||
41 | + ->limit($offset, $limit) | ||
42 | + ->select(); | ||
43 | + $list = collection($list)->toArray(); | ||
44 | + $result = array("total" => $total, "rows" => $list); | ||
45 | + | ||
46 | + return json($result); | ||
47 | + } | ||
48 | + return $this->view->fetch(); | ||
49 | + } | ||
50 | + | ||
51 | + public function detail($ids = null) | ||
52 | + { | ||
53 | + $row = $this->model->get($ids); | ||
54 | + if (!$row) { | ||
55 | + $this->error(__('No Results were found')); | ||
56 | + } | ||
57 | + $this->view->assign("row", $row); | ||
58 | + return $this->view->fetch(); | ||
59 | + } | ||
60 | + | ||
61 | +} |
1 | +<?php | ||
2 | + | ||
3 | +return [ | ||
4 | + 'Title' => '任务标题', | ||
5 | + 'Maximums' => '最多执行', | ||
6 | + 'Sleep' => '延迟秒数', | ||
7 | + 'Schedule' => '执行周期', | ||
8 | + 'Executes' => '执行次数', | ||
9 | + 'Completed' => '已完成', | ||
10 | + 'Expired' => '已过期', | ||
11 | + 'Hidden' => '已禁用', | ||
12 | + 'Logs' => '日志信息', | ||
13 | + 'Crontab rules' => 'Crontab规则', | ||
14 | + 'No limit' => '无限制', | ||
15 | + 'Execute time' => '最后执行时间', | ||
16 | + 'Request Url' => '请求URL', | ||
17 | + 'Execute Sql Script' => '执行SQL', | ||
18 | + 'Execute Shell' => '执行Shell', | ||
19 | + 'Crontab format invalid' => 'Crontab格式错误', | ||
20 | + 'Next execute time' => '下次预计时间', | ||
21 | + 'The next %s times the execution time' => '接下来 %s 次的执行时间', | ||
22 | +]; |
application/admin/lang/zh-cn/payimage.php
0 → 100644
application/admin/lang/zh-cn/vipdaynum.php
0 → 100644
application/admin/lang/zh-cn/viporder.php
0 → 100644
application/admin/model/Crontab.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\model; | ||
4 | + | ||
5 | +use think\Model; | ||
6 | + | ||
7 | +class Crontab extends Model | ||
8 | +{ | ||
9 | + | ||
10 | + // 开启自动写入时间戳字段 | ||
11 | + protected $autoWriteTimestamp = 'int'; | ||
12 | + // 定义时间戳字段名 | ||
13 | + protected $createTime = 'createtime'; | ||
14 | + protected $updateTime = 'updatetime'; | ||
15 | + // 定义字段类型 | ||
16 | + protected $type = [ | ||
17 | + ]; | ||
18 | + // 追加属性 | ||
19 | + protected $append = [ | ||
20 | + 'type_text' | ||
21 | + ]; | ||
22 | + | ||
23 | + public static function getTypeList() | ||
24 | + { | ||
25 | + return [ | ||
26 | + 'url' => __('Request Url'), | ||
27 | + 'sql' => __('Execute Sql Script'), | ||
28 | + 'shell' => __('Execute Shell'), | ||
29 | + ]; | ||
30 | + } | ||
31 | + | ||
32 | + public function getTypeTextAttr($value, $data) | ||
33 | + { | ||
34 | + $typelist = self::getTypeList(); | ||
35 | + $value = $value ? $value : $data['type']; | ||
36 | + return $value && isset($typelist[$value]) ? $typelist[$value] : $value; | ||
37 | + } | ||
38 | + | ||
39 | + protected function setBegintimeAttr($value) | ||
40 | + { | ||
41 | + return $value && !is_numeric($value) ? strtotime($value) : $value; | ||
42 | + } | ||
43 | + | ||
44 | + protected function setEndtimeAttr($value) | ||
45 | + { | ||
46 | + return $value && !is_numeric($value) ? strtotime($value) : $value; | ||
47 | + } | ||
48 | + | ||
49 | + protected function setExecutetimeAttr($value) | ||
50 | + { | ||
51 | + return $value && !is_numeric($value) ? strtotime($value) : $value; | ||
52 | + } | ||
53 | + | ||
54 | +} |
application/admin/model/CrontabLog.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\model; | ||
4 | + | ||
5 | +use think\Model; | ||
6 | + | ||
7 | +class CrontabLog extends Model | ||
8 | +{ | ||
9 | + | ||
10 | + // 开启自动写入时间戳字段 | ||
11 | + protected $autoWriteTimestamp = 'int'; | ||
12 | + // 定义时间戳字段名 | ||
13 | + protected $createTime = false; | ||
14 | + protected $updateTime = false; | ||
15 | + // 定义字段类型 | ||
16 | + protected $type = [ | ||
17 | + ]; | ||
18 | + // 追加属性 | ||
19 | + protected $append = [ | ||
20 | + ]; | ||
21 | + | ||
22 | + public function getStatusList() | ||
23 | + { | ||
24 | + return ['normal' => __('Normal'), 'hidden' => __('Hidden')]; | ||
25 | + } | ||
26 | + | ||
27 | + public function getStatusTextAttr($value, $data) | ||
28 | + { | ||
29 | + $value = $value ? $value : (isset($data['status']) ? $data['status'] : ''); | ||
30 | + $list = $this->getStatusList(); | ||
31 | + return isset($list[$value]) ? $list[$value] : ''; | ||
32 | + } | ||
33 | + | ||
34 | +} |
application/admin/model/Payimage.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\model; | ||
4 | + | ||
5 | +use think\Model; | ||
6 | + | ||
7 | + | ||
8 | +class Payimage extends Model | ||
9 | +{ | ||
10 | + | ||
11 | + | ||
12 | + | ||
13 | + | ||
14 | + | ||
15 | + // 表名 | ||
16 | + protected $name = 'payimage'; | ||
17 | + | ||
18 | + // 自动写入时间戳字段 | ||
19 | + protected $autoWriteTimestamp = 'int'; | ||
20 | + | ||
21 | + // 定义时间戳字段名 | ||
22 | + protected $createTime = 'createtime'; | ||
23 | + protected $updateTime = 'updatetime'; | ||
24 | + protected $deleteTime = false; | ||
25 | + | ||
26 | + // 追加属性 | ||
27 | + protected $append = [ | ||
28 | + | ||
29 | + ]; | ||
30 | + | ||
31 | + | ||
32 | + | ||
33 | + | ||
34 | + | ||
35 | + | ||
36 | + | ||
37 | + | ||
38 | + | ||
39 | + | ||
40 | +} |
application/admin/model/Vipdaynum.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\model; | ||
4 | + | ||
5 | +use think\Model; | ||
6 | + | ||
7 | + | ||
8 | +class Vipdaynum extends Model | ||
9 | +{ | ||
10 | + | ||
11 | + | ||
12 | + | ||
13 | + | ||
14 | + | ||
15 | + // 表名 | ||
16 | + protected $name = 'vipdaynum'; | ||
17 | + | ||
18 | + // 自动写入时间戳字段 | ||
19 | + protected $autoWriteTimestamp = 'int'; | ||
20 | + | ||
21 | + // 定义时间戳字段名 | ||
22 | + protected $createTime = 'createtime'; | ||
23 | + protected $updateTime = 'updatetime'; | ||
24 | + protected $deleteTime = false; | ||
25 | + | ||
26 | + // 追加属性 | ||
27 | + protected $append = [ | ||
28 | + | ||
29 | + ]; | ||
30 | + | ||
31 | + | ||
32 | + | ||
33 | + | ||
34 | + | ||
35 | + | ||
36 | + | ||
37 | + | ||
38 | + | ||
39 | + | ||
40 | +} |
application/admin/model/Viporder.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\model; | ||
4 | + | ||
5 | +use think\Model; | ||
6 | + | ||
7 | + | ||
8 | +class Viporder extends Model | ||
9 | +{ | ||
10 | + | ||
11 | + | ||
12 | + | ||
13 | + | ||
14 | + | ||
15 | + // 表名 | ||
16 | + protected $name = 'viporder'; | ||
17 | + | ||
18 | + // 自动写入时间戳字段 | ||
19 | + protected $autoWriteTimestamp = 'int'; | ||
20 | + | ||
21 | + // 定义时间戳字段名 | ||
22 | + protected $createTime = 'createtime'; | ||
23 | + protected $updateTime = 'updatetime'; | ||
24 | + protected $deleteTime = false; | ||
25 | + | ||
26 | + // 追加属性 | ||
27 | + protected $append = [ | ||
28 | + | ||
29 | + ]; | ||
30 | + | ||
31 | + | ||
32 | + | ||
33 | + | ||
34 | + | ||
35 | + | ||
36 | + | ||
37 | + | ||
38 | + | ||
39 | + | ||
40 | +} |
application/admin/validate/Payimage.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\validate; | ||
4 | + | ||
5 | +use think\Validate; | ||
6 | + | ||
7 | +class Payimage extends Validate | ||
8 | +{ | ||
9 | + /** | ||
10 | + * 验证规则 | ||
11 | + */ | ||
12 | + protected $rule = [ | ||
13 | + ]; | ||
14 | + /** | ||
15 | + * 提示消息 | ||
16 | + */ | ||
17 | + protected $message = [ | ||
18 | + ]; | ||
19 | + /** | ||
20 | + * 验证场景 | ||
21 | + */ | ||
22 | + protected $scene = [ | ||
23 | + 'add' => [], | ||
24 | + 'edit' => [], | ||
25 | + ]; | ||
26 | + | ||
27 | +} |
application/admin/validate/Vipdaynum.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\validate; | ||
4 | + | ||
5 | +use think\Validate; | ||
6 | + | ||
7 | +class Vipdaynum extends Validate | ||
8 | +{ | ||
9 | + /** | ||
10 | + * 验证规则 | ||
11 | + */ | ||
12 | + protected $rule = [ | ||
13 | + ]; | ||
14 | + /** | ||
15 | + * 提示消息 | ||
16 | + */ | ||
17 | + protected $message = [ | ||
18 | + ]; | ||
19 | + /** | ||
20 | + * 验证场景 | ||
21 | + */ | ||
22 | + protected $scene = [ | ||
23 | + 'add' => [], | ||
24 | + 'edit' => [], | ||
25 | + ]; | ||
26 | + | ||
27 | +} |
application/admin/validate/Viporder.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\validate; | ||
4 | + | ||
5 | +use think\Validate; | ||
6 | + | ||
7 | +class Viporder extends Validate | ||
8 | +{ | ||
9 | + /** | ||
10 | + * 验证规则 | ||
11 | + */ | ||
12 | + protected $rule = [ | ||
13 | + ]; | ||
14 | + /** | ||
15 | + * 提示消息 | ||
16 | + */ | ||
17 | + protected $message = [ | ||
18 | + ]; | ||
19 | + /** | ||
20 | + * 验证场景 | ||
21 | + */ | ||
22 | + protected $scene = [ | ||
23 | + 'add' => [], | ||
24 | + 'edit' => [], | ||
25 | + ]; | ||
26 | + | ||
27 | +} |
1 | +<style type="text/css"> | ||
2 | + #schedulepicker { | ||
3 | + padding-top:7px; | ||
4 | + } | ||
5 | +</style> | ||
6 | +<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action=""> | ||
7 | + <div class="form-group"> | ||
8 | + <label for="name" class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label> | ||
9 | + <div class="col-xs-12 col-sm-8"> | ||
10 | + <input type="text" class="form-control" id="title" name="row[title]" value="" data-rule="required" /> | ||
11 | + </div> | ||
12 | + </div> | ||
13 | + <div class="form-group"> | ||
14 | + <label for="name" class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label> | ||
15 | + <div class="col-xs-12 col-sm-8"> | ||
16 | + {:build_select('row[type]', $typeList, null, ['class'=>'form-control', 'data-rule'=>'required'])} | ||
17 | + </div> | ||
18 | + </div> | ||
19 | + <div class="form-group"> | ||
20 | + <label for="content" class="control-label col-xs-12 col-sm-2">{:__('Content')}:</label> | ||
21 | + <div class="col-xs-12 col-sm-8"> | ||
22 | + <textarea name="row[content]" id="conent" cols="30" rows="5" class="form-control" data-rule="required"></textarea> | ||
23 | + </div> | ||
24 | + </div> | ||
25 | + <div class="form-group"> | ||
26 | + <label for="schedule" class="control-label col-xs-12 col-sm-2">{:__('Schedule')}:</label> | ||
27 | + <div class="col-xs-12 col-sm-8"> | ||
28 | + <div class="input-group margin-bottom-sm"> | ||
29 | + <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)"/> | ||
30 | + <span class="input-group-btn"> | ||
31 | + <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> | ||
32 | + </span> | ||
33 | + <span class="msg-box n-right"></span> | ||
34 | + </div> | ||
35 | + <div id="schedulepicker"> | ||
36 | + <pre><code>* * * * * | ||
37 | +- - - - - | ||
38 | +| | | | +--- day of week (0 - 7) (Sunday=0 or 7) | ||
39 | +| | | +-------- month (1 - 12) | ||
40 | +| | +------------- day of month (1 - 31) | ||
41 | +| +------------------ hour (0 - 23) | ||
42 | ++----------------------- min (0 - 59)</code></pre> | ||
43 | + <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> | ||
44 | + <ol id="scheduleresult" class="list-group"> | ||
45 | + </ol> | ||
46 | + </div> | ||
47 | + </div> | ||
48 | + </div> | ||
49 | + <div class="form-group"> | ||
50 | + <label for="maximums" class="control-label col-xs-12 col-sm-2">{:__('Maximums')}:</label> | ||
51 | + <div class="col-xs-12 col-sm-4"> | ||
52 | + <input type="number" class="form-control" id="maximums" name="row[maximums]" value="0" data-rule="required" size="6" /> | ||
53 | + </div> | ||
54 | + </div> | ||
55 | + <div class="form-group"> | ||
56 | + <label for="begintime" class="control-label col-xs-12 col-sm-2">{:__('Begin time')}:</label> | ||
57 | + <div class="col-xs-12 col-sm-4"> | ||
58 | + <input type="text" class="form-control datetimepicker" id="begintime" name="row[begintime]" value="" data-rule="{:__('Begin time')}:required" size="6" /> | ||
59 | + </div> | ||
60 | + </div> | ||
61 | + <div class="form-group"> | ||
62 | + <label for="endtime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label> | ||
63 | + <div class="col-xs-12 col-sm-4"> | ||
64 | + <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" /> | ||
65 | + </div> | ||
66 | + </div> | ||
67 | + <div class="form-group"> | ||
68 | + <label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label> | ||
69 | + <div class="col-xs-12 col-sm-4"> | ||
70 | + <input type="text" class="form-control" id="weigh" name="row[weigh]" value="0" data-rule="required" size="6" /> | ||
71 | + </div> | ||
72 | + </div> | ||
73 | + <div class="form-group"> | ||
74 | + <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> | ||
75 | + <div class="col-xs-12 col-sm-8"> | ||
76 | + {:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])} | ||
77 | + </div> | ||
78 | + </div> | ||
79 | + <div class="form-group hide layer-footer"> | ||
80 | + <label class="control-label col-xs-12 col-sm-2"></label> | ||
81 | + <div class="col-xs-12 col-sm-8"> | ||
82 | + <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> | ||
83 | + <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> | ||
84 | + </div> | ||
85 | + </div> | ||
86 | + | ||
87 | +</form> |
1 | +<style type="text/css"> | ||
2 | + #schedulepicker { | ||
3 | + padding-top: 7px; | ||
4 | + } | ||
5 | +</style> | ||
6 | +<form id="edit-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action=""> | ||
7 | + <div class="form-group"> | ||
8 | + <label for="name" class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label> | ||
9 | + <div class="col-xs-12 col-sm-8"> | ||
10 | + <input type="text" class="form-control" id="title" name="row[title]" value="{$row.title}" data-rule="required"/> | ||
11 | + </div> | ||
12 | + </div> | ||
13 | + <div class="form-group"> | ||
14 | + <label for="name" class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label> | ||
15 | + <div class="col-xs-12 col-sm-8"> | ||
16 | + {:build_select('row[type]', $typeList, $row['type'], ['class'=>'form-control', 'data-rule'=>'required'])} | ||
17 | + </div> | ||
18 | + </div> | ||
19 | + <div class="form-group"> | ||
20 | + <label for="content" class="control-label col-xs-12 col-sm-2">{:__('Content')}:</label> | ||
21 | + <div class="col-xs-12 col-sm-8"> | ||
22 | + <textarea name="row[content]" id="conent" cols="30" rows="5" class="form-control" data-rule="required">{$row.content}</textarea> | ||
23 | + </div> | ||
24 | + </div> | ||
25 | + <div class="form-group"> | ||
26 | + <label for="schedule" class="control-label col-xs-12 col-sm-2">{:__('Schedule')}:</label> | ||
27 | + <div class="col-xs-12 col-sm-8"> | ||
28 | + <div class="input-group margin-bottom-sm"> | ||
29 | + <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)"/> | ||
30 | + <span class="input-group-btn"> | ||
31 | + <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> | ||
32 | + </span> | ||
33 | + <span class="msg-box n-right"></span> | ||
34 | + </div> | ||
35 | + | ||
36 | + <div id="schedulepicker"> | ||
37 | + <pre><code>* * * * * | ||
38 | +- - - - - | ||
39 | +| | | | +--- day of week (0 - 7) (Sunday=0 or 7) | ||
40 | +| | | +-------- month (1 - 12) | ||
41 | +| | +------------- day of month (1 - 31) | ||
42 | +| +------------------ hour (0 - 23) | ||
43 | ++----------------------- min (0 - 59)</code></pre> | ||
44 | + <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> | ||
45 | + <ol id="scheduleresult" class="list-group"> | ||
46 | + </ol> | ||
47 | + </div> | ||
48 | + </div> | ||
49 | + </div> | ||
50 | + <div class="form-group"> | ||
51 | + <label for="maximums" class="control-label col-xs-12 col-sm-2">{:__('Maximums')}:</label> | ||
52 | + <div class="col-xs-12 col-sm-4"> | ||
53 | + <input type="number" class="form-control" id="maximums" name="row[maximums]" value="{$row.maximums}" data-rule="required" size="6"/> | ||
54 | + </div> | ||
55 | + </div> | ||
56 | + <div class="form-group"> | ||
57 | + <label for="begintime" class="control-label col-xs-12 col-sm-2">{:__('Begin time')}:</label> | ||
58 | + <div class="col-xs-12 col-sm-4"> | ||
59 | + <input type="text" class="form-control datetimepicker" id="begintime" name="row[begintime]" value="{$row.begintime|datetime}" data-rule="{:__('Begin time')}:required" size="6"/> | ||
60 | + </div> | ||
61 | + </div> | ||
62 | + <div class="form-group"> | ||
63 | + <label for="endtime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label> | ||
64 | + <div class="col-xs-12 col-sm-4"> | ||
65 | + <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"/> | ||
66 | + </div> | ||
67 | + </div> | ||
68 | + <div class="form-group"> | ||
69 | + <label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label> | ||
70 | + <div class="col-xs-12 col-sm-4"> | ||
71 | + <input type="text" class="form-control" id="weigh" name="row[weigh]" value="{$row.weigh}" data-rule="required" size="6"/> | ||
72 | + </div> | ||
73 | + </div> | ||
74 | + <div class="form-group"> | ||
75 | + <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> | ||
76 | + <div class="col-xs-12 col-sm-8"> | ||
77 | + {:build_radios('row[status]', ['normal'=>__('Normal'), 'completed'=>__('Completed'), 'expired'=>__('Expired'), 'hidden'=>__('Hidden')], $row['status'])} | ||
78 | + </div> | ||
79 | + </div> | ||
80 | + <div class="form-group hide layer-footer"> | ||
81 | + <label class="control-label col-xs-12 col-sm-2"></label> | ||
82 | + <div class="col-xs-12 col-sm-8"> | ||
83 | + <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> | ||
84 | + <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> | ||
85 | + </div> | ||
86 | + </div> | ||
87 | + | ||
88 | +</form> |
1 | +<div class="panel panel-default panel-intro"> | ||
2 | + | ||
3 | + <div class="panel-heading"> | ||
4 | + {:build_heading(null,FALSE)} | ||
5 | + <ul class="nav nav-tabs" data-field="type"> | ||
6 | + <li class="active"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li> | ||
7 | + {foreach name="typeList" item="vo"} | ||
8 | + <li><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li> | ||
9 | + {/foreach} | ||
10 | + </ul> | ||
11 | + </div> | ||
12 | + | ||
13 | + <div class="panel-body"> | ||
14 | + <div id="myTabContent" class="tab-content"> | ||
15 | + <div class="tab-pane fade active in" id="one"> | ||
16 | + <div class="widget-body no-padding"> | ||
17 | + <div id="toolbar" class="toolbar"> | ||
18 | + {:build_toolbar('refresh,add,edit,del')} | ||
19 | + </div> | ||
20 | + <table id="table" class="table table-striped table-bordered table-hover" | ||
21 | + data-operate-edit="{:$auth->check('general/crontab/edit')}" | ||
22 | + data-operate-del="{:$auth->check('general/crontab/del')}" | ||
23 | + width="100%"> | ||
24 | + </table> | ||
25 | + </div> | ||
26 | + </div> | ||
27 | + | ||
28 | + </div> | ||
29 | + </div> | ||
30 | +</div> |
1 | +<style type="text/css"> | ||
2 | + #schedulepicker { | ||
3 | + padding-top:7px; | ||
4 | + } | ||
5 | +</style> | ||
6 | +<form id="edit-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action=""> | ||
7 | + <div class="form-group"> | ||
8 | + <label for="content" class="control-label col-xs-12 col-sm-2">{:__('Content')}:</label> | ||
9 | + <div class="col-xs-12 col-sm-10"> | ||
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> | ||
11 | + </div> | ||
12 | + </div> | ||
13 | + <div class="form-group"> | ||
14 | + <label for="executetime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label> | ||
15 | + <div class="col-xs-12 col-sm-4"> | ||
16 | + <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 /> | ||
17 | + </div> | ||
18 | + </div> | ||
19 | + <div class="form-group"> | ||
20 | + <label for="completetime" class="control-label col-xs-12 col-sm-2">{:__('End time')}:</label> | ||
21 | + <div class="col-xs-12 col-sm-4"> | ||
22 | + <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 /> | ||
23 | + </div> | ||
24 | + </div> | ||
25 | + <div class="form-group"> | ||
26 | + <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> | ||
27 | + <div class="col-xs-12 col-sm-8"> | ||
28 | + <div style="padding-top:8px;"> | ||
29 | + {if $row['status']=='success'}<span class="label label-success">{:__('Success')}</span>{else/}<span class="label label-danger">{:__('Failure')}</span>{/if} | ||
30 | + </div> | ||
31 | + </div> | ||
32 | + </div> | ||
33 | + <div class="form-group hide layer-footer"> | ||
34 | + <label class="control-label col-xs-12 col-sm-2"></label> | ||
35 | + <div class="col-xs-12 col-sm-8"> | ||
36 | + <button type="button" class="btn btn-success btn-embossed" onclick="parent.Layer.close(parent.Layer.getFrameIndex(window.name))">{:__('Close')}</button> | ||
37 | + </div> | ||
38 | + </div> | ||
39 | + | ||
40 | +</form> |
1 | +<div class="panel panel-default panel-intro"> | ||
2 | + | ||
3 | + <div class="panel-heading"> | ||
4 | + {:build_heading(null,FALSE)} | ||
5 | + <ul class="nav nav-tabs" data-field="status"> | ||
6 | + <li class="active"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li> | ||
7 | + {foreach name="statusList" item="vo"} | ||
8 | + <li><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li> | ||
9 | + {/foreach} | ||
10 | + </ul> | ||
11 | + </div> | ||
12 | + | ||
13 | + <div class="panel-body"> | ||
14 | + <div id="myTabContent" class="tab-content"> | ||
15 | + <div class="tab-pane fade active in" id="one"> | ||
16 | + <div class="widget-body no-padding"> | ||
17 | + <div id="toolbar" class="toolbar"> | ||
18 | + {:build_toolbar('refresh,del')} | ||
19 | + </div> | ||
20 | + <table id="table" class="table table-striped table-bordered table-hover" | ||
21 | + data-operate-detail="{:$auth->check('general/crontab/detail')}" | ||
22 | + data-operate-del="{:$auth->check('general/crontab/del')}" | ||
23 | + width="100%"> | ||
24 | + </table> | ||
25 | + </div> | ||
26 | + </div> | ||
27 | + | ||
28 | + </div> | ||
29 | + </div> | ||
30 | +</div> |
@@ -6,6 +6,18 @@ | @@ -6,6 +6,18 @@ | ||
6 | <textarea id="c-content" class="form-control editor" rows="5" name="row[content]" cols="50"></textarea> | 6 | <textarea id="c-content" class="form-control editor" rows="5" name="row[content]" cols="50"></textarea> |
7 | </div> | 7 | </div> |
8 | </div> | 8 | </div> |
9 | + <div class="form-group"> | ||
10 | + <label class="control-label col-xs-12 col-sm-2">{:__('会员权益')}:</label> | ||
11 | + <div class="col-xs-12 col-sm-8"> | ||
12 | + <textarea id="c-desc" class="form-control editor" rows="5" name="row[desc]" cols="50"></textarea> | ||
13 | + </div> | ||
14 | + </div> | ||
15 | + <div class="form-group"> | ||
16 | + <label class="control-label col-xs-12 col-sm-2">{:__('操作说明')}:</label> | ||
17 | + <div class="col-xs-12 col-sm-8"> | ||
18 | + <textarea id="c-explain" class="form-control editor" rows="5" name="row[explain]" cols="50"></textarea> | ||
19 | + </div> | ||
20 | + </div> | ||
9 | <div class="form-group layer-footer"> | 21 | <div class="form-group layer-footer"> |
10 | <label class="control-label col-xs-12 col-sm-2"></label> | 22 | <label class="control-label col-xs-12 col-sm-2"></label> |
11 | <div class="col-xs-12 col-sm-8"> | 23 | <div class="col-xs-12 col-sm-8"> |
@@ -6,6 +6,18 @@ | @@ -6,6 +6,18 @@ | ||
6 | <textarea id="c-content" class="form-control editor" rows="5" name="row[content]" cols="50">{$row.content|htmlentities}</textarea> | 6 | <textarea id="c-content" class="form-control editor" rows="5" name="row[content]" cols="50">{$row.content|htmlentities}</textarea> |
7 | </div> | 7 | </div> |
8 | </div> | 8 | </div> |
9 | + <div class="form-group"> | ||
10 | + <label class="control-label col-xs-12 col-sm-2">{:__('会员权益')}:</label> | ||
11 | + <div class="col-xs-12 col-sm-8"> | ||
12 | + <textarea id="c-desc" class="form-control editor" rows="5" name="row[desc]" cols="50">{$row.desc|htmlentities}</textarea> | ||
13 | + </div> | ||
14 | + </div> | ||
15 | + <div class="form-group"> | ||
16 | + <label class="control-label col-xs-12 col-sm-2">{:__('操作说明')}:</label> | ||
17 | + <div class="col-xs-12 col-sm-8"> | ||
18 | + <textarea id="c-explain" class="form-control editor" rows="5" name="row[explain]" cols="50">{$row.explain|htmlentities}</textarea> | ||
19 | + </div> | ||
20 | + </div> | ||
9 | <div class="form-group layer-footer"> | 21 | <div class="form-group layer-footer"> |
10 | <label class="control-label col-xs-12 col-sm-2"></label> | 22 | <label class="control-label col-xs-12 col-sm-2"></label> |
11 | <div class="col-xs-12 col-sm-8"> | 23 | <div class="col-xs-12 col-sm-8"> |
application/admin/view/payimage/add.html
0 → 100644
1 | +<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action=""> | ||
2 | + | ||
3 | + <div class="form-group"> | ||
4 | + <label class="control-label col-xs-12 col-sm-2">{:__('Image')}:</label> | ||
5 | + <div class="col-xs-12 col-sm-8"> | ||
6 | + <div class="input-group"> | ||
7 | + <input id="c-image" class="form-control" size="50" name="row[image]" type="text"> | ||
8 | + <div class="input-group-addon no-border no-padding"> | ||
9 | + <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> | ||
10 | + <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> | ||
11 | + </div> | ||
12 | + <span class="msg-box n-right" for="c-image"></span> | ||
13 | + </div> | ||
14 | + <ul class="row list-inline plupload-preview" id="p-image"></ul> | ||
15 | + </div> | ||
16 | + </div> | ||
17 | + <div class="form-group"> | ||
18 | + <label class="control-label col-xs-12 col-sm-2">{:__('Aliimage')}:</label> | ||
19 | + <div class="col-xs-12 col-sm-8"> | ||
20 | + <div class="input-group"> | ||
21 | + <input id="c-aliimage" class="form-control" size="50" name="row[aliimage]" type="text"> | ||
22 | + <div class="input-group-addon no-border no-padding"> | ||
23 | + <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> | ||
24 | + <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> | ||
25 | + </div> | ||
26 | + <span class="msg-box n-right" for="c-aliimage"></span> | ||
27 | + </div> | ||
28 | + <ul class="row list-inline plupload-preview" id="p-aliimage"></ul> | ||
29 | + </div> | ||
30 | + </div> | ||
31 | + <div class="form-group layer-footer"> | ||
32 | + <label class="control-label col-xs-12 col-sm-2"></label> | ||
33 | + <div class="col-xs-12 col-sm-8"> | ||
34 | + <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> | ||
35 | + <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> | ||
36 | + </div> | ||
37 | + </div> | ||
38 | +</form> |
application/admin/view/payimage/edit.html
0 → 100644
1 | +<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action=""> | ||
2 | + | ||
3 | + <div class="form-group"> | ||
4 | + <label class="control-label col-xs-12 col-sm-2">{:__('Image')}:</label> | ||
5 | + <div class="col-xs-12 col-sm-8"> | ||
6 | + <div class="input-group"> | ||
7 | + <input id="c-image" class="form-control" size="50" name="row[image]" type="text" value="{$row.image|htmlentities}"> | ||
8 | + <div class="input-group-addon no-border no-padding"> | ||
9 | + <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> | ||
10 | + <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> | ||
11 | + </div> | ||
12 | + <span class="msg-box n-right" for="c-image"></span> | ||
13 | + </div> | ||
14 | + <ul class="row list-inline plupload-preview" id="p-image"></ul> | ||
15 | + </div> | ||
16 | + </div> | ||
17 | + <div class="form-group"> | ||
18 | + <label class="control-label col-xs-12 col-sm-2">{:__('Aliimage')}:</label> | ||
19 | + <div class="col-xs-12 col-sm-8"> | ||
20 | + <div class="input-group"> | ||
21 | + <input id="c-aliimage" class="form-control" size="50" name="row[aliimage]" type="text" value="{$row.aliimage|htmlentities}"> | ||
22 | + <div class="input-group-addon no-border no-padding"> | ||
23 | + <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> | ||
24 | + <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> | ||
25 | + </div> | ||
26 | + <span class="msg-box n-right" for="c-aliimage"></span> | ||
27 | + </div> | ||
28 | + <ul class="row list-inline plupload-preview" id="p-aliimage"></ul> | ||
29 | + </div> | ||
30 | + </div> | ||
31 | + <div class="form-group layer-footer"> | ||
32 | + <label class="control-label col-xs-12 col-sm-2"></label> | ||
33 | + <div class="col-xs-12 col-sm-8"> | ||
34 | + <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> | ||
35 | + <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> | ||
36 | + </div> | ||
37 | + </div> | ||
38 | +</form> |
application/admin/view/payimage/index.html
0 → 100644
1 | +<div class="panel panel-default panel-intro"> | ||
2 | + {:build_heading()} | ||
3 | + | ||
4 | + <div class="panel-body"> | ||
5 | + <div id="myTabContent" class="tab-content"> | ||
6 | + <div class="tab-pane fade active in" id="one"> | ||
7 | + <div class="widget-body no-padding"> | ||
8 | + <div id="toolbar" class="toolbar"> | ||
9 | + <a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a> | ||
10 | + <!--<a href="javascript:;" class="btn btn-success btn-add {:$auth->check('payimage/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>--> | ||
11 | + <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> | ||
12 | + <!--<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>--> | ||
13 | + <!--<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>--> | ||
14 | + | ||
15 | + <!--<div class="dropdown btn-group {:$auth->check('payimage/multi')?'':'hide'}">--> | ||
16 | + <!--<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>--> | ||
17 | + <!--<ul class="dropdown-menu text-left" role="menu">--> | ||
18 | + <!--<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>--> | ||
19 | + <!--<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>--> | ||
20 | + <!--</ul>--> | ||
21 | + <!--</div>--> | ||
22 | + | ||
23 | + | ||
24 | + </div> | ||
25 | + <table id="table" class="table table-striped table-bordered table-hover table-nowrap" | ||
26 | + data-operate-edit="{:$auth->check('payimage/edit')}" | ||
27 | + data-operate-del="{:$auth->check('payimage/del')}" | ||
28 | + width="100%"> | ||
29 | + </table> | ||
30 | + </div> | ||
31 | + </div> | ||
32 | + | ||
33 | + </div> | ||
34 | + </div> | ||
35 | +</div> |
application/admin/view/vipdaynum/add.html
0 → 100644
1 | +<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action=""> | ||
2 | + | ||
3 | + <div class="form-group"> | ||
4 | + <label class="control-label col-xs-12 col-sm-2">{:__('Day_num')}:</label> | ||
5 | + <div class="col-xs-12 col-sm-8"> | ||
6 | + <input id="c-day_num" class="form-control" name="row[day_num]" type="number"> | ||
7 | + </div> | ||
8 | + </div> | ||
9 | + <div class="form-group layer-footer"> | ||
10 | + <label class="control-label col-xs-12 col-sm-2"></label> | ||
11 | + <div class="col-xs-12 col-sm-8"> | ||
12 | + <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> | ||
13 | + <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> | ||
14 | + </div> | ||
15 | + </div> | ||
16 | +</form> |
application/admin/view/vipdaynum/edit.html
0 → 100644
1 | +<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action=""> | ||
2 | + | ||
3 | + <div class="form-group"> | ||
4 | + <label class="control-label col-xs-12 col-sm-2">{:__('Day_num')}:</label> | ||
5 | + <div class="col-xs-12 col-sm-8"> | ||
6 | + <input id="c-day_num" class="form-control" name="row[day_num]" type="number" value="{$row.day_num|htmlentities}"> | ||
7 | + </div> | ||
8 | + </div> | ||
9 | + <div class="form-group layer-footer"> | ||
10 | + <label class="control-label col-xs-12 col-sm-2"></label> | ||
11 | + <div class="col-xs-12 col-sm-8"> | ||
12 | + <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> | ||
13 | + <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> | ||
14 | + </div> | ||
15 | + </div> | ||
16 | +</form> |
application/admin/view/vipdaynum/index.html
0 → 100644
1 | +<div class="panel panel-default panel-intro"> | ||
2 | + {:build_heading()} | ||
3 | + | ||
4 | + <div class="panel-body"> | ||
5 | + <div id="myTabContent" class="tab-content"> | ||
6 | + <div class="tab-pane fade active in" id="one"> | ||
7 | + <div class="widget-body no-padding"> | ||
8 | + <div id="toolbar" class="toolbar"> | ||
9 | + <a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a> | ||
10 | + <!--<a href="javascript:;" class="btn btn-success btn-add {:$auth->check('vipdaynum/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>--> | ||
11 | + <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> | ||
12 | + <!--<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>--> | ||
13 | + <!--<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>--> | ||
14 | + | ||
15 | + <!--<div class="dropdown btn-group {:$auth->check('vipdaynum/multi')?'':'hide'}">--> | ||
16 | + <!--<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>--> | ||
17 | + <!--<ul class="dropdown-menu text-left" role="menu">--> | ||
18 | + <!--<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>--> | ||
19 | + <!--<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>--> | ||
20 | + <!--</ul>--> | ||
21 | + <!--</div>--> | ||
22 | + | ||
23 | + | ||
24 | + </div> | ||
25 | + <table id="table" class="table table-striped table-bordered table-hover table-nowrap" | ||
26 | + data-operate-edit="{:$auth->check('vipdaynum/edit')}" | ||
27 | + data-operate-del="{:$auth->check('vipdaynum/del')}" | ||
28 | + width="100%"> | ||
29 | + </table> | ||
30 | + </div> | ||
31 | + </div> | ||
32 | + | ||
33 | + </div> | ||
34 | + </div> | ||
35 | +</div> |
application/admin/view/viporder/add.html
0 → 100644
1 | +<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action=""> | ||
2 | + | ||
3 | + <div class="form-group"> | ||
4 | + <label class="control-label col-xs-12 col-sm-2">{:__('User_id')}:</label> | ||
5 | + <div class="col-xs-12 col-sm-8"> | ||
6 | + <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=""> | ||
7 | + </div> | ||
8 | + </div> | ||
9 | + <div class="form-group"> | ||
10 | + <label class="control-label col-xs-12 col-sm-2">{:__('Order_num')}:</label> | ||
11 | + <div class="col-xs-12 col-sm-8"> | ||
12 | + <input id="c-order_num" class="form-control" name="row[order_num]" type="text"> | ||
13 | + </div> | ||
14 | + </div> | ||
15 | + <div class="form-group"> | ||
16 | + <label class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label> | ||
17 | + <div class="col-xs-12 col-sm-8"> | ||
18 | + <input id="c-type" class="form-control" name="row[type]" type="number"> | ||
19 | + </div> | ||
20 | + </div> | ||
21 | + <div class="form-group"> | ||
22 | + <label class="control-label col-xs-12 col-sm-2">{:__('Daynum')}:</label> | ||
23 | + <div class="col-xs-12 col-sm-8"> | ||
24 | + <input id="c-daynum" class="form-control" name="row[daynum]" type="number"> | ||
25 | + </div> | ||
26 | + </div> | ||
27 | + <div class="form-group"> | ||
28 | + <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> | ||
29 | + <div class="col-xs-12 col-sm-8"> | ||
30 | + <input id="c-status" class="form-control" name="row[status]" type="number" value="0"> | ||
31 | + </div> | ||
32 | + </div> | ||
33 | + <div class="form-group layer-footer"> | ||
34 | + <label class="control-label col-xs-12 col-sm-2"></label> | ||
35 | + <div class="col-xs-12 col-sm-8"> | ||
36 | + <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> | ||
37 | + <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> | ||
38 | + </div> | ||
39 | + </div> | ||
40 | +</form> |
application/admin/view/viporder/edit.html
0 → 100644
1 | +<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action=""> | ||
2 | + | ||
3 | + <!--<div class="form-group">--> | ||
4 | + <!--<label class="control-label col-xs-12 col-sm-2">{:__('User_id')}:</label>--> | ||
5 | + <!--<div class="col-xs-12 col-sm-8">--> | ||
6 | + <!--<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}">--> | ||
7 | + <!--</div>--> | ||
8 | + <!--</div>--> | ||
9 | + <!--<div class="form-group">--> | ||
10 | + <!--<label class="control-label col-xs-12 col-sm-2">{:__('Order_num')}:</label>--> | ||
11 | + <!--<div class="col-xs-12 col-sm-8">--> | ||
12 | + <!--<input id="c-order_num" class="form-control" name="row[order_num]" type="text" value="{$row.order_num|htmlentities}">--> | ||
13 | + <!--</div>--> | ||
14 | + <!--</div>--> | ||
15 | + <!--<div class="form-group">--> | ||
16 | + <!--<label class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label>--> | ||
17 | + <!--<div class="col-xs-12 col-sm-8">--> | ||
18 | + <!--<input id="c-type" class="form-control" name="row[type]" type="number" value="{$row.type|htmlentities}">--> | ||
19 | + <!--</div>--> | ||
20 | + <!--</div>--> | ||
21 | + <!--<div class="form-group">--> | ||
22 | + <!--<label class="control-label col-xs-12 col-sm-2">{:__('Daynum')}:</label>--> | ||
23 | + <!--<div class="col-xs-12 col-sm-8">--> | ||
24 | + <!--<input id="c-daynum" class="form-control" name="row[daynum]" type="number" value="{$row.daynum|htmlentities}">--> | ||
25 | + <!--</div>--> | ||
26 | + <!--</div>--> | ||
27 | + <div class="form-group"> | ||
28 | + <label class="control-label col-xs-12 col-sm-2">{:__('审核状态')}:</label> | ||
29 | + <div class="col-xs-12 col-sm-8"> | ||
30 | + {:build_radios('row[status]', ['0'=>'待审核','1'=>'通过','2'=>'未通过'], $row['status'])} | ||
31 | + </div> | ||
32 | + </div> | ||
33 | + <div class="form-group layer-footer"> | ||
34 | + <label class="control-label col-xs-12 col-sm-2"></label> | ||
35 | + <div class="col-xs-12 col-sm-8"> | ||
36 | + <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> | ||
37 | + <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> | ||
38 | + </div> | ||
39 | + </div> | ||
40 | +</form> |
application/admin/view/viporder/index.html
0 → 100644
1 | +<div class="panel panel-default panel-intro"> | ||
2 | + {:build_heading()} | ||
3 | + | ||
4 | + <div class="panel-body"> | ||
5 | + <div id="myTabContent" class="tab-content"> | ||
6 | + <div class="tab-pane fade active in" id="one"> | ||
7 | + <div class="widget-body no-padding"> | ||
8 | + <div id="toolbar" class="toolbar"> | ||
9 | + <a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a> | ||
10 | + <!--<a href="javascript:;" class="btn btn-success btn-add {:$auth->check('viporder/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>--> | ||
11 | + <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> | ||
12 | + <!--<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>--> | ||
13 | + <!--<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>--> | ||
14 | + | ||
15 | + <!--<div class="dropdown btn-group {:$auth->check('viporder/multi')?'':'hide'}">--> | ||
16 | + <!--<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>--> | ||
17 | + <!--<ul class="dropdown-menu text-left" role="menu">--> | ||
18 | + <!--<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>--> | ||
19 | + <!--<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>--> | ||
20 | + <!--</ul>--> | ||
21 | + <!--</div>--> | ||
22 | + | ||
23 | + | ||
24 | + </div> | ||
25 | + <table id="table" class="table table-striped table-bordered table-hover table-nowrap" | ||
26 | + data-operate-edit="{:$auth->check('viporder/edit')}" | ||
27 | + data-operate-del="{:$auth->check('viporder/del')}" | ||
28 | + width="100%"> | ||
29 | + </table> | ||
30 | + </div> | ||
31 | + </div> | ||
32 | + | ||
33 | + </div> | ||
34 | + </div> | ||
35 | +</div> |
@@ -2,6 +2,7 @@ | @@ -2,6 +2,7 @@ | ||
2 | 2 | ||
3 | namespace app\api\controller; | 3 | namespace app\api\controller; |
4 | 4 | ||
5 | +use app\admin\controller\general\Attachment; | ||
5 | use app\common\controller\Api; | 6 | use app\common\controller\Api; |
6 | use app\common\model\Area; | 7 | use app\common\model\Area; |
7 | use app\common\model\Version; | 8 | use app\common\model\Version; |
@@ -47,75 +48,68 @@ class Common extends Api | @@ -47,75 +48,68 @@ class Common extends Api | ||
47 | */ | 48 | */ |
48 | public function upload() | 49 | public function upload() |
49 | { | 50 | { |
51 | + Config::set('default_return_type', 'json'); | ||
52 | + $config = get_addon_config('qiniu'); | ||
53 | + | ||
50 | $file = $this->request->file('file'); | 54 | $file = $this->request->file('file'); |
51 | - if (empty($file)) { | ||
52 | - $this->error(__('No file upload or server upload limit exceeded')); | 55 | + if (!$file || !$file->isValid()) { |
56 | + $this->error("请上传有效的文件"); | ||
53 | } | 57 | } |
58 | + $fileInfo = $file->getInfo(); | ||
54 | 59 | ||
55 | - //判断是否已经存在附件 | ||
56 | - $sha1 = $file->hash(); | ||
57 | - | ||
58 | - $upload = Config::get('upload'); | 60 | + $filePath = $file->getRealPath() ?: $file->getPathname(); |
59 | 61 | ||
60 | - preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches); | 62 | + preg_match('/(\d+)(\w+)/', $config['maxsize'], $matches); |
61 | $type = strtolower($matches[2]); | 63 | $type = strtolower($matches[2]); |
62 | $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3]; | 64 | $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3]; |
63 | - $size = (int)$upload['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0); | ||
64 | - $fileInfo = $file->getInfo(); | 65 | + $size = (int)$config['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0); |
66 | + | ||
65 | $suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION)); | 67 | $suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION)); |
66 | - $suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file'; | 68 | + $suffix = $suffix ? $suffix : 'file'; |
67 | 69 | ||
68 | - $mimetypeArr = explode(',', strtolower($upload['mimetype'])); | 70 | + $md5 = md5_file($filePath); |
71 | + $search = ['$(year)', '$(mon)', '$(day)', '$(etag)', '$(ext)']; | ||
72 | + $replace = [date("Y"), date("m"), date("d"), $md5, '.' . $suffix]; | ||
73 | + $object = ltrim(str_replace($search, $replace, $config['savekey']), '/'); | ||
74 | + | ||
75 | + $mimetypeArr = explode(',', strtolower($config['mimetype'])); | ||
69 | $typeArr = explode('/', $fileInfo['type']); | 76 | $typeArr = explode('/', $fileInfo['type']); |
70 | 77 | ||
71 | - //禁止上传PHP和HTML文件 | ||
72 | - if (in_array($fileInfo['type'], ['text/x-php', 'text/html']) || in_array($suffix, ['php', 'html', 'htm'])) { | ||
73 | - $this->error(__('Uploaded file format is limited')); | 78 | + //检查文件大小 |
79 | + if (!$file->checkSize($size)) { | ||
80 | + $this->error("起过最大可上传文件限制"); | ||
74 | } | 81 | } |
82 | + | ||
75 | //验证文件后缀 | 83 | //验证文件后缀 |
76 | - if ($upload['mimetype'] !== '*' && | 84 | + if ($config['mimetype'] !== '*' && |
77 | ( | 85 | ( |
78 | !in_array($suffix, $mimetypeArr) | 86 | !in_array($suffix, $mimetypeArr) |
79 | - || (stripos($typeArr[0] . '/', $upload['mimetype']) !== false && (!in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr))) | 87 | + || (stripos($typeArr[0] . '/', $config['mimetype']) !== false && (!in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr))) |
80 | ) | 88 | ) |
81 | ) { | 89 | ) { |
82 | - $this->error(__('Uploaded file format is limited')); | ||
83 | - } | ||
84 | - //验证是否为图片文件 | ||
85 | - $imagewidth = $imageheight = 0; | ||
86 | - 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'])) { | ||
87 | - $imgInfo = getimagesize($fileInfo['tmp_name']); | ||
88 | - if (!$imgInfo || !isset($imgInfo[0]) || !isset($imgInfo[1])) { | ||
89 | - $this->error(__('Uploaded file is not a valid image')); | ||
90 | - } | ||
91 | - $imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth; | ||
92 | - $imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight; | 90 | + $this->error(__('上传格式限制')); |
93 | } | 91 | } |
94 | - $replaceArr = [ | ||
95 | - '{year}' => date("Y"), | ||
96 | - '{mon}' => date("m"), | ||
97 | - '{day}' => date("d"), | ||
98 | - '{hour}' => date("H"), | ||
99 | - '{min}' => date("i"), | ||
100 | - '{sec}' => date("s"), | ||
101 | - '{random}' => Random::alnum(16), | ||
102 | - '{random32}' => Random::alnum(32), | ||
103 | - '{filename}' => $suffix ? substr($fileInfo['name'], 0, strripos($fileInfo['name'], '.')) : $fileInfo['name'], | ||
104 | - '{suffix}' => $suffix, | ||
105 | - '{.suffix}' => $suffix ? '.' . $suffix : '', | ||
106 | - '{filemd5}' => md5_file($fileInfo['tmp_name']), | ||
107 | - ]; | ||
108 | - $savekey = $upload['savekey']; | ||
109 | - $savekey = str_replace(array_keys($replaceArr), array_values($replaceArr), $savekey); | 92 | + |
93 | + $savekey = '/' . $object; | ||
110 | 94 | ||
111 | $uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1); | 95 | $uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1); |
112 | $fileName = substr($savekey, strripos($savekey, '/') + 1); | 96 | $fileName = substr($savekey, strripos($savekey, '/') + 1); |
113 | - // | ||
114 | - $splInfo = $file->validate(['size' => $size])->move(ROOT_PATH . '/public' . $uploadDir, $fileName); | 97 | + //先上传到本地 |
98 | + $splInfo = $file->move(ROOT_PATH . '/public' . $uploadDir, $fileName); | ||
115 | if ($splInfo) { | 99 | if ($splInfo) { |
100 | + $extparam = $this->request->post(); | ||
101 | + $filePath = $splInfo->getRealPath() ?: $splInfo->getPathname(); | ||
102 | + | ||
103 | + $sha1 = sha1_file($filePath); | ||
104 | + $imagewidth = $imageheight = 0; | ||
105 | + if (in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf'])) { | ||
106 | + $imgInfo = getimagesize($splInfo->getPathname()); | ||
107 | + $imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth; | ||
108 | + $imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight; | ||
109 | + } | ||
116 | $params = array( | 110 | $params = array( |
117 | - 'admin_id' => 0, | ||
118 | - 'user_id' => (int)$this->auth->id, | 111 | + 'admin_id' => session('admin.id'), |
112 | +// 'user_id' => $this->auth->id, | ||
119 | 'filesize' => $fileInfo['size'], | 113 | 'filesize' => $fileInfo['size'], |
120 | 'imagewidth' => $imagewidth, | 114 | 'imagewidth' => $imagewidth, |
121 | 'imageheight' => $imageheight, | 115 | 'imageheight' => $imageheight, |
@@ -126,17 +120,45 @@ class Common extends Api | @@ -126,17 +120,45 @@ class Common extends Api | ||
126 | 'uploadtime' => time(), | 120 | 'uploadtime' => time(), |
127 | 'storage' => 'local', | 121 | 'storage' => 'local', |
128 | 'sha1' => $sha1, | 122 | 'sha1' => $sha1, |
123 | + 'extparam' => json_encode($extparam), | ||
129 | ); | 124 | ); |
130 | - $attachment = model("attachment"); | ||
131 | - $attachment->data(array_filter($params)); | 125 | + $attachment = \app\common\model\Attachment::create(array_filter($params), true); |
126 | + $policy = array( | ||
127 | + 'saveKey' => ltrim($savekey, '/'), | ||
128 | + ); | ||
129 | + $auth = new \addons\qiniu\library\Auth($config['app_key'], $config['secret_key']); | ||
130 | + $token = $auth->uploadToken($config['bucket'], null, $config['expire'], $policy); | ||
131 | + $multipart = [ | ||
132 | + ['name' => 'token', 'contents' => $token], | ||
133 | + [ | ||
134 | + 'name' => 'file', | ||
135 | + 'contents' => fopen($filePath, 'r'), | ||
136 | + 'filename' => $fileName, | ||
137 | + ] | ||
138 | + ]; | ||
139 | + try { | ||
140 | + $client = new \GuzzleHttp\Client(); | ||
141 | + $res = $client->request('POST', $config['uploadurl'], [ | ||
142 | + 'multipart' => $multipart | ||
143 | + ]); | ||
144 | + $code = $res->getStatusCode(); | ||
145 | + //成功不做任何操作 | ||
146 | + } catch (\GuzzleHttp\Exception\ClientException $e) { | ||
147 | + $attachment->delete(); | ||
148 | + unlink($filePath); | ||
149 | + $this->error("上传失败"); | ||
150 | + } | ||
151 | + | ||
152 | + $url = '/' . $object; | ||
153 | + | ||
154 | + //上传成功后将存储变更为qiniu | ||
155 | + $attachment->storage = 'qiniu'; | ||
132 | $attachment->save(); | 156 | $attachment->save(); |
133 | - \think\Hook::listen("upload_after", $attachment); | ||
134 | - $this->success(__('Upload successful'), [ | ||
135 | - 'url' => $uploadDir . $splInfo->getSaveName() | ||
136 | - ]); | 157 | + |
158 | + $this->success("上传成功", $url); | ||
137 | } else { | 159 | } else { |
138 | - // 上传失败获取错误信息 | ||
139 | - $this->error($file->getError()); | 160 | + $this->error('上传失败'); |
140 | } | 161 | } |
162 | + return; | ||
141 | } | 163 | } |
142 | } | 164 | } |
@@ -10,7 +10,10 @@ namespace app\api\controller; | @@ -10,7 +10,10 @@ namespace app\api\controller; | ||
10 | 10 | ||
11 | 11 | ||
12 | use app\common\controller\Api; | 12 | use app\common\controller\Api; |
13 | + | ||
14 | +use Qiniu\Storage\UploadManager; | ||
13 | use think\Db; | 15 | use think\Db; |
16 | +use Qiniu\Auth; | ||
14 | 17 | ||
15 | 18 | ||
16 | /** | 19 | /** |
@@ -30,13 +33,14 @@ class Create extends Api | @@ -30,13 +33,14 @@ class Create extends Api | ||
30 | * @ApiRoute (/api/create/publish_folder) | 33 | * @ApiRoute (/api/create/publish_folder) |
31 | * | 34 | * |
32 | * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | 35 | * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") |
33 | - * @ApiParams (name="id", type="inter", required=true, description="父级文件夹id") | 36 | + * @ApiParams (name="id", type="inter", required=true, description="父级文件夹id首页为0") |
34 | * | 37 | * |
35 | * @ApiReturn({ | 38 | * @ApiReturn({ |
36 | "code": 1, | 39 | "code": 1, |
37 | "msg": "成功", | 40 | "msg": "成功", |
38 | "time": "1571492001", | 41 | "time": "1571492001", |
39 | "data": { | 42 | "data": { |
43 | + | ||
40 | } | 44 | } |
41 | ] | 45 | ] |
42 | } | 46 | } |
@@ -74,4 +78,698 @@ class Create extends Api | @@ -74,4 +78,698 @@ class Create extends Api | ||
74 | } | 78 | } |
75 | } | 79 | } |
76 | 80 | ||
81 | + /** | ||
82 | + * @ApiTitle (发布图片) | ||
83 | + * @ApiSummary (发布图片) | ||
84 | + * @ApiMethod (POST) | ||
85 | + * @ApiRoute (/api/create/publish_pic) | ||
86 | + * | ||
87 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
88 | + * @ApiParams (name="images", type="string", required=true, description="图片内容") | ||
89 | + * @ApiParams (name="folder_id", type="inter", required=true, description="存储位置id 首页为0") | ||
90 | + * | ||
91 | + * @ApiReturn({ | ||
92 | + "code": 1, | ||
93 | + "msg": "成功", | ||
94 | + "time": "1571492001", | ||
95 | + "data": { | ||
96 | + | ||
97 | + } | ||
98 | + }) | ||
99 | + */ | ||
100 | + public function publish_pic() | ||
101 | + { | ||
102 | + $user_id = $this->auth->id; | ||
103 | + $user = Db::name('user')->where('id',$user_id)->field('id,identity,audit')->find(); | ||
104 | + //判断用户身份是否审核通过 | ||
105 | + if($user['audit'] != 1){ | ||
106 | + $this->error('身份身份通过才可发布!'); | ||
107 | + } | ||
108 | + //判断用户身份是否有发布的权限 | ||
109 | + if($user['identity'] == 1){ | ||
110 | + $this->error('您的权限不足'); | ||
111 | + } | ||
112 | + $folder_id = $this->request->param('folder_id'); | ||
113 | + $images = $this->request->param('images'); | ||
114 | + if(empty($images)){ | ||
115 | + $this->error('缺少必要参数'); | ||
116 | + } | ||
117 | + //判断图片大小 | ||
118 | + $image = explode(',',$images); | ||
119 | + $count = count($image); | ||
120 | + if($count > 9){ | ||
121 | + $this->error('最多上传9张图片'); | ||
122 | + } | ||
123 | + //添加发布的文件数据表 | ||
124 | + $res['user_id'] = $user_id; | ||
125 | + $res['type'] = 2; | ||
126 | + $res['name'] = date('YmdHis'); | ||
127 | + $res['folder_id'] = $folder_id; | ||
128 | + $res['images'] = $images; | ||
129 | + $res['createtime'] = time(); | ||
130 | + $res['updatetime'] = time(); | ||
131 | + $data = Db::name('savemes')->insertGetId($res); | ||
132 | + if(empty($data)){ | ||
133 | + $this->error('发布图片失败'); | ||
134 | + }else{ | ||
135 | + $this->success('发布图片成功'); | ||
136 | + } | ||
137 | + } | ||
138 | + | ||
139 | + /** | ||
140 | + * @ApiTitle (发布视频) | ||
141 | + * @ApiSummary (发布视频) | ||
142 | + * @ApiMethod (POST) | ||
143 | + * @ApiRoute (/api/create/publish_video) | ||
144 | + * | ||
145 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
146 | + * @ApiParams (name="video", type="string", required=true, description="视频内容") | ||
147 | + * @ApiParams (name="folder_id", type="inter", required=true, description="存储位置id 首页为0") | ||
148 | + * | ||
149 | + * @ApiReturn({ | ||
150 | + "code": 1, | ||
151 | + "msg": "成功", | ||
152 | + "time": "1571492001", | ||
153 | + "data": { | ||
154 | + | ||
155 | + } | ||
156 | + }) | ||
157 | + */ | ||
158 | + public function publish_video() | ||
159 | + { | ||
160 | + $user_id = $this->auth->id; | ||
161 | + $user = Db::name('user')->where('id',$user_id)->field('id,identity,audit')->find(); | ||
162 | + //判断用户身份是否审核通过 | ||
163 | + if($user['audit'] != 1){ | ||
164 | + $this->error('身份身份通过才可发布!'); | ||
165 | + } | ||
166 | + //判断用户身份是否有发布的权限 | ||
167 | + if($user['identity'] == 1){ | ||
168 | + $this->error('您的权限不足'); | ||
169 | + } | ||
170 | + $folder_id = $this->request->param('folder_id'); | ||
171 | + $video = $this->request->param('video'); | ||
172 | + if(empty($video)){ | ||
173 | + $this->error('缺少必要参数'); | ||
174 | + } | ||
175 | + | ||
176 | + //添加发布的文件数据表 | ||
177 | + $res['user_id'] = $user_id; | ||
178 | + $res['type'] = 3; | ||
179 | + $res['name'] = date('YmdHis'); | ||
180 | + $res['folder_id'] = $folder_id; | ||
181 | + $res['video'] = $video; | ||
182 | + $res['createtime'] = time(); | ||
183 | + $res['updatetime'] = time(); | ||
184 | + $data = Db::name('savemes')->insertGetId($res); | ||
185 | + if(empty($data)){ | ||
186 | + $this->error('发布视频失败'); | ||
187 | + }else{ | ||
188 | + $this->success('发布视频成功'); | ||
189 | + } | ||
190 | + } | ||
191 | + | ||
192 | + /** | ||
193 | + * @ApiTitle (发布笔记) | ||
194 | + * @ApiSummary (发布笔记) | ||
195 | + * @ApiMethod (POST) | ||
196 | + * @ApiRoute (/api/create/publish_note) | ||
197 | + * | ||
198 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
199 | + * @ApiParams (name="content", type="string", required=true, description="笔记内容") | ||
200 | + * @ApiParams (name="folder_id", type="inter", required=true, description="存储位置id 首页为0") | ||
201 | + * | ||
202 | + * @ApiReturn({ | ||
203 | + "code": 1, | ||
204 | + "msg": "成功", | ||
205 | + "time": "1571492001", | ||
206 | + "data": { | ||
207 | + | ||
208 | + } | ||
209 | + }) | ||
210 | + */ | ||
211 | + public function publish_note() | ||
212 | + { | ||
213 | + $user_id = $this->auth->id; | ||
214 | + $user = Db::name('user')->where('id',$user_id)->field('id,identity,audit')->find(); | ||
215 | + //判断用户身份是否审核通过 | ||
216 | + if($user['audit'] != 1){ | ||
217 | + $this->error('身份身份通过才可发布!'); | ||
218 | + } | ||
219 | + //判断用户身份是否有发布的权限 | ||
220 | + if($user['identity'] == 1){ | ||
221 | + $this->error('您的权限不足'); | ||
222 | + } | ||
223 | + $folder_id = $this->request->param('folder_id'); | ||
224 | + $content = $_POST['content']; | ||
225 | + if(empty($content)){ | ||
226 | + $this->error('缺少必要参数'); | ||
227 | + } | ||
228 | + | ||
229 | + //添加发布的文件数据表 | ||
230 | + $res['user_id'] = $user_id; | ||
231 | + $res['type'] = 1; | ||
232 | + $res['name'] = date('YmdHis'); | ||
233 | + $res['folder_id'] = $folder_id; | ||
234 | + $res['content'] = $content; | ||
235 | + $res['createtime'] = time(); | ||
236 | + $res['updatetime'] = time(); | ||
237 | + $data = Db::name('savemes')->insertGetId($res); | ||
238 | + if(empty($data)){ | ||
239 | + $this->error('发布笔记失败'); | ||
240 | + }else{ | ||
241 | + $this->success('发布笔记成功'); | ||
242 | + } | ||
243 | + } | ||
244 | + | ||
245 | + /** | ||
246 | + * @ApiTitle (文佳列表) | ||
247 | + * @ApiSummary (上传列表) | ||
248 | + * @ApiMethod (POST) | ||
249 | + * @ApiRoute (/api/create/publish_list) | ||
250 | + * | ||
251 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
252 | + * | ||
253 | + * @ApiReturn({ | ||
254 | + "code": 1, | ||
255 | + "msg": "成功", | ||
256 | + "time": "1571492001", | ||
257 | + "data": { | ||
258 | + "id": //id, | ||
259 | + "user_id": //用户id, | ||
260 | + "type": //类型1笔记2图片3视频, | ||
261 | + "folder_id": //所在位置id, | ||
262 | + "name": //名称, | ||
263 | + "images": //图片, | ||
264 | + "video": //视频地址, | ||
265 | + "content": //内容, | ||
266 | + "is_open": //是否公开1公开2私密, | ||
267 | + "is_up": //是否上架1上架2下架, | ||
268 | + "uptime": //下架时间, | ||
269 | + "createtime": //创建时间, | ||
270 | + "updatetime": //修改时间, | ||
271 | + "video_image": //视频封面图 | ||
272 | + } | ||
273 | + ] | ||
274 | + } | ||
275 | + }) | ||
276 | + */ | ||
277 | + public function publish_list() | ||
278 | + { | ||
279 | + $qiniu = get_addon_config('qiniu')['cdnurl']; | ||
280 | + $user_id = $this->auth->id; | ||
281 | + $data = Db::name('savemes') | ||
282 | + ->where('user_id',$user_id) | ||
283 | + ->order('type asc') | ||
284 | + ->select(); | ||
285 | + foreach ($data as &$v){ | ||
286 | + if($v['type'] == 3){ | ||
287 | + $v['video'] = $qiniu.$v['video']; | ||
288 | + // 获取视频第一帧图片 | ||
289 | + $video_info = json_decode(file_get_contents($v['video'] . '?avinfo'), true); | ||
290 | + $v['video_image'] = $this->get_video_first_image($v['video'], $video_info); | ||
291 | + }elseif ($v['type'] == 2){ | ||
292 | + $v['images'] = explode(',',$v['images']); | ||
293 | + foreach ($v['images'] as &$val){ | ||
294 | + $val = $qiniu.$val; | ||
295 | + } | ||
296 | + } | ||
297 | + } | ||
298 | + $this->success('success',$data); | ||
299 | + | ||
300 | + } | ||
301 | + public function get_video_first_image($video_url,$video_info){ | ||
302 | + if(empty($video_info['streams'][0]['width'])) { | ||
303 | + $width = $video_info['streams'][1]['width']; | ||
304 | + $height = $video_info['streams'][1]['height']; | ||
305 | + } else { | ||
306 | + $width = $video_info['streams'][0]['width']; | ||
307 | + $height = $video_info['streams'][0]['height']; | ||
308 | + } | ||
309 | + return $video_url.'?vframe/jpg/offset/1/w/'.$width.'/h/'.$height; | ||
310 | + } | ||
311 | + | ||
312 | + /** | ||
313 | + * @ApiTitle (笔记详情) | ||
314 | + * @ApiSummary (笔记详情) | ||
315 | + * @ApiMethod (POST) | ||
316 | + * @ApiRoute (/api/create/note_detail) | ||
317 | + * | ||
318 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
319 | + * @ApiParams (name="id", type="inter", required=true, description="笔记id") | ||
320 | + * | ||
321 | + * @ApiReturn({ | ||
322 | + "code": 1, | ||
323 | + "msg": "成功", | ||
324 | + "time": "1571492001", | ||
325 | + "data": { | ||
326 | + "id": //id, | ||
327 | + "user_id": //用户id, | ||
328 | + "folder_id": //存储位置0为首页, | ||
329 | + "name": //名称, | ||
330 | + "content": //内容, | ||
331 | + "is_open": //是否公开1公开2私密, | ||
332 | + "is_up": //是否上架1上架2下架, | ||
333 | + "uptime": //下架时间, | ||
334 | + "collect_num": //收藏数量, | ||
335 | + "createtime": "//创建时间", | ||
336 | + "is_mine"://是否为本人1是2否 | ||
337 | + "is_collect"://是否收藏过1是2否 | ||
338 | + } | ||
339 | + }) | ||
340 | + */ | ||
341 | + public function note_detail() | ||
342 | + { | ||
343 | + $user_id = $this->auth->id; | ||
344 | + $id = $this->request->param('id'); | ||
345 | + if(empty($id)){ | ||
346 | + $this->error('缺少必要参数'); | ||
347 | + } | ||
348 | + $data = Db::name('savemes')->field('updatetime,images,video,type',true)->where('type',1)->where('id',$id)->find(); | ||
349 | + if(empty($data)){ | ||
350 | + $this->error('参数有误'); | ||
351 | + } | ||
352 | + //是否本人打开 | ||
353 | + if($data['user_id'] == $user_id){ | ||
354 | + $data['is_mine'] = 1; | ||
355 | + }else{ | ||
356 | + $data['is_mine'] = 2; | ||
357 | + } | ||
358 | + //是否收藏过 | ||
359 | + $collect = Db::name('collect')->where('user_id',$user_id)->where('savemes_id',$id)->find(); | ||
360 | + if(empty($collect)){ | ||
361 | + $data['is_collect'] = 2; | ||
362 | + }else{ | ||
363 | + $data['is_collect'] = 1; | ||
364 | + } | ||
365 | + $data['createtime'] = date('Y-m-d H:i:s',$data['createtime']); | ||
366 | + $this->success('success',$data); | ||
367 | + } | ||
368 | + | ||
369 | + /** | ||
370 | + * @ApiTitle (收藏/取消收藏) | ||
371 | + * @ApiSummary (收藏/取消收藏) | ||
372 | + * @ApiMethod (POST) | ||
373 | + * @ApiRoute (/api/create/collect) | ||
374 | + * | ||
375 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
376 | + * @ApiParams (name="id", type="inter", required=true, description="文件id") | ||
377 | + * | ||
378 | + * @ApiReturn({ | ||
379 | + "code": 1, | ||
380 | + "msg": "成功", | ||
381 | + "time": "1571492001", | ||
382 | + "data": { | ||
383 | + | ||
384 | + } | ||
385 | + }) | ||
386 | + */ | ||
387 | + public function collect() | ||
388 | + { | ||
389 | + $user_id = $this->auth->id; | ||
390 | + $id = $this->request->param('id'); | ||
391 | + if(empty($id)){ | ||
392 | + $this->error('缺少必要参数'); | ||
393 | + } | ||
394 | + $data = Db::name('collect')->where('user_id',$user_id)->where('savemes_id',$id)->find(); | ||
395 | + if(empty($data)){ | ||
396 | + $res['user_id'] = $user_id; | ||
397 | + $res['savemes_id'] = $id; | ||
398 | + $res['createtime'] = time(); | ||
399 | + $res['updatetime'] = time(); | ||
400 | + $info = Db::name('collect')->insertGetId($res); | ||
401 | + if(empty($info)){ | ||
402 | + $this->error('收藏失败'); | ||
403 | + }else{ | ||
404 | + $this->success('收藏成功'); | ||
405 | + } | ||
406 | + }else{ | ||
407 | + $info = Db::name('collect')->where('user_id',$user_id)->where('savemes_id',$id)->delete(); | ||
408 | + if(empty($info)){ | ||
409 | + $this->error('取消收藏失败'); | ||
410 | + }else{ | ||
411 | + $this->success('取消收藏成功'); | ||
412 | + } | ||
413 | + } | ||
414 | + } | ||
415 | + | ||
416 | + | ||
417 | + //批量操作 | ||
418 | + | ||
419 | + /** | ||
420 | + * @ApiTitle (文件删除) | ||
421 | + * @ApiSummary (文件删除) | ||
422 | + * @ApiMethod (POST) | ||
423 | + * @ApiRoute (/api/create/del) | ||
424 | + * | ||
425 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
426 | + * @ApiParams (name="ids", type="inter", required=true, description="文件ids字符串") | ||
427 | + * | ||
428 | + * @ApiReturn({ | ||
429 | + "code": 1, | ||
430 | + "msg": "成功", | ||
431 | + "time": "1571492001", | ||
432 | + "data": { | ||
433 | + | ||
434 | + } | ||
435 | + }) | ||
436 | + */ | ||
437 | + public function del() | ||
438 | + { | ||
439 | + $user_id = $this->auth->id; | ||
440 | + $ids = $this->request->param('ids'); | ||
441 | + if(empty($ids)){ | ||
442 | + $this->error('缺少必要参数'); | ||
443 | + } | ||
444 | + $arr_ids = explode(',',$ids); | ||
445 | + //删除文件 | ||
446 | + Db::startTrans(); | ||
447 | + try{ | ||
448 | + Db::name('savemes')->whereIn('id',$arr_ids)->delete(); | ||
449 | + Db::name('collect')->whereIn('savemes_id',$arr_ids)->delete(); | ||
450 | + Db::name('rotor')->whereIn('savemes_id',$arr_ids)->delete(); | ||
451 | + Db::commit(); | ||
452 | + } catch (\Exception $e) { | ||
453 | + // 回滚事务 | ||
454 | + Db::rollback(); | ||
455 | + } | ||
456 | + $this->success('删除成功'); | ||
457 | + } | ||
458 | + | ||
459 | + /** | ||
460 | + * @ApiTitle (设为公开) | ||
461 | + * @ApiSummary (设为公开) | ||
462 | + * @ApiMethod (POST) | ||
463 | + * @ApiRoute (/api/create/set_gong) | ||
464 | + * | ||
465 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
466 | + * @ApiParams (name="ids", type="inter", required=true, description="文件ids字符串") | ||
467 | + * | ||
468 | + * @ApiReturn({ | ||
469 | + "code": 1, | ||
470 | + "msg": "成功", | ||
471 | + "time": "1571492001", | ||
472 | + "data": { | ||
473 | + | ||
474 | + } | ||
475 | + }) | ||
476 | + */ | ||
477 | + public function set_gong() | ||
478 | + { | ||
479 | + $user_id = $this->auth->id; | ||
480 | + $ids = $this->request->param('ids'); | ||
481 | + if(empty($ids)){ | ||
482 | + $this->error('缺少必要参数'); | ||
483 | + } | ||
484 | + $arr_ids = explode(',',$ids); | ||
485 | + | ||
486 | + //设置为公开 | ||
487 | + Db::startTrans(); | ||
488 | + try{ | ||
489 | + Db::name('savemes')->whereIn('id',$arr_ids)->update(['is_open'=>1]); | ||
490 | + Db::name('rotor')->whereIn('savemes_id',$arr_ids)->update(['is_open'=>1]); | ||
491 | + Db::commit(); | ||
492 | + } catch (\Exception $e) { | ||
493 | + // 回滚事务 | ||
494 | + Db::rollback(); | ||
495 | + } | ||
496 | + $this->success('设置成功'); | ||
497 | + } | ||
498 | + | ||
499 | + /** | ||
500 | + * @ApiTitle (设为私密) | ||
501 | + * @ApiSummary (设为私密) | ||
502 | + * @ApiMethod (POST) | ||
503 | + * @ApiRoute (/api/create/set_si) | ||
504 | + * | ||
505 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
506 | + * @ApiParams (name="ids", type="inter", required=true, description="文件ids字符串") | ||
507 | + * | ||
508 | + * @ApiReturn({ | ||
509 | + "code": 1, | ||
510 | + "msg": "成功", | ||
511 | + "time": "1571492001", | ||
512 | + "data": { | ||
513 | + | ||
514 | + } | ||
515 | + }) | ||
516 | + */ | ||
517 | + public function set_si() | ||
518 | + { | ||
519 | + $user_id = $this->auth->id; | ||
520 | + $ids = $this->request->param('ids'); | ||
521 | + if(empty($ids)){ | ||
522 | + $this->error('缺少必要参数'); | ||
523 | + } | ||
524 | + $arr_ids = explode(',',$ids); | ||
525 | + | ||
526 | + //设置为公开 | ||
527 | + Db::startTrans(); | ||
528 | + try{ | ||
529 | + Db::name('savemes')->whereIn('id',$arr_ids)->update(['is_open'=>2]); | ||
530 | + Db::name('rotor')->whereIn('savemes_id',$arr_ids)->update(['is_open'=>2]); | ||
531 | + Db::commit(); | ||
532 | + } catch (\Exception $e) { | ||
533 | + // 回滚事务 | ||
534 | + Db::rollback(); | ||
535 | + } | ||
536 | + $this->success('设置成功'); | ||
537 | + } | ||
538 | + | ||
539 | + /** | ||
540 | + * @ApiTitle (全部上架) | ||
541 | + * @ApiSummary (全部上架) | ||
542 | + * @ApiMethod (POST) | ||
543 | + * @ApiRoute (/api/create/all_up) | ||
544 | + * | ||
545 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
546 | + * @ApiParams (name="ids", type="inter", required=true, description="文件ids字符串") | ||
547 | + * | ||
548 | + * @ApiReturn({ | ||
549 | + "code": 1, | ||
550 | + "msg": "成功", | ||
551 | + "time": "1571492001", | ||
552 | + "data": { | ||
553 | + | ||
554 | + } | ||
555 | + }) | ||
556 | + */ | ||
557 | + public function all_up() | ||
558 | + { | ||
559 | + $user_id = $this->auth->id; | ||
560 | + $ids = $this->request->param('ids'); | ||
561 | + if(empty($ids)){ | ||
562 | + $this->error('缺少必要参数'); | ||
563 | + } | ||
564 | + $arr_ids = explode(',',$ids); | ||
565 | + | ||
566 | + //全部上架 | ||
567 | + Db::startTrans(); | ||
568 | + try{ | ||
569 | + Db::name('savemes')->whereIn('id',$arr_ids)->update(['is_up'=>1,'uptime'=>0]); | ||
570 | + Db::name('rotor')->whereIn('savemes_id',$arr_ids)->update(['is_up'=>1]); | ||
571 | + Db::commit(); | ||
572 | + } catch (\Exception $e) { | ||
573 | + // 回滚事务 | ||
574 | + Db::rollback(); | ||
575 | + } | ||
576 | + $this->success('成功'); | ||
577 | + } | ||
578 | + | ||
579 | + /** | ||
580 | + * @ApiTitle (全部下架) | ||
581 | + * @ApiSummary (全部下架) | ||
582 | + * @ApiMethod (POST) | ||
583 | + * @ApiRoute (/api/create/all_down) | ||
584 | + * | ||
585 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
586 | + * @ApiParams (name="ids", type="inter", required=true, description="文件ids字符串") | ||
587 | + * | ||
588 | + * @ApiReturn({ | ||
589 | + "code": 1, | ||
590 | + "msg": "成功", | ||
591 | + "time": "1571492001", | ||
592 | + "data": { | ||
593 | + | ||
594 | + } | ||
595 | + }) | ||
596 | + */ | ||
597 | + public function all_down() | ||
598 | + { | ||
599 | + $user_id = $this->auth->id; | ||
600 | + $ids = $this->request->param('ids'); | ||
601 | + if(empty($ids)){ | ||
602 | + $this->error('缺少必要参数'); | ||
603 | + } | ||
604 | + $arr_ids = explode(',',$ids); | ||
605 | + | ||
606 | + //全部上架 | ||
607 | + Db::startTrans(); | ||
608 | + try{ | ||
609 | + Db::name('savemes')->whereIn('id',$arr_ids)->update(['is_up'=>2,'uptime'=>time()]); | ||
610 | + Db::name('rotor')->whereIn('savemes_id',$arr_ids)->update(['is_up'=>2]); | ||
611 | + Db::commit(); | ||
612 | + } catch (\Exception $e) { | ||
613 | + // 回滚事务 | ||
614 | + Db::rollback(); | ||
615 | + } | ||
616 | + $this->success('成功'); | ||
617 | + } | ||
618 | + | ||
619 | + /** | ||
620 | + * @ApiTitle (移动到) | ||
621 | + * @ApiSummary (移动到) | ||
622 | + * @ApiMethod (POST) | ||
623 | + * @ApiRoute (/api/create/all_move) | ||
624 | + * | ||
625 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
626 | + * @ApiParams (name="ids", type="inter", required=true, description="文件ids字符串") | ||
627 | + * @ApiParams (name="move_id", type="inter", required=true, description="移动的目标id首页为0") | ||
628 | + * | ||
629 | + * @ApiReturn({ | ||
630 | + "code": 1, | ||
631 | + "msg": "成功", | ||
632 | + "time": "1571492001", | ||
633 | + "data": { | ||
634 | + | ||
635 | + } | ||
636 | + }) | ||
637 | + */ | ||
638 | + public function all_move() | ||
639 | + { | ||
640 | + $user_id = $this->auth->id; | ||
641 | + $ids = $this->request->param('ids'); | ||
642 | + if(empty($ids)){ | ||
643 | + $this->error('缺少必要参数'); | ||
644 | + } | ||
645 | + $arr_ids = explode(',',$ids); | ||
646 | + | ||
647 | + $move_id = $this->request->param('move_id'); | ||
648 | + if(empty($move_id)){ | ||
649 | + $this->error('缺少必要参数'); | ||
650 | + } | ||
651 | + //全部上架 | ||
652 | + $data = Db::name('savemes')->whereIn('id',$arr_ids)->update(['folder_id'=>$move_id]); | ||
653 | + if(empty($data)){ | ||
654 | + $this->error('失败'); | ||
655 | + }else{ | ||
656 | + $this->success('成功'); | ||
657 | + } | ||
658 | + } | ||
659 | + | ||
660 | + /** | ||
661 | + * @ApiTitle (下载) | ||
662 | + * @ApiSummary (下载) | ||
663 | + * @ApiMethod (POST) | ||
664 | + * @ApiRoute (/api/create/download) | ||
665 | + * | ||
666 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
667 | + * @ApiParams (name="ids", type="inter", required=true, description="文件ids字符串") | ||
668 | + * | ||
669 | + * @ApiReturn({ | ||
670 | + "code": 1, | ||
671 | + "msg": "成功", | ||
672 | + "time": "1571492001", | ||
673 | + "data": { | ||
674 | + "info"://下载的文件 | ||
675 | + } | ||
676 | + }) | ||
677 | + */ | ||
678 | + public function download() | ||
679 | + { | ||
680 | + $qiniu = get_addon_config('qiniu')['cdnurl']; | ||
681 | + $user_id = $this->auth->id; | ||
682 | + $ids = $this->request->param('ids'); | ||
683 | + if(empty($ids)){ | ||
684 | + $this->error('缺少必要参数'); | ||
685 | + } | ||
686 | + $arr_ids = explode(',',$ids); | ||
687 | + | ||
688 | + $data = Db::name('savemes')->field('id,type,images,video')->whereIn('id',$arr_ids)->select(); | ||
689 | + $arr = []; | ||
690 | + foreach ($data as &$v){ | ||
691 | + //判断是否有笔记 | ||
692 | + if($v['type'] == 1){ | ||
693 | + $this->error('笔记不能下载'); | ||
694 | + } | ||
695 | + if($v['type'] == 2){ | ||
696 | + $v['video'] = ''; | ||
697 | + $v['images'] = explode(',',$v['images']); | ||
698 | + foreach ($v['images'] as &$val){ | ||
699 | + $qiuniu_url = $qiniu.$val; | ||
700 | + $a = file_get_contents($qiuniu_url); | ||
701 | + $path = './uploads/'.explode('/',$val)[2].'/'; | ||
702 | + if(!file_exists($path)) { | ||
703 | + mkdir($path,0777,true); | ||
704 | + } | ||
705 | + file_put_contents('.'.$val,$a); | ||
706 | + $val = request()->domain().$val; | ||
707 | + array_push($arr,$val); | ||
708 | + } | ||
709 | + } | ||
710 | + if($v['type'] == 3){ | ||
711 | + $v['images'] = ''; | ||
712 | + $qiuniu_url = $qiniu.$v['video']; | ||
713 | + $a = file_get_contents($qiuniu_url); | ||
714 | + $path = './uploads/'.explode('/',$v['video'])[2].'/'; | ||
715 | + if(!file_exists($path)) { | ||
716 | + mkdir($path,0777,true); | ||
717 | + } | ||
718 | + file_put_contents('.'.$v['video'],$a); | ||
719 | + $v['video'] = request()->domain().$v['video']; | ||
720 | + array_push($arr,$v['video']); | ||
721 | + } | ||
722 | + } | ||
723 | + $this->success('success',['info'=>$arr]); | ||
724 | + } | ||
725 | + | ||
726 | + /** | ||
727 | + * @ApiTitle (重命名) | ||
728 | + * @ApiSummary (重命名) | ||
729 | + * @ApiMethod (POST) | ||
730 | + * @ApiRoute (/api/create/rename) | ||
731 | + * | ||
732 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
733 | + * @ApiParams (name="id", type="inter", required=true, description="文件id") | ||
734 | + * @ApiParams (name="type", type="inter", required=true, description="类型1文件2文件夹") | ||
735 | + * @ApiParams (name="name", type="string", required=true, description="修改后的名称") | ||
736 | + * | ||
737 | + * @ApiReturn({ | ||
738 | + "code": 1, | ||
739 | + "msg": "成功", | ||
740 | + "time": "1571492001", | ||
741 | + "data": { | ||
742 | + | ||
743 | + } | ||
744 | + }) | ||
745 | + */ | ||
746 | + public function rename() | ||
747 | + { | ||
748 | + $user_id = $this->auth->id; | ||
749 | + $id = $this->request->param('id'); | ||
750 | + $name = $this->request->param('name'); | ||
751 | + $type = $this->request->param('type'); | ||
752 | + if(empty($id) || empty($name) || empty($type)){ | ||
753 | + $this->error('缺少必要参数'); | ||
754 | + } | ||
755 | + if($type == 1){ | ||
756 | + $data = Db::name('savemes')->where('id',$id)->find(); | ||
757 | + if($data['user_id'] != $user_id){ | ||
758 | + $this->error('没有权限重命名'); | ||
759 | + } | ||
760 | + $res = Db::name('savemes')->where('id',$id)->update(['name'=>$name]); | ||
761 | + }elseif ($type == 2){ | ||
762 | + $data = Db::name('folder')->where('id',$id)->find(); | ||
763 | + if($data['user_id'] != $user_id){ | ||
764 | + $this->error('没有权限重命名'); | ||
765 | + } | ||
766 | + $res = Db::name('folder')->where('id',$id)->update(['folder_name'=>$name]); | ||
767 | + } | ||
768 | + if(empty($res)){ | ||
769 | + $this->error('重命名失败'); | ||
770 | + }else{ | ||
771 | + $this->success('重命名成功'); | ||
772 | + } | ||
773 | + } | ||
774 | + | ||
77 | } | 775 | } |
@@ -13,7 +13,29 @@ class Index extends Api | @@ -13,7 +13,29 @@ class Index extends Api | ||
13 | protected $noNeedLogin = ['*']; | 13 | protected $noNeedLogin = ['*']; |
14 | protected $noNeedRight = ['*']; | 14 | protected $noNeedRight = ['*']; |
15 | 15 | ||
16 | + /** | ||
17 | + * @ApiTitle (APP启动页) | ||
18 | + * @ApiSummary (APP启动页) | ||
19 | + * @ApiMethod (POST) | ||
20 | + * @ApiRoute (/api/index/flash) | ||
21 | + * | ||
22 | + * @ApiReturn({ | ||
23 | + "code": 1, | ||
24 | + "msg": "成功", | ||
25 | + "time": "1571492001", | ||
26 | + "data": { | ||
27 | + "image": //启动页图片, | ||
28 | + } | ||
29 | + }) | ||
30 | + */ | ||
31 | + public function flash() | ||
32 | + { | ||
33 | + $qiniu = get_addon_config('qiniu')['cdnurl']; | ||
34 | + $data = Db::name('flash')->where('id',1)->field('image')->find(); | ||
35 | + $data['image'] = $qiniu.$data['image']; | ||
36 | + $this->success('success',$data); | ||
16 | 37 | ||
38 | + } | ||
17 | 39 | ||
18 | 40 | ||
19 | /** | 41 | /** |
@@ -35,6 +57,7 @@ class Index extends Api | @@ -35,6 +57,7 @@ class Index extends Api | ||
35 | "user_id": //用户id, | 57 | "user_id": //用户id, |
36 | "folder_name": //文件夹名称, | 58 | "folder_name": //文件夹名称, |
37 | "pid": //父级文件夹id, | 59 | "pid": //父级文件夹id, |
60 | + "is_open": //是否公开1公开2私密 | ||
38 | "is_up": //1上架2下架 | 61 | "is_up": //1上架2下架 |
39 | "createtime": //创建时间, | 62 | "createtime": //创建时间, |
40 | "updatetime": //修改时间 | 63 | "updatetime": //修改时间 |
@@ -358,8 +358,8 @@ class Login extends Api | @@ -358,8 +358,8 @@ class Login extends Api | ||
358 | } | 358 | } |
359 | 359 | ||
360 | /** | 360 | /** |
361 | - * @ApiTitle (用户协议) | ||
362 | - * @ApiSummary (用户协议) | 361 | + * @ApiTitle (文案) |
362 | + * @ApiSummary (文案) | ||
363 | * @ApiMethod (POST) | 363 | * @ApiMethod (POST) |
364 | * @ApiRoute (/api/login/official) | 364 | * @ApiRoute (/api/login/official) |
365 | * | 365 | * |
@@ -369,13 +369,15 @@ class Login extends Api | @@ -369,13 +369,15 @@ class Login extends Api | ||
369 | "time": "1553839125", | 369 | "time": "1553839125", |
370 | "data": { | 370 | "data": { |
371 | "id"://id | 371 | "id"://id |
372 | - "content"://内容 | 372 | + "content"://用户协议 |
373 | + "desc"://会员权益 | ||
374 | + "explain"://操作说明 | ||
373 | } | 375 | } |
374 | }) | 376 | }) |
375 | */ | 377 | */ |
376 | public function official() | 378 | public function official() |
377 | { | 379 | { |
378 | - $data = Db::name('official')->where('id',1)->field('id,content')->find(); | 380 | + $data = Db::name('official')->where('id',1)->field('id,content,desc,explain')->find(); |
379 | $this->success('success',$data); | 381 | $this->success('success',$data); |
380 | } | 382 | } |
381 | 383 |
application/api/controller/Order.php
0 → 100644
1 | +<?php | ||
2 | +/** | ||
3 | + * Created by PhpStorm. | ||
4 | + * User: Administrator | ||
5 | + * Date: 2020/7/10 | ||
6 | + * Time: 17:32 | ||
7 | + */ | ||
8 | + | ||
9 | +namespace app\api\controller; | ||
10 | + | ||
11 | + | ||
12 | +use app\common\controller\Api; | ||
13 | +use think\Db; | ||
14 | + | ||
15 | +/** | ||
16 | + * 开通会员 | ||
17 | + */ | ||
18 | +class Order extends Api | ||
19 | +{ | ||
20 | + protected $noNeedLogin = ['']; | ||
21 | + protected $noNeedRight = ['*']; | ||
22 | + | ||
23 | + | ||
24 | + /** | ||
25 | + * @ApiTitle (收款码图片) | ||
26 | + * @ApiSummary (收款码图片) | ||
27 | + * @ApiMethod (POST) | ||
28 | + * @ApiRoute (/api/order/payimage) | ||
29 | + * | ||
30 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
31 | + * @ApiParams (name="type", type="inter", required=true, description="类型1微信2支付") | ||
32 | + * | ||
33 | + * @ApiReturn({ | ||
34 | + "code": 1, | ||
35 | + "msg": "成功", | ||
36 | + "time": "1571492001", | ||
37 | + "data": { | ||
38 | + "image": //图片地址 | ||
39 | + } | ||
40 | + ] | ||
41 | + } | ||
42 | + }) | ||
43 | + */ | ||
44 | + public function payimage() | ||
45 | + { | ||
46 | + $qiniu = get_addon_config('qiniu')['cdnurl']; | ||
47 | + $user_id = $this->auth->id; | ||
48 | + $type = $this->request->param('type'); | ||
49 | + if(empty($type)){ | ||
50 | + $this->error('缺少必要参数'); | ||
51 | + } | ||
52 | + $data = Db::name('payimage')->where('id',1)->find(); | ||
53 | + if($type == 1){ | ||
54 | + $this->success('success',['image'=>$qiniu.$data['image']]); | ||
55 | + }else{ | ||
56 | + $this->success('success',['image'=>$qiniu.$data['aliimage']]); | ||
57 | + } | ||
58 | + } | ||
59 | + | ||
60 | + | ||
61 | + /** | ||
62 | + * @ApiTitle (开通会员订单) | ||
63 | + * @ApiSummary (开通会员订单) | ||
64 | + * @ApiMethod (POST) | ||
65 | + * @ApiRoute (/api/order/index) | ||
66 | + * | ||
67 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
68 | + * @ApiParams (name="type", type="inter", required=true, description="支付方式1微信2支付宝") | ||
69 | + * @ApiParams (name="order_num", type="inter", required=true, description="订单后四位") | ||
70 | + * | ||
71 | + * @ApiReturn({ | ||
72 | + "code": 1, | ||
73 | + "msg": "成功", | ||
74 | + "time": "1571492001", | ||
75 | + "data": { | ||
76 | + "order_id"://订单id | ||
77 | + } | ||
78 | + ] | ||
79 | + } | ||
80 | + }) | ||
81 | + */ | ||
82 | + public function index() | ||
83 | + { | ||
84 | + $user_id = $this->auth->id; | ||
85 | + $type = $this->request->param('type'); | ||
86 | + $order_num = $this->request->param('order_num'); | ||
87 | + if(empty($type) || empty($order_num)){ | ||
88 | + $this->error('缺少必要参数'); | ||
89 | + } | ||
90 | + $vipdaynum = Db::name('vipdaynum')->where('id',1)->value('day_num'); | ||
91 | + | ||
92 | + $res['user_id'] = $user_id; | ||
93 | + $res['order_num'] = $order_num; | ||
94 | + $res['type'] = $type; | ||
95 | + $res['daynum'] = $vipdaynum; | ||
96 | + $res['createtime'] = time(); | ||
97 | + $res['updatetime'] = time(); | ||
98 | + $data = Db::name('viporder')->insertGetId($res); | ||
99 | + if(empty($data)){ | ||
100 | + $this->error('开通失败'); | ||
101 | + }else{ | ||
102 | + $this->success('开通成功',['oder_id'=>$data]); | ||
103 | + } | ||
104 | + } | ||
105 | + | ||
106 | + | ||
107 | + /** | ||
108 | + * @ApiTitle (我的订阅) | ||
109 | + * @ApiSummary (我的订阅) | ||
110 | + * @ApiMethod (POST) | ||
111 | + * @ApiRoute (/api/order/myattention) | ||
112 | + * | ||
113 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
114 | + * | ||
115 | + * @ApiParams (name="page", type="inter", required=false, description="当前页(默认1)") | ||
116 | + * @ApiParams (name="pageNum", type="inter", required=false, description="每页显示数据个数(默认10)") | ||
117 | + * | ||
118 | + * | ||
119 | + * @ApiReturn({ | ||
120 | + "code": 1, | ||
121 | + "msg": "成功", | ||
122 | + "time": "1571492001", | ||
123 | + "data": { | ||
124 | + "id"://订阅ID | ||
125 | + "user_id": //用户id, | ||
126 | + "to_user_id"://订阅的用户id | ||
127 | + "createtime"://创建时间 | ||
128 | + "username"://用户名 | ||
129 | + "avatar"://头像 | ||
130 | + "createtime"://创建时间 | ||
131 | + "updatetime"://修改时间 | ||
132 | + } | ||
133 | + }) | ||
134 | + */ | ||
135 | + public function myattention() | ||
136 | + { | ||
137 | + $qiniu = get_addon_config('qiniu')['cdnurl']; | ||
138 | + $user_id = $this->auth->id; | ||
139 | + $page = $this->request->param('page', 1, 'intval'); | ||
140 | + $pageNum = $this->request->param('pageNum', 10, 'intval'); | ||
141 | + $data = Db::name('subscribe') | ||
142 | + ->alias('a') | ||
143 | + ->join('user b','a.to_user_id = b.id') | ||
144 | + ->where('a.user_id',$user_id) | ||
145 | + ->field('a.*,b.username,b.avatar') | ||
146 | + ->order('a.id desc') | ||
147 | + ->page($page,$pageNum) | ||
148 | + ->select(); | ||
149 | + foreach ($data as &$v){ | ||
150 | + $v['avatar'] = $qiniu.$v['avatar']; | ||
151 | + } | ||
152 | + $this->success('success',$data); | ||
153 | + } | ||
154 | + | ||
155 | + /** | ||
156 | + * @ApiTitle (订阅/取消订阅) | ||
157 | + * @ApiSummary (订阅/取消订阅) | ||
158 | + * @ApiMethod (POST) | ||
159 | + * @ApiRoute (/api/order/ding) | ||
160 | + * | ||
161 | + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token") | ||
162 | + * | ||
163 | + * @ApiParams (name="to_user_id", type="inter", required=true, description="订阅人id") | ||
164 | + * | ||
165 | + * @ApiReturn({ | ||
166 | + "code": 1, | ||
167 | + "msg": "成功", | ||
168 | + "time": "1571492001", | ||
169 | + "data": { | ||
170 | + } | ||
171 | + }) | ||
172 | + */ | ||
173 | + public function ding() | ||
174 | + { | ||
175 | + $user_id = $this->auth->id; | ||
176 | + $to_user_id = $this->request->param('to_user_id'); | ||
177 | + if(empty($to_user_id)){ | ||
178 | + $this->error('缺少必要参数'); | ||
179 | + } | ||
180 | + $data = Db::name('subscribe')->where('user_id',$user_id)->where('to_user_id',$to_user_id)->find(); | ||
181 | + if(empty($data)){ | ||
182 | + $res['user_id'] = $user_id; | ||
183 | + $res['to_user_id'] = $to_user_id; | ||
184 | + $res['createtime'] = time(); | ||
185 | + $res['updatetime'] = time(); | ||
186 | + $arr = Db::name('subscribe')->insertGetId($res); | ||
187 | + if(empty($arr)){ | ||
188 | + $this->error('订阅失败'); | ||
189 | + }else{ | ||
190 | + $this->success('订阅成功'); | ||
191 | + } | ||
192 | + }else{ | ||
193 | + $arr = Db::name('subscribe')->where('user_id',$user_id)->where('to_user_id',$to_user_id)->delete(); | ||
194 | + if(empty($arr)){ | ||
195 | + $this->error('取消订阅失败'); | ||
196 | + }else{ | ||
197 | + $this->success('取消订阅成功'); | ||
198 | + } | ||
199 | + } | ||
200 | + } | ||
201 | + | ||
202 | +} |
@@ -24,7 +24,8 @@ | @@ -24,7 +24,8 @@ | ||
24 | "phpmailer/phpmailer": "~6.0.6", | 24 | "phpmailer/phpmailer": "~6.0.6", |
25 | "karsonzhang/fastadmin-addons": "~1.1.9", | 25 | "karsonzhang/fastadmin-addons": "~1.1.9", |
26 | "overtrue/pinyin": "~3.0", | 26 | "overtrue/pinyin": "~3.0", |
27 | - "phpoffice/phpspreadsheet": "^1.2" | 27 | + "phpoffice/phpspreadsheet": "^1.2", |
28 | + "qiniu/php-sdk": "^7.2" | ||
28 | }, | 29 | }, |
29 | "config": { | 30 | "config": { |
30 | "preferred-install": "dist" | 31 | "preferred-install": "dist" |
-
请 注册 或 登录 后发表评论