作者 李忠强

更新

  1 +{"files":["application\\admin\\controller\\Command.php","application\\admin\\lang\\zh-cn\\command.php","application\\admin\\model\\Command.php","application\\admin\\validate\\Command.php","application\\admin\\view\\command\\add.html","application\\admin\\view\\command\\detail.html","application\\admin\\view\\command\\index.html","public\\assets\\js\\backend\\command.js"],"license":"regular","licenseto":"10789","licensekey":"ogGuqfEhWU5smPv7 ZCMeDKwDoQx8JuH\/Lrj4FA==","domains":[],"licensecodes":[],"validations":[],"menus":["command","command\/index","command\/add","command\/detail","command\/execute","command\/del","command\/multi"]}
  1 +<?php
  2 +
  3 +namespace addons\command;
  4 +
  5 +use app\common\library\Menu;
  6 +use think\Addons;
  7 +
  8 +/**
  9 + * 在线命令插件
  10 + */
  11 +class Command extends Addons
  12 +{
  13 +
  14 + /**
  15 + * 插件安装方法
  16 + * @return bool
  17 + */
  18 + public function install()
  19 + {
  20 + $menu = [
  21 + [
  22 + 'name' => 'command',
  23 + 'title' => '在线命令管理',
  24 + 'icon' => 'fa fa-terminal',
  25 + 'sublist' => [
  26 + ['name' => 'command/index', 'title' => '查看'],
  27 + ['name' => 'command/add', 'title' => '添加'],
  28 + ['name' => 'command/detail', 'title' => '详情'],
  29 + ['name' => 'command/execute', 'title' => '运行'],
  30 + ['name' => 'command/del', 'title' => '删除'],
  31 + ['name' => 'command/multi', 'title' => '批量更新'],
  32 + ]
  33 + ]
  34 + ];
  35 + Menu::create($menu);
  36 + return true;
  37 + }
  38 +
  39 + /**
  40 + * 插件卸载方法
  41 + * @return bool
  42 + */
  43 + public function uninstall()
  44 + {
  45 + Menu::delete('command');
  46 + return true;
  47 + }
  48 +
  49 + /**
  50 + * 插件启用方法
  51 + * @return bool
  52 + */
  53 + public function enable()
  54 + {
  55 + Menu::enable('command');
  56 + return true;
  57 + }
  58 +
  59 + /**
  60 + * 插件禁用方法
  61 + * @return bool
  62 + */
  63 + public function disable()
  64 + {
  65 + Menu::disable('command');
  66 + return true;
  67 + }
  68 +
  69 +}
  1 +<?php
  2 +
  3 +return [
  4 +];
  1 +<?php
  2 +
  3 +namespace addons\command\controller;
  4 +
  5 +use think\addons\Controller;
  6 +
  7 +class Index extends Controller
  8 +{
  9 +
  10 + public function index()
  11 + {
  12 + $this->error("当前插件暂无前台页面");
  13 + }
  14 +
  15 +}
  1 +name = command
  2 +title = 在线命令
  3 +intro = 可在线执行FastAdmin的命令行相关命令
  4 +author = Karson
  5 +website = https://www.fastadmin.net
  6 +version = 1.0.6
  7 +state = 1
  8 +url = /addons/command
  9 +license = regular
  10 +licenseto = 10789
  1 +CREATE TABLE IF NOT EXISTS `__PREFIX__command` (
  2 + `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
  3 + `type` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '类型',
  4 + `params` varchar(1500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '参数',
  5 + `command` varchar(1500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '命令',
  6 + `content` text COMMENT '返回结果',
  7 + `executetime` int(10) UNSIGNED DEFAULT NULL COMMENT '执行时间',
  8 + `createtime` int(10) UNSIGNED DEFAULT NULL COMMENT '创建时间',
  9 + `updatetime` int(10) UNSIGNED DEFAULT NULL COMMENT '更新时间',
  10 + `status` enum('successed','failured') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'failured' COMMENT '状态',
  11 + PRIMARY KEY (`id`) USING BTREE
  12 +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '在线命令表';
  1 +<?php
  2 +
  3 +namespace addons\command\library;
  4 +
  5 +/**
  6 + * Class Output
  7 + */
  8 +class Output extends \think\console\Output
  9 +{
  10 +
  11 + protected $message = [];
  12 +
  13 + public function __construct($driver = 'console')
  14 + {
  15 + parent::__construct($driver);
  16 + }
  17 +
  18 + protected function block($style, $message)
  19 + {
  20 + $this->message[] = $message;
  21 + }
  22 +
  23 + public function getMessage()
  24 + {
  25 + return $this->message;
  26 + }
  27 +
  28 +}
  1 +<?php
  2 +
  3 +namespace app\admin\controller;
  4 +
  5 +use app\common\controller\Backend;
  6 +use think\Config;
  7 +use think\console\Input;
  8 +use think\Db;
  9 +use think\Exception;
  10 +
  11 +/**
  12 + * 在线命令管理
  13 + *
  14 + * @icon fa fa-circle-o
  15 + */
  16 +class Command extends Backend
  17 +{
  18 +
  19 + /**
  20 + * Command模型对象
  21 + */
  22 + protected $model = null;
  23 + protected $noNeedRight = ['get_controller_list', 'get_field_list'];
  24 +
  25 + public function _initialize()
  26 + {
  27 + parent::_initialize();
  28 + $this->model = model('Command');
  29 + $this->view->assign("statusList", $this->model->getStatusList());
  30 + }
  31 +
  32 + /**
  33 + * 添加
  34 + */
  35 + public function add()
  36 + {
  37 +
  38 + $tableList = [];
  39 + $list = \think\Db::query("SHOW TABLES");
  40 + foreach ($list as $key => $row) {
  41 + $tableList[reset($row)] = reset($row);
  42 + }
  43 +
  44 + $this->view->assign("tableList", $tableList);
  45 + return $this->view->fetch();
  46 + }
  47 +
  48 + /**
  49 + * 获取字段列表
  50 + * @internal
  51 + */
  52 + public function get_field_list()
  53 + {
  54 + $dbname = Config::get('database.database');
  55 + $prefix = Config::get('database.prefix');
  56 + $table = $this->request->request('table');
  57 + //从数据库中获取表字段信息
  58 + $sql = "SELECT * FROM `information_schema`.`columns` "
  59 + . "WHERE TABLE_SCHEMA = ? AND table_name = ? "
  60 + . "ORDER BY ORDINAL_POSITION";
  61 + //加载主表的列
  62 + $columnList = Db::query($sql, [$dbname, $table]);
  63 + $fieldlist = [];
  64 + foreach ($columnList as $index => $item) {
  65 + $fieldlist[] = $item['COLUMN_NAME'];
  66 + }
  67 + $this->success("", null, ['fieldlist' => $fieldlist]);
  68 + }
  69 +
  70 + /**
  71 + * 获取控制器列表
  72 + * @internal
  73 + */
  74 + public function get_controller_list()
  75 + {
  76 + //搜索关键词,客户端输入以空格分开,这里接收为数组
  77 + $word = (array)$this->request->request("q_word/a");
  78 + $word = implode('', $word);
  79 +
  80 + $adminPath = dirname(__DIR__) . DS;
  81 + $controllerDir = $adminPath . 'controller' . DS;
  82 + $files = new \RecursiveIteratorIterator(
  83 + new \RecursiveDirectoryIterator($controllerDir), \RecursiveIteratorIterator::LEAVES_ONLY
  84 + );
  85 + $list = [];
  86 + foreach ($files as $name => $file) {
  87 + if (!$file->isDir()) {
  88 + $filePath = $file->getRealPath();
  89 + $name = str_replace($controllerDir, '', $filePath);
  90 + $name = str_replace(DS, "/", $name);
  91 + if (!preg_match("/(.*)\.php\$/", $name)) {
  92 + continue;
  93 + }
  94 + if (!$word || stripos($name, $word) !== false) {
  95 + $list[] = ['id' => $name, 'name' => $name];
  96 + }
  97 + }
  98 + }
  99 + $pageNumber = $this->request->request("pageNumber");
  100 + $pageSize = $this->request->request("pageSize");
  101 + return json(['list' => array_slice($list, ($pageNumber - 1) * $pageSize, $pageSize), 'total' => count($list)]);
  102 + }
  103 +
  104 + /**
  105 + * 详情
  106 + */
  107 + public function detail($ids)
  108 + {
  109 + $row = $this->model->get($ids);
  110 + if (!$row) {
  111 + $this->error(__('No Results were found'));
  112 + }
  113 + $this->view->assign("row", $row);
  114 + return $this->view->fetch();
  115 + }
  116 +
  117 + /**
  118 + * 执行
  119 + */
  120 + public function execute($ids)
  121 + {
  122 + $row = $this->model->get($ids);
  123 + if (!$row) {
  124 + $this->error(__('No Results were found'));
  125 + }
  126 + $result = $this->doexecute($row['type'], json_decode($row['params'], true));
  127 + $this->success("", null, ['result' => $result]);
  128 + }
  129 +
  130 + /**
  131 + * 执行命令
  132 + */
  133 + public function command($action = '')
  134 + {
  135 + $commandtype = $this->request->request("commandtype");
  136 + $params = $this->request->request();
  137 + $allowfields = [
  138 + 'crud' => 'table,controller,model,fields,force,local,delete,menu',
  139 + 'menu' => 'controller,delete',
  140 + 'min' => 'module,resource,optimize',
  141 + 'api' => 'url,module,output,template,force,title,author,class,language',
  142 + ];
  143 + $argv = [];
  144 + $allowfields = isset($allowfields[$commandtype]) ? explode(',', $allowfields[$commandtype]) : [];
  145 + $allowfields = array_filter(array_intersect_key($params, array_flip($allowfields)));
  146 + if (isset($params['local']) && !$params['local']) {
  147 + $allowfields['local'] = $params['local'];
  148 + } else {
  149 + unset($allowfields['local']);
  150 + }
  151 + foreach ($allowfields as $key => $param) {
  152 + $argv[] = "--{$key}=" . (is_array($param) ? implode(',', $param) : $param);
  153 + }
  154 + if ($commandtype == 'crud') {
  155 + $extend = 'setcheckboxsuffix,enumradiosuffix,imagefield,filefield,intdatesuffix,switchsuffix,citysuffix,selectpagesuffix,selectpagessuffix,ignorefields,sortfield,editorsuffix,headingfilterfield';
  156 + $extendArr = explode(',', $extend);
  157 + foreach ($params as $index => $item) {
  158 + if (in_array($index, $extendArr)) {
  159 + foreach (explode(',', $item) as $key => $value) {
  160 + if ($value) {
  161 + $argv[] = "--{$index}={$value}";
  162 + }
  163 + }
  164 + }
  165 + }
  166 + $isrelation = (int)$this->request->request('isrelation');
  167 + if ($isrelation && isset($params['relation'])) {
  168 + foreach ($params['relation'] as $index => $relation) {
  169 + foreach ($relation as $key => $value) {
  170 + $argv[] = "--{$key}=" . (is_array($value) ? implode(',', $value) : $value);
  171 + }
  172 + }
  173 + }
  174 + } else {
  175 + if ($commandtype == 'menu') {
  176 + if (isset($params['allcontroller']) && $params['allcontroller']) {
  177 + $argv[] = "--controller=all-controller";
  178 + } else {
  179 + foreach (explode(',', $params['controllerfile']) as $index => $param) {
  180 + if ($param) {
  181 + $argv[] = "--controller=" . substr($param, 0, -4);
  182 + }
  183 + }
  184 + }
  185 + } else {
  186 + if ($commandtype == 'min') {
  187 +
  188 + } else {
  189 + if ($commandtype == 'api') {
  190 +
  191 + } else {
  192 +
  193 + }
  194 + }
  195 + }
  196 + }
  197 + if ($action == 'execute') {
  198 + $result = $this->doexecute($commandtype, $argv);
  199 + $this->success("", null, ['result' => $result]);
  200 + } else {
  201 + $this->success("", null, ['command' => "php think {$commandtype} " . implode(' ', $argv)]);
  202 + }
  203 +
  204 + return;
  205 + }
  206 +
  207 + protected function doexecute($commandtype, $argv)
  208 + {
  209 + $commandName = "\\app\\admin\\command\\" . ucfirst($commandtype);
  210 + $input = new Input($argv);
  211 + $output = new \addons\command\library\Output();
  212 + $command = new $commandName($commandtype);
  213 + $data = [
  214 + 'type' => $commandtype,
  215 + 'params' => json_encode($argv),
  216 + 'command' => "php think {$commandtype} " . implode(' ', $argv),
  217 + 'executetime' => time(),
  218 + ];
  219 + $this->model->save($data);
  220 + try {
  221 + $command->run($input, $output);
  222 + $result = implode("\n", $output->getMessage());
  223 + $this->model->status = 'successed';
  224 + } catch (Exception $e) {
  225 + $result = implode("\n", $output->getMessage()) . "\n";
  226 + $result .= $e->getMessage();
  227 + $this->model->status = 'failured';
  228 + }
  229 + $result = trim($result);
  230 + $this->model->content = $result;
  231 + $this->model->save();
  232 + return $result;
  233 + }
  234 +
  235 +
  236 +}
  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 Timeslot extends Backend
  13 +{
  14 +
  15 + /**
  16 + * Timeslot模型对象
  17 + * @var \app\admin\model\Timeslot
  18 + */
  19 + protected $model = null;
  20 +
  21 + public function _initialize()
  22 + {
  23 + parent::_initialize();
  24 + $this->model = new \app\admin\model\Timeslot;
  25 +
  26 + }
  27 +
  28 + public function import()
  29 + {
  30 + parent::import();
  31 + }
  32 +
  33 + /**
  34 + * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
  35 + * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
  36 + * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
  37 + */
  38 +
  39 +
  40 +}
  1 +<?php
  2 +
  3 +return [
  4 + 'Id' => 'ID',
  5 + 'Type' => '类型',
  6 + 'Params' => '参数',
  7 + 'Command' => '命令',
  8 + 'Content' => '返回结果',
  9 + 'Executetime' => '执行时间',
  10 + 'Createtime' => '创建时间',
  11 + 'Updatetime' => '更新时间',
  12 + 'Execute again' => '再次执行',
  13 + 'Successed' => '成功',
  14 + 'Failured' => '失败',
  15 + 'Status' => '状态'
  16 +];
  1 +<?php
  2 +
  3 +return [
  4 + 'Time' => '时间'
  5 +];
  1 +<?php
  2 +
  3 +namespace app\admin\model;
  4 +
  5 +use think\Model;
  6 +
  7 +class Command extends Model
  8 +{
  9 + // 表名
  10 + protected $name = 'command';
  11 +
  12 + // 自动写入时间戳字段
  13 + protected $autoWriteTimestamp = 'int';
  14 +
  15 + // 定义时间戳字段名
  16 + protected $createTime = 'createtime';
  17 + protected $updateTime = 'updatetime';
  18 +
  19 + // 追加属性
  20 + protected $append = [
  21 + 'executetime_text',
  22 + 'type_text',
  23 + 'status_text'
  24 + ];
  25 +
  26 +
  27 + public function getStatusList()
  28 + {
  29 + return ['successed' => __('Successed'), 'failured' => __('Failured')];
  30 + }
  31 +
  32 +
  33 + public function getExecutetimeTextAttr($value, $data)
  34 + {
  35 + $value = $value ? $value : $data['executetime'];
  36 + return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
  37 + }
  38 +
  39 + public function getTypeTextAttr($value, $data)
  40 + {
  41 + $value = $value ? $value : $data['type'];
  42 + $list = ['crud' => '一键生成CRUD', 'menu' => '一键生成菜单', 'min' => '一键压缩打包', 'api' => '一键生成文档'];
  43 + return isset($list[$value]) ? $list[$value] : '';
  44 + }
  45 +
  46 + public function getStatusTextAttr($value, $data)
  47 + {
  48 + $value = $value ? $value : $data['status'];
  49 + $list = $this->getStatusList();
  50 + return isset($list[$value]) ? $list[$value] : '';
  51 + }
  52 +
  53 + protected function setExecutetimeAttr($value)
  54 + {
  55 + return $value && !is_numeric($value) ? strtotime($value) : $value;
  56 + }
  57 +
  58 +
  59 +}
  1 +<?php
  2 +
  3 +namespace app\admin\model;
  4 +
  5 +use think\Model;
  6 +
  7 +
  8 +class Timeslot extends Model
  9 +{
  10 +
  11 +
  12 +
  13 +
  14 +
  15 + // 表名
  16 + protected $name = 'timeslot';
  17 +
  18 + // 自动写入时间戳字段
  19 + protected $autoWriteTimestamp = false;
  20 +
  21 + // 定义时间戳字段名
  22 + protected $createTime = false;
  23 + protected $updateTime = false;
  24 + protected $deleteTime = false;
  25 +
  26 + // 追加属性
  27 + protected $append = [
  28 + 'time_text'
  29 + ];
  30 +
  31 +
  32 +
  33 +
  34 +
  35 +
  36 + public function getTimeTextAttr($value, $data)
  37 + {
  38 + $value = $value ? $value : (isset($data['time']) ? $data['time'] : '');
  39 + return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
  40 + }
  41 +
  42 +
  43 +}
  1 +<?php
  2 +
  3 +namespace app\admin\validate;
  4 +
  5 +use think\Validate;
  6 +
  7 +class Command 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 +<?php
  2 +
  3 +namespace app\admin\validate;
  4 +
  5 +use think\Validate;
  6 +
  7 +class Timeslot 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>
  2 + .relation-item {margin-top:10px;}
  3 + legend {padding-bottom:5px;font-size:14px;font-weight:600;}
  4 + label {font-weight:normal;}
  5 + .form-control{padding:6px 8px;}
  6 + #extend-zone .col-xs-2 {margin-top:10px;padding-right:0;}
  7 + #extend-zone .col-xs-2:nth-child(6n+0) {padding-right:15px;}
  8 +</style>
  9 +<div class="panel panel-default panel-intro">
  10 + <div class="panel-heading">
  11 + <ul class="nav nav-tabs">
  12 + <li class="active"><a href="#crud" data-toggle="tab">{:__('一键生成CRUD')}</a></li>
  13 + <li><a href="#menu" data-toggle="tab">{:__('一键生成菜单')}</a></li>
  14 + <li><a href="#min" data-toggle="tab">{:__('一键压缩打包')}</a></li>
  15 + <li><a href="#api" data-toggle="tab">{:__('一键生成API文档')}</a></li>
  16 + </ul>
  17 + </div>
  18 + <div class="panel-body">
  19 + <div id="myTabContent" class="tab-content">
  20 + <div class="tab-pane fade active in" id="crud">
  21 + <div class="row">
  22 + <div class="col-xs-12">
  23 + <form role="form">
  24 + <input type="hidden" name="commandtype" value="crud" />
  25 + <div class="form-group">
  26 + <div class="row">
  27 + <div class="col-xs-3">
  28 + <input checked="" name="isrelation" type="hidden" value="0">
  29 + <label class="control-label" data-toggle="tooltip" title="当前只支持生成1对1关联模型,选中后请配置关联表和字段">
  30 + <input name="isrelation" type="checkbox" value="1">
  31 + 关联模型
  32 + </label>
  33 + </div>
  34 + <div class="col-xs-3">
  35 + <input checked="" name="local" type="hidden" value="1">
  36 + <label class="control-label" data-toggle="tooltip" title="默认模型生成在application/admin/model目录下,选中后将生成在application/common/model目录下">
  37 + <input name="local" type="checkbox" value="0"> 全局模型类
  38 + </label>
  39 + </div>
  40 + <div class="col-xs-3">
  41 + <input checked="" name="delete" type="hidden" value="0">
  42 + <label class="control-label" data-toggle="tooltip" title="删除CRUD生成的相关文件">
  43 + <input name="delete" type="checkbox" value="1"> 删除模式
  44 + </label>
  45 + </div>
  46 + <div class="col-xs-3">
  47 + <input checked="" name="force" type="hidden" value="0">
  48 + <label class="control-label" data-toggle="tooltip" title="选中后,如果已经存在同名文件将被覆盖。如果是删除将不再提醒">
  49 + <input name="force" type="checkbox" value="1">
  50 + 强制覆盖模式
  51 + </label>
  52 + </div>
  53 + <!--
  54 + <div class="col-xs-3">
  55 + <input checked="" name="menu" type="hidden" value="0">
  56 + <label class="control-label" data-toggle="tooltip" title="选中后,将同时生成后台菜单规则">
  57 + <input name="menu" type="checkbox" value="1">
  58 + 生成菜单
  59 + </label>
  60 + </div>
  61 + -->
  62 + </div>
  63 + </div>
  64 + <div class="form-group">
  65 + <legend>主表设置</legend>
  66 + <div class="row">
  67 + <div class="col-xs-3">
  68 + <label>请选择主表</label>
  69 + {:build_select('table',$tableList,null,['class'=>'form-control selectpicker', 'data-live-search'=>'true']);}
  70 + </div>
  71 + <div class="col-xs-3">
  72 + <label>自定义控制器名</label>
  73 + <input type="text" class="form-control" name="controller" data-toggle="tooltip" title="默认根据表名自动生成,如果需要放在二级目录请手动填写" placeholder="支持目录层级,以/分隔">
  74 + </div>
  75 + <div class="col-xs-3">
  76 + <label>自定义模型名</label>
  77 + <input type="text" class="form-control" name="model" data-toggle="tooltip" title="默认根据表名自动生成" placeholder="不支持目录层级">
  78 + </div>
  79 + <div class="col-xs-3">
  80 + <label>请选择显示字段(默认全部)</label>
  81 + <select name="fields[]" id="fields" multiple style="height:30px;" class="form-control selectpicker"></select>
  82 + </div>
  83 +
  84 + </div>
  85 +
  86 + </div>
  87 +
  88 + <div class="form-group hide" id="relation-zone">
  89 + <legend>关联表设置</legend>
  90 +
  91 + <div class="row" style="margin-top:15px;">
  92 + <div class="col-xs-12">
  93 + <a href="javascript:;" class="btn btn-primary btn-sm btn-newrelation" data-index="1">追加关联模型</a>
  94 + </div>
  95 + </div>
  96 + </div>
  97 +
  98 + <hr>
  99 + <div class="form-group" id="extend-zone">
  100 + <legend>字段识别设置 <span style="font-size:12px;font-weight: normal;">(与之匹配的字段都将生成相应组件)</span></legend>
  101 + <div class="row">
  102 + <div class="col-xs-2">
  103 + <label>复选框后缀</label>
  104 + <input type="text" class="form-control" name="setcheckboxsuffix" placeholder="默认为set类型" />
  105 + </div>
  106 + <div class="col-xs-2">
  107 + <label>单选框后缀</label>
  108 + <input type="text" class="form-control" name="enumradiosuffix" placeholder="默认为enum类型" />
  109 + </div>
  110 + <div class="col-xs-2">
  111 + <label>图片类型后缀</label>
  112 + <input type="text" class="form-control" name="imagefield" placeholder="默认为image,images,avatar,avatars" />
  113 + </div>
  114 + <div class="col-xs-2">
  115 + <label>文件类型后缀</label>
  116 + <input type="text" class="form-control" name="filefield" placeholder="默认为file,files" />
  117 + </div>
  118 + <div class="col-xs-2">
  119 + <label>日期时间后缀</label>
  120 + <input type="text" class="form-control" name="intdatesuffix" placeholder="默认为time" />
  121 + </div>
  122 + <div class="col-xs-2">
  123 + <label>开关后缀</label>
  124 + <input type="text" class="form-control" name="switchsuffix" placeholder="默认为switch" />
  125 + </div>
  126 + <div class="col-xs-2">
  127 + <label>城市选择后缀</label>
  128 + <input type="text" class="form-control" name="citysuffix" placeholder="默认为city" />
  129 + </div>
  130 + <div class="col-xs-2">
  131 + <label>动态下拉后缀(单)</label>
  132 + <input type="text" class="form-control" name="selectpagesuffix" placeholder="默认为_id" />
  133 + </div>
  134 + <div class="col-xs-2">
  135 + <label>动态下拉后缀(多)</label>
  136 + <input type="text" class="form-control" name="selectpagessuffix" placeholder="默认为_ids" />
  137 + </div>
  138 + <div class="col-xs-2">
  139 + <label>忽略的字段</label>
  140 + <input type="text" class="form-control" name="ignorefields" placeholder="默认无" />
  141 + </div>
  142 + <div class="col-xs-2">
  143 + <label>排序字段</label>
  144 + <input type="text" class="form-control" name="sortfield" placeholder="默认为weigh" />
  145 + </div>
  146 + <div class="col-xs-2">
  147 + <label>富文本编辑器</label>
  148 + <input type="text" class="form-control" name="editorsuffix" placeholder="默认为content" />
  149 + </div>
  150 + <div class="col-xs-2">
  151 + <label>选项卡过滤字段</label>
  152 + <input type="text" class="form-control" name="headingfilterfield" placeholder="默认为status" />
  153 + </div>
  154 +
  155 + </div>
  156 +
  157 + </div>
  158 +
  159 + <div class="form-group">
  160 + <legend>生成命令行</legend>
  161 + <textarea class="form-control" data-toggle="tooltip" title="如果在线执行命令失败,可以将命令复制到命令行进行执行" rel="command" rows="1" placeholder="请点击生成命令行"></textarea>
  162 + </div>
  163 +
  164 + <div class="form-group">
  165 + <legend>返回结果</legend>
  166 + <textarea class="form-control" rel="result" rows="5" placeholder="请点击立即执行"></textarea>
  167 + </div>
  168 +
  169 + <div class="form-group">
  170 + <button type="button" class="btn btn-info btn-embossed btn-command">{:__('生成命令行')}</button>
  171 + <button type="button" class="btn btn-success btn-embossed btn-execute">{:__('立即执行')}</button>
  172 + </div>
  173 +
  174 + </form>
  175 + </div>
  176 + </div>
  177 + </div>
  178 + <div class="tab-pane fade" id="menu">
  179 + <div class="row">
  180 + <div class="col-xs-12">
  181 + <form role="form">
  182 + <input type="hidden" name="commandtype" value="menu" />
  183 + <div class="form-group">
  184 + <div class="row">
  185 + <div class="col-xs-3">
  186 + <input checked="" name="allcontroller" type="hidden" value="0">
  187 + <label class="control-label">
  188 + <input name="allcontroller" data-toggle="collapse" data-target="#controller" type="checkbox" value="1"> 一键生成全部控制器
  189 + </label>
  190 + </div>
  191 + <div class="col-xs-3">
  192 + <input checked="" name="delete" type="hidden" value="0">
  193 + <label class="control-label">
  194 + <input name="delete" type="checkbox" value="1"> 删除模式
  195 + </label>
  196 + </div>
  197 + <div class="col-xs-3">
  198 + <input checked="" name="force" type="hidden" value="0">
  199 + <label class="control-label">
  200 + <input name="force" type="checkbox" value="1"> 强制覆盖模式
  201 + </label>
  202 + </div>
  203 + </div>
  204 + </div>
  205 +
  206 + <div class="form-group in" id="controller">
  207 + <legend>控制器设置</legend>
  208 +
  209 + <div class="row" style="margin-top:15px;">
  210 + <div class="col-xs-12">
  211 + <input type="text" name="controllerfile" class="form-control selectpage" style="width:720px;" data-source="command/get_controller_list" data-multiple="true" name="controller" placeholder="请选择控制器" />
  212 + </div>
  213 + </div>
  214 + </div>
  215 +
  216 + <div class="form-group">
  217 + <legend>生成命令行</legend>
  218 + <textarea class="form-control" rel="command" rows="1" placeholder="请点击生成命令行"></textarea>
  219 + </div>
  220 +
  221 + <div class="form-group">
  222 + <legend>返回结果</legend>
  223 + <textarea class="form-control" rel="result" rows="5" placeholder="请点击立即执行"></textarea>
  224 + </div>
  225 +
  226 + <div class="form-group">
  227 + <button type="button" class="btn btn-info btn-embossed btn-command">{:__('生成命令行')}</button>
  228 + <button type="button" class="btn btn-success btn-embossed btn-execute">{:__('立即执行')}</button>
  229 + </div>
  230 +
  231 + </form>
  232 + </div>
  233 + </div>
  234 + </div>
  235 + <div class="tab-pane fade" id="min">
  236 + <div class="row">
  237 + <div class="col-xs-12">
  238 + <form role="form">
  239 + <input type="hidden" name="commandtype" value="min" />
  240 + <div class="form-group">
  241 + <legend>基础设置</legend>
  242 + <div class="row">
  243 + <div class="col-xs-3">
  244 + <label>请选择压缩模块</label>
  245 + <select name="module" class="form-control selectpicker">
  246 + <option value="all" selected>全部</option>
  247 + <option value="backend">后台Backend</option>
  248 + <option value="frontend">前台Frontend</option>
  249 + </select>
  250 + </div>
  251 + <div class="col-xs-3">
  252 + <label>请选择压缩资源</label>
  253 + <select name="resource" class="form-control selectpicker">
  254 + <option value="all" selected>全部</option>
  255 + <option value="js">JS</option>
  256 + <option value="css">CSS</option>
  257 + </select>
  258 + </div>
  259 + <div class="col-xs-3">
  260 + <label>请选择压缩模式</label>
  261 + <select name="optimize" class="form-control selectpicker">
  262 + <option value=""></option>
  263 + <option value="uglify">uglify</option>
  264 + <option value="closure">closure</option>
  265 + </select>
  266 + </div>
  267 + </div>
  268 + </div>
  269 +
  270 + <div class="form-group in">
  271 + <legend>控制器设置</legend>
  272 +
  273 + <div class="row" style="margin-top:15px;">
  274 + <div class="col-xs-12">
  275 +
  276 + </div>
  277 + </div>
  278 + </div>
  279 +
  280 + <div class="form-group">
  281 + <legend>生成命令行</legend>
  282 + <textarea class="form-control" rel="command" rows="1" placeholder="请点击生成命令行"></textarea>
  283 + </div>
  284 +
  285 + <div class="form-group">
  286 + <legend>返回结果</legend>
  287 + <textarea class="form-control" rel="result" rows="5" placeholder="请点击立即执行"></textarea>
  288 + </div>
  289 +
  290 + <div class="form-group">
  291 + <button type="button" class="btn btn-info btn-embossed btn-command">{:__('生成命令行')}</button>
  292 + <button type="button" class="btn btn-success btn-embossed btn-execute">{:__('立即执行')}</button>
  293 + </div>
  294 +
  295 + </form>
  296 + </div>
  297 + </div>
  298 + </div>
  299 + <div class="tab-pane fade" id="api">
  300 + <div class="row">
  301 + <div class="col-xs-12">
  302 + <form role="form">
  303 + <input type="hidden" name="commandtype" value="api" />
  304 + <div class="form-group">
  305 + <div class="row">
  306 + <div class="col-xs-3">
  307 + <input checked="" name="force" type="hidden" value="0">
  308 + <label class="control-label">
  309 + <input name="force" type="checkbox" value="1">
  310 + 覆盖模式
  311 + </label>
  312 + </div>
  313 + </div>
  314 + </div>
  315 + <div class="form-group">
  316 + <legend>文档设置</legend>
  317 + <div class="row">
  318 + <div class="col-xs-3">
  319 + <label>请输入接口URL</label>
  320 + <input type="text" name="url" class="form-control" placeholder="API URL,可留空" />
  321 + </div>
  322 + <div class="col-xs-3">
  323 + <label>接口生成文件</label>
  324 + <input type="text" name="output" class="form-control" placeholder="留空则使用api.html" />
  325 + </div>
  326 + <div class="col-xs-3">
  327 + <label>模板文件</label>
  328 + <input type="text" name="template" class="form-control" placeholder="如果不清楚请留空" />
  329 + </div>
  330 + </div>
  331 + <div class="row" style="margin-top:10px;">
  332 + <div class="col-xs-3">
  333 + <label>文档标题</label>
  334 + <input type="text" name="title" class="form-control" placeholder="默认为FastAdmin" />
  335 + </div>
  336 + <div class="col-xs-3">
  337 + <label>文档作者</label>
  338 + <input type="text" name="author" class="form-control" placeholder="默认为FastAdmin" />
  339 + </div>
  340 + <div class="col-xs-3">
  341 + <label>文档语言</label>
  342 + <select name="language" class="form-control">
  343 + <option value="" selected>请选择语言</option>
  344 + <option value="zh-cn">中文</option>
  345 + <option value="en">英文</option>
  346 + </select>
  347 + </div>
  348 + </div>
  349 + </div>
  350 +
  351 + <div class="form-group">
  352 + <legend>生成命令行</legend>
  353 + <textarea class="form-control" rel="command" rows="1" placeholder="请点击生成命令行"></textarea>
  354 + </div>
  355 +
  356 + <div class="form-group">
  357 + <legend>返回结果</legend>
  358 + <textarea class="form-control" rel="result" rows="5" placeholder="请点击立即执行"></textarea>
  359 + </div>
  360 +
  361 + <div class="form-group">
  362 + <button type="button" class="btn btn-info btn-embossed btn-command">{:__('生成命令行')}</button>
  363 + <button type="button" class="btn btn-success btn-embossed btn-execute">{:__('立即执行')}</button>
  364 + </div>
  365 +
  366 + </form>
  367 + </div>
  368 + </div>
  369 + </div>
  370 + </div>
  371 + </div>
  372 +</div>
  373 +<script id="relationtpl" type="text/html">
  374 + <div class="row relation-item">
  375 + <div class="col-xs-2">
  376 + <label>请选择关联表</label>
  377 + <select name="relation[<%=index%>][relation]" class="form-control relationtable" data-live-search="true"></select>
  378 + </div>
  379 + <div class="col-xs-2">
  380 + <label>请选择关联类型</label>
  381 + <select name="relation[<%=index%>][relationmode]" class="form-control relationmode"></select>
  382 + </div>
  383 + <div class="col-xs-2">
  384 + <label>关联外键</label>
  385 + <select name="relation[<%=index%>][relationforeignkey]" class="form-control relationforeignkey"></select>
  386 + </div>
  387 + <div class="col-xs-2">
  388 + <label>关联主键</label>
  389 + <select name="relation[<%=index%>][relationprimarykey]" class="form-control relationprimarykey"></select>
  390 + </div>
  391 + <div class="col-xs-2">
  392 + <label>请选择显示字段</label>
  393 + <select name="relation[<%=index%>][relationfields][]" multiple class="form-control relationfields"></select>
  394 + </div>
  395 + <div class="col-xs-2">
  396 + <label>&nbsp;</label>
  397 + <a href="javascript:;" class="btn btn-danger btn-block btn-removerelation">移除</a>
  398 + </div>
  399 + </div>
  400 +</script>
  1 +<table class="table table-striped">
  2 + <thead>
  3 + <tr>
  4 + <th>{:__('Title')}</th>
  5 + <th>{:__('Content')}</th>
  6 + </tr>
  7 + </thead>
  8 + <tbody>
  9 + <tr>
  10 + <td>{:__('Type')}</td>
  11 + <td>{$row.type}({$row.type_text})</td>
  12 + </tr>
  13 + <tr>
  14 + <td>{:__('Params')}</td>
  15 + <td>{$row.params}</td>
  16 + </tr>
  17 + <tr>
  18 + <td>{:__('Command')}</td>
  19 + <td>{$row.command}</td>
  20 + </tr>
  21 + <tr>
  22 + <td>{:__('Content')}</td>
  23 + <td>
  24 + <textarea class="form-control" name="" id="" cols="60" rows="10">{$row.content}</textarea>
  25 + </td>
  26 + </tr>
  27 + <tr>
  28 + <td>{:__('Executetime')}</td>
  29 + <td>{$row.executetime|datetime}</td>
  30 + </tr>
  31 + <tr>
  32 + <td>{:__('Status')}</td>
  33 + <td>{$row.status_text}</td>
  34 + </tr>
  35 + </tbody>
  36 +</table>
  37 +<div class="hide layer-footer">
  38 + <label class="control-label col-xs-12 col-sm-2"></label>
  39 + <div class="col-xs-12 col-sm-8">
  40 + <button type="reset" class="btn btn-primary btn-embossed btn-close" onclick="Layer.closeAll();">{:__('Close')}</button>
  41 + </div>
  42 +</div>
  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('command/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>
  11 + <a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('command/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>
  12 +
  13 + </div>
  14 + <table id="table" class="table table-striped table-bordered table-hover"
  15 + data-operate-detail="{:$auth->check('command/detail')}"
  16 + data-operate-execute="{:$auth->check('command/execute')}"
  17 + data-operate-del="{:$auth->check('command/del')}"
  18 + width="100%">
  19 + </table>
  20 + </div>
  21 + </div>
  22 +
  23 + </div>
  24 + </div>
  25 +</div>
  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">{:__('Time')}:</label>
  5 + <div class="col-xs-12 col-sm-8">
  6 + <input id="c-time" class="form-control datetimepicker" data-date-format="HH:mm" data-use-current="true" name="row[time]" type="text" value="{:date('H:i')}">
  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>
  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">{:__('Time')}:</label>
  5 + <div class="col-xs-12 col-sm-8">
  6 + <input id="c-time" class="form-control datetimepicker" data-date-format="HH:mm" data-use-current="true" name="row[time]" type="text" value="{:$row.time?datetime('H:i',$row.time):''}">
  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>
  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('timeslot/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('timeslot/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('timeslot/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>-->
  13 +<!-- <a href="javascript:;" class="btn btn-danger btn-import {:$auth->check('timeslot/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('timeslot/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('timeslot/edit')}"
  27 + data-operate-del="{:$auth->check('timeslot/del')}"
  28 + width="100%">
  29 + </table>
  30 + </div>
  31 + </div>
  32 +
  33 + </div>
  34 + </div>
  35 +</div>
  1 +<?php
  2 +
  3 +
  4 +namespace app\api\controller;
  5 +
  6 +
  7 +use app\api\model\Category;
  8 +use app\api\model\Goods;
  9 +use app\api\model\GoodsSpec;
  10 +use app\api\model\GoodsSpecRel;
  11 +use app\common\controller\Api;
  12 +use think\Config;
  13 +use think\Db;
  14 +
  15 +/**
  16 + * 分类页面
  17 + */
  18 +class Classification extends Api
  19 +{
  20 + protected $noNeedLogin = ['*'];
  21 + protected $noNeedRight = ['*'];
  22 +
  23 + /**
  24 + * @ApiTitle (分类列表)
  25 + * @ApiSummary (分类按钮页面左侧分类列表 其他页面切换到分类页面id不传值 分类页面点击分类id传值 后台返回高亮显示)
  26 + * @ApiMethod (POST)
  27 + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
  28 + * @ApiParams (name=id, type=integer, required=false, description="分类id")
  29 + * @ApiReturn ({
  30 + 'code':'1',
  31 + 'msg':'返回成功'
  32 + 'data':[
  33 + {
  34 + "id": 4,
  35 + "name": "电子产品",
  36 + "is_myself": "0", 0不高亮1高亮
  37 + "image_text": ""
  38 + },
  39 + {
  40 + "id": 6,
  41 + "name": "水果",
  42 + "is_myself": "0",
  43 + "image_text": ""
  44 + }
  45 + ]
  46 + })
  47 + */
  48 + public function sort()
  49 + {
  50 + $id = $this->request->post('id',0);
  51 + $model = new Category();
  52 + $list = $model->field('id,name')->select();
  53 + foreach ($list as $key => &$value){
  54 + $value['is_myself'] = $value['id']==$id?'1':'0';
  55 + }
  56 + $this->success('分类列表',$list);
  57 + }
  58 +
  59 + /**
  60 + * @ApiTitle (分类列表商品)
  61 + * @ApiSummary (分类按钮页面右侧商品列表 初次点击分类页面可不传分类id值)
  62 + * @ApiMethod (POST)
  63 + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
  64 + * @ApiParams (name=sort_id, type=integer, required=false, description="分类id")
  65 + * @ApiParams (name=page, type=integer, required=false, description="页数")
  66 + * @ApiReturn ({
  67 + 'code':'1',
  68 + 'msg':'返回成功'
  69 + 'data':{
  70 + "list": {
  71 + "total": 4, 总条数
  72 + "per_page": 10,每页数量
  73 + "current_page": 1,当前页
  74 + "last_page": 1,最后一页
  75 + "data": [
  76 + {
  77 + "goods_id": 21,
  78 + "goods_name": "小米Mix3",
  79 + "price": "100.00",
  80 + "line_price": "1000.00",划线价
  81 + "image_text": "图片路径"
  82 + }
  83 + ]
  84 + },
  85 + "image": "广告图"
  86 + }
  87 + })
  88 + */
  89 + public function sortGoodsList()
  90 + {
  91 + $sort_id = $this->request->post('sort_id',0);
  92 + $page = $this->request->post('page',1);
  93 + $model = new Goods();
  94 + if ($sort_id > 0){
  95 + $list = $model->where('is_index','1')
  96 + ->where('is_delete','0')
  97 + ->where('goods_status','10')
  98 + ->field('goods_id,goods_name,image')
  99 + ->paginate(10,false,['page'=>$page])
  100 + ->each(function ($item,$key){
  101 + $goods_spec = Db::name('litestore_goods_spec')
  102 + ->where('goods_id',$item['goods_id'])
  103 + ->find();
  104 + $item['price'] = $goods_spec['goods_price'];
  105 + $item['line_price'] = $goods_spec['line_price'];
  106 + });
  107 + }else{
  108 + $list = $model
  109 + ->field('goods_id,goods_name,image')
  110 + ->paginate(10,false,['page'=>$page])
  111 + ->each(function ($item,$key){
  112 + $goods_spec = Db::name('litestore_goods_spec')
  113 + ->where('goods_id',$item['goods_id'])
  114 + ->find();
  115 + $item['price'] = $goods_spec['goods_price'];
  116 + $item['line_price'] = $goods_spec['line_price'];
  117 + });
  118 + }
  119 + $this->success('分类商品列表',['list'=>$list,'image'=>cdnurl(Config::get('site.advert'),true)]);
  120 + }
  121 +
  122 + /**
  123 + * @ApiTitle (商品规格)
  124 + * @ApiSummary (分类按钮页面右侧商品列表 初次点击分类页面可不传分类id值)
  125 + * @ApiMethod (POST)
  126 + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
  127 + * @ApiParams (name=goods_id, type=integer, required=true, description="商品id")
  128 + * @ApiReturn ({
  129 + 'code':'1',
  130 + 'msg':'返回成功'
  131 + 'data':{
  132 + // 规格组合完毕的列表
  133 + "list": [
  134 + {
  135 + "goods_spec_id": 103,
  136 + "goods_id": 22,
  137 + "goods_no": "SNHW001",
  138 + "goods_price": "4499.00",
  139 + "line_price": "0.00",
  140 + "stock_num": 941,
  141 + "goods_sales": 58,
  142 + "goods_weight": 500,
  143 + "spec_sku_id": "44_46", // 搜索字段 组合sku里面的id搜索 从小到大排序
  144 + "spec_image": "",
  145 + "create_time": 1542784591,
  146 + "update_time": 1543242861
  147 + }
  148 + ],
  149 + // 规格展示的列表
  150 + "sku": [
  151 + {
  152 + "name": "颜色",
  153 + "second": [
  154 + {
  155 + "id": 44,
  156 + "name": "亮黑色"
  157 + }
  158 + ]
  159 + },
  160 + {
  161 + "name": "内存",
  162 + "second": [
  163 + {
  164 + "id": 46,
  165 + "name": "6GB+64GB"
  166 + }
  167 + ]
  168 + }
  169 + ]
  170 + }
  171 + })
  172 + */
  173 + public function goodsSku()
  174 + {
  175 + $goods_id = $this->request->post('goods_id');
  176 + $goodsspecrelmodel = new GoodsSpecRel();
  177 + $list = $goodsspecrelmodel
  178 + ->where('goods_id',$goods_id)
  179 + ->select();
  180 + $array = [];
  181 + foreach ($list as $key => $value){
  182 + if (!isset($array[$value['spec_id']])){
  183 + $array[$value['spec_id']]['name'] = Db::name('litestore_spec')
  184 + ->where('id',$value['spec_id'])
  185 + ->value('spec_name');
  186 + }
  187 + $spec_value =Db::name('litestore_spec_value')
  188 + ->where('id',$value['spec_value_id'])
  189 + ->value('spec_value');
  190 + $array[$value['spec_id']]['second'][] = [
  191 + 'id' => $value['spec_value_id'],
  192 + 'name' => $spec_value
  193 + ];
  194 + }
  195 + $array = array_values($array);
  196 + $goods_spec = GoodsSpec::all(['goods_id'=>$goods_id]);
  197 + $this->success('商品规格',['list'=>$goods_spec,'sku'=>$array]);
  198 + }
  199 +
  200 +}
  1 +<?php
  2 +
  3 +
  4 +namespace app\api\controller;
  5 +
  6 +
  7 +use app\api\model\GoodsComment;
  8 +use app\api\model\GoodsSpec;
  9 +use app\api\model\GoodsSpecRel;
  10 +use app\common\controller\Api;
  11 +use think\Db;
  12 +
  13 +/**
  14 + * 商品页面
  15 + */
  16 +class Goods extends Api
  17 +{
  18 + protected $noNeedRight = ['*'];
  19 + protected $noNeedLogin = ['*'];
  20 +
  21 +
  22 + /**
  23 + * @ApiTitle (商品详情)
  24 + * @ApiMethod (POST)
  25 + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
  26 + * @ApiParams (name=goods_id, type=integer, required=true, description="商品id")
  27 + * @ApiReturn ({
  28 + 'code':'1',
  29 + 'msg':'商品详情'
  30 + 'data':{
  31 + "goods_id": 22,商品id
  32 + "goods_name": "Mate 20 华为 HUAWEI ",
  33 + "spec_type": "20", 10=单规格20=多规格
  34 + "brand": null, 品牌
  35 + "makefor": null, 进口国产
  36 + "packing": null, 包装方式
  37 + "keep": null, 保存条件
  38 + "number": null, 编号
  39 + "price_description": null, 价格说明
  40 + "sales_actual": 64, 销量
  41 + "price": "4499.00", 价格
  42 + "line_price": "0.00", 划线价
  43 + "images_text": [
  44 + 轮播图
  45 + ],
  46 + "down_image_text": "底部图",
  47 + "four_image_text": [
  48 + 四宫格图
  49 + ]
  50 + }
  51 + })
  52 + */
  53 + public function goodsDetail()
  54 + {
  55 + $goods_id = $this->request->post('goods_id');
  56 + $goodsmodel = new \app\api\model\Goods();
  57 + if (!is_numeric($goods_id)){
  58 + $this->error('商品id不合法');
  59 + }
  60 + $goods = $goodsmodel::get($goods_id);
  61 + $goods_spec = Db::name('litestore_goods_spec')->where('goods_id',$goods['goods_id'])->find();
  62 + $goods['price'] = $goods_spec['goods_price'];
  63 + $goods['line_price'] = $goods_spec['line_price'];
  64 + $this->success('商品详情',$goods);
  65 + }
  66 +
  67 + /**
  68 + * @ApiTitle (商品详情页评价)
  69 + * @ApiMethod (POST)
  70 + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
  71 + * @ApiParams (name=goods_id, type=integer, required=true, description="商品id")
  72 + * @ApiReturn ({
  73 + 'code':'1',
  74 + 'msg':'商品详情页评价'
  75 + 'data':{
  76 + "comment_number": 1, 评价数量
  77 + "comment": {
  78 + "id": 1,
  79 + "user_id": null,
  80 + "goods_id": 22,
  81 + "comment": "12121212", 评论内容
  82 + "images": "1asdasd",
  83 + "score": null,
  84 + "createtime": null,
  85 + "status": "normal",
  86 + "images_text": [
  87 + 评价图片数组
  88 + "http://temporaryfood.com1asdasd"
  89 + ]
  90 + }
  91 + "user": {
  92 + "id": 1,
  93 + "nickname": "admin",
  94 + "avatar_text": "用户头像",
  95 + }
  96 + }
  97 + })
  98 + */
  99 + public function goodsDetailComment()
  100 + {
  101 + $goods_id = $this->request->post('goods_id');
  102 + if (!is_numeric($goods_id)){
  103 + $this->error('商品id不合法');
  104 + }
  105 + $model = new GoodsComment();
  106 + $goods = [];
  107 + $goods['comment_number'] = $model->where('status','normal')->count();
  108 + $goods['comment'] = $model
  109 + ->with(['user'])
  110 + ->where('goods_id',$goods_id)
  111 + ->where('status','normal')
  112 + ->order('id','desc')
  113 + ->find();
  114 + $goods['comment']->getRelation('user')->visible(['id','nickname']);
  115 + $this->success('商品详情页评价',$goods);
  116 + }
  117 +
  118 +
  119 + /**
  120 + * @ApiTitle (商品评价列表)
  121 + * @ApiMethod (POST)
  122 + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
  123 + * @ApiParams (name=goods_id, type=integer, required=true, description="商品id")
  124 + * @ApiParams (name=page, type=integer, required=false, description="页数")
  125 + * @ApiReturn ({
  126 + 'code':'1',
  127 + 'msg':'返回成功'
  128 + 'data':{
  129 + "total": 1,
  130 + "per_page": 10,
  131 + "current_page": 1,
  132 + "last_page": 1,
  133 + "data": [
  134 + {
  135 + "id": 1,
  136 + "user_id": 1,
  137 + "goods_id": 22,
  138 + "comment": "12121212",
  139 + "images": "1asdasd",
  140 + "score": null,
  141 + "createtime": null,
  142 + "status": "normal",
  143 + "user": {
  144 + "id": 1,
  145 + "nickname": "admin",
  146 + "avatar_text": ""
  147 + },
  148 + "images_text": [
  149 + "http://temporaryfood.com1asdasd"
  150 + ],
  151 + "createtime_text": ""
  152 + }
  153 + ]
  154 + }
  155 + })
  156 + */
  157 + public function goodsComment()
  158 + {
  159 + $goods_id = $this->request->post('goods_id');
  160 + $page = $this->request->post('page');
  161 + $model = new \app\api\model\GoodsComment();
  162 + if (!is_numeric($goods_id)){
  163 + $this->error('商品id不合法');
  164 + }
  165 + $lists = $model
  166 + ->with(['user'])
  167 + ->where('goods_id',$goods_id)
  168 + ->order('id','desc')
  169 + ->paginate(10,false,['page'=>$page])
  170 + ->each(function ($item,$key){
  171 + $item->getRelation('user')->visible(['id','nickname']);
  172 + });
  173 + $this->success('商品规格',$lists);
  174 + }
  175 +}
@@ -2,11 +2,15 @@ @@ -2,11 +2,15 @@
2 2
3 namespace app\api\controller; 3 namespace app\api\controller;
4 4
  5 +use app\api\model\Category;
  6 +use app\api\model\Goods;
5 use app\api\model\News; 7 use app\api\model\News;
6 use app\common\controller\Api; 8 use app\common\controller\Api;
  9 +use think\Config;
  10 +use think\Db;
7 11
8 /** 12 /**
9 - * 首页接口 13 + * 首页
10 */ 14 */
11 class Index extends Api 15 class Index extends Api
12 { 16 {
@@ -38,14 +42,122 @@ class Index extends Api @@ -38,14 +42,122 @@ class Index extends Api
38 * @ApiReturn ({ 42 * @ApiReturn ({
39 'code':'1', 43 'code':'1',
40 'msg':'返回成功' 44 'msg':'返回成功'
41 - 'data':'轮播图数组' 45 + 'data':[
  46 + {
  47 + "id": 4,
  48 + "name": "电子产品",
  49 + "image": "https://her-family.oss-cn-qingdao.aliyuncs.com/addons_store_uploads/20181105/509af801726984aaa359b4bf249f5716.png",
  50 + "image_text": "图片地址"
  51 + },
  52 + {
  53 + "id": 6,
  54 + "name": "水果",
  55 + "image": "https://her-family.oss-cn-qingdao.aliyuncs.com/addons_store_uploads/20181105/c83a0019dfa7a768037e98f02b70efd5.jpg",
  56 + "image_text": "图片地址"
  57 + }
  58 + ]
42 }) 59 })
43 */ 60 */
44 public function category() 61 public function category()
45 { 62 {
46 63
47 - $model = new Cat();  
48 - $list = $model->where('status','normal')->column('image');  
49 - $this->success('banner',$list); 64 + $model = new Category();
  65 + $list = $model->where('is_index','1')->field('id,name,image')->limit(10)->select();
  66 + $this->success('首页分类',$list);
  67 + }
  68 +
  69 + /**
  70 + * @ApiTitle (首页活动&&通知文本)
  71 + * @ApiMethod (POST)
  72 + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
  73 + * @ApiReturn ({
  74 + 'code':'1',
  75 + 'msg':'返回成功'
  76 + 'data':{
  77 + "left": {
  78 + "id": 1,
  79 + "name": "新人用户",
  80 + "place": "left"
  81 + },
  82 + "rightTop": {
  83 + "id": 2,
  84 + "name": "限时秒杀",
  85 + "place": "rightTop"
  86 + },
  87 + "rightDown": {
  88 + "id": 3,
  89 + "name": "进口商品",
  90 + "place": "rightDown"
  91 + }
  92 + "content": "首页通知文本"
  93 + }
  94 + })
  95 + */
  96 + public function activity()
  97 + {
  98 + $list = Db::name('activity')->select();
  99 + $data = [];
  100 + foreach ($list as $key => $value){
  101 + if ($value['place'] == 'left'){
  102 + $data['left'] = $value;
  103 + }elseif ($value['place'] == 'rightTop'){
  104 + $data['rightTop'] = $value;
  105 + }else{
  106 + $data['rightDown'] = $value;
  107 + }
  108 + }
  109 + $data['content'] = Config::get('site.notice');
  110 + $this->success('首页活动标题',$data);
  111 + }
  112 +
  113 +
  114 + /**
  115 + * @ApiTitle (猜你喜欢)
  116 + * @ApiMethod (POST)
  117 + * @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
  118 + * @ApiParams (name=page, type=integer, required=false, description="页数 默认1")
  119 + * @ApiReturn ({
  120 + 'code':'1',
  121 + 'msg':'返回成功'
  122 + 'data':{
  123 + "total": 4,
  124 + "per_page": 10,
  125 + "current_page": 1,
  126 + "last_page": 1,
  127 + "data": [
  128 + {
  129 + "goods_id": 21,
  130 + "goods_name": "小米Mix3",
  131 + "image": null,
  132 + "cart_number": 10, 购物车数量
  133 + "price": "100.00", 价格
  134 + "line_price": "1000.00", 划线价
  135 + "image_text": "图片地址"
50 } 136 }
  137 + ]
  138 + })
  139 + */
  140 + public function userLike()
  141 + {
  142 + $page = $this->request->post('page',1);
  143 + $model = new Goods();
  144 + $list = $model->where('is_index','1')
  145 + ->where('is_delete','0')
  146 + ->where('goods_status','10')
  147 + ->field('goods_id,goods_name,image')
  148 + ->paginate(10,false,['page'=>$page])
  149 + ->each(function ($item,$key){
  150 + $item['cart_number'] = Db::name('cart')
  151 + ->where('user_id',$this->auth->id)
  152 + ->where('goods_id',$item['goods_id'])
  153 + ->sum('number');
  154 + $goods_spec = Db::name('litestore_goods_spec')
  155 + ->where('goods_id',$item['goods_id'])
  156 + ->find();
  157 + $item['price'] = $goods_spec['goods_price'];
  158 + $item['line_price'] = $goods_spec['line_price'];
  159 + });
  160 + $this->success('猜你喜欢',$list);
  161 + }
  162 +
51 } 163 }
  1 +<?php
  2 +
  3 +
  4 +namespace app\api\model;
  5 +
  6 +
  7 +use think\Model;
  8 +
  9 +class Goods extends Model
  10 +{
  11 + protected $name = 'litestore_goods';
  12 + protected $append = [
  13 + 'image_text',
  14 + 'images_text',
  15 + 'down_image_text',
  16 + 'four_image_text'
  17 + ];
  18 +
  19 + public function getImageTextAttr($value,$data)
  20 + {
  21 + $value = !empty($data['image']) ? cdnurl($data['image'],true):'';
  22 + return $value;
  23 + }
  24 +
  25 + public function getFourImageTextAttr($value,$data)
  26 + {
  27 + $value = !empty($data['four_image']) ? explode(',',$data['four_image']):[];
  28 + foreach ($value as $key => &$val){
  29 + $val = cdnurl($val,true);
  30 + }
  31 + return $value;
  32 + }
  33 +
  34 + public function getImagesTextAttr($value,$data)
  35 + {
  36 + $value = !empty($data['images']) ? explode(',',$data['images']):[];
  37 + foreach ($value as $key => &$val){
  38 + $val = cdnurl($val,true);
  39 + }
  40 + return $value;
  41 + }
  42 +
  43 + public function getDownImageTextAttr($value,$data)
  44 + {
  45 + $value = !empty($data['down_image']) ? cdnurl($data['down_image'],true):'';
  46 + return $value;
  47 + }
  48 +}
  1 +<?php
  2 +
  3 +
  4 +namespace app\api\model;
  5 +
  6 +
  7 +use think\Model;
  8 +
  9 +class GoodsComment extends Model
  10 +{
  11 + protected $append = [
  12 + 'images_text',
  13 + 'createtime_text'
  14 + ];
  15 +
  16 + public function getImagesTextAttr($value,$data)
  17 + {
  18 + $value = !empty($data['images'])?explode(',',$data['images']):[];
  19 + foreach ($value as $key => &$val){
  20 + $val = cdnurl($val,true);
  21 + }
  22 + return $value;
  23 + }
  24 +
  25 + public function getCreatetimeTextAttr($value,$data)
  26 + {
  27 + $value = !empty($data['createtime'])?date('Y-m-d',$data['createtime']):'';
  28 + return $value;
  29 + }
  30 +
  31 + public function user()
  32 + {
  33 + return $this->belongsTo('User','user_id','id');
  34 + }
  35 +}
  1 +<?php
  2 +
  3 +
  4 +namespace app\api\model;
  5 +
  6 +
  7 +use think\Model;
  8 +
  9 +class GoodsSpec extends Model
  10 +{
  11 + protected $name = 'litestore_goods_spec';
  12 +}
  1 +<?php
  2 +
  3 +
  4 +namespace app\api\model;
  5 +
  6 +
  7 +use think\Model;
  8 +
  9 +class GoodsSpecRel extends Model
  10 +{
  11 + protected $name = 'litestore_goods_spec_rel';
  12 +
  13 + public function spec()
  14 + {
  15 + return $this->belongsTo('Spec','spec_id','id');
  16 + }
  17 +
  18 + public function specvalue()
  19 + {
  20 + return $this->belongsTo('SpecValue','spec_value_id','id');
  21 + }
  22 +}
  1 +<?php
  2 +
  3 +
  4 +namespace app\api\model;
  5 +
  6 +
  7 +use think\Model;
  8 +
  9 +class Spec extends Model
  10 +{
  11 + protected $name = 'litestore_spec';
  12 +}
  1 +<?php
  2 +
  3 +
  4 +namespace app\api\model;
  5 +
  6 +
  7 +use think\Model;
  8 +
  9 +class SpecValue extends Model
  10 +{
  11 + protected $name = 'litestore_spec_value';
  12 +}
  1 +<?php
  2 +
  3 +
  4 +namespace app\api\model;
  5 +
  6 +
  7 +use think\Model;
  8 +
  9 +class User extends Model
  10 +{
  11 + protected $append = [
  12 + 'avatar_text'
  13 + ];
  14 +
  15 + public function getAvatarTextAttr($value,$data)
  16 + {
  17 + $value = !empty($data['avatar'])?cdnurl($data['avatar'],true):'';
  18 + return $value;
  19 + }
  20 +}
@@ -4,6 +4,7 @@ namespace app\common\controller; @@ -4,6 +4,7 @@ namespace app\common\controller;
4 4
5 use app\common\library\Auth; 5 use app\common\library\Auth;
6 use think\Config; 6 use think\Config;
  7 +use think\Db;
7 use think\exception\HttpResponseException; 8 use think\exception\HttpResponseException;
8 use think\exception\ValidateException; 9 use think\exception\ValidateException;
9 use think\Hook; 10 use think\Hook;
@@ -324,4 +325,55 @@ class Api @@ -324,4 +325,55 @@ class Api
324 //刷新Token 325 //刷新Token
325 $this->request->token(); 326 $this->request->token();
326 } 327 }
  328 +
  329 + /**
  330 + * 获取秒杀时间段列表
  331 + * @return array
  332 + */
  333 + protected function timeplot()
  334 + {
  335 + $time = time();
  336 + $data = Db::name('timeslot')->column('time');
  337 + foreach ($data as $key => $value){
  338 + $data[$key] = strtotime($value);
  339 + }
  340 + asort($data);
  341 + $count = count($data);
  342 + for ($i = 0,$j = 1;$i<$count-1,$j<$count;$i++,$j++){
  343 + if ($data[$i] <= $time && $data[$j] > $time){
  344 + $data[$i] = [
  345 + 'time'=>date('H:i',$data[$i]),
  346 + 'status' => 'begin'
  347 + ];
  348 + $data[$j] = [
  349 + 'time'=>date('H:i',$data[$j]),
  350 + 'status' => 'will'
  351 + ];
  352 + $i++;$j++;
  353 + }elseif($data[$i] < $time){
  354 + $data[$i] = [
  355 + 'time'=>date('H:i',$data[$i]),
  356 + 'status' => 'over'
  357 + ];
  358 + }elseif($i==0&&$data[$i] > $time){
  359 + $data[$i] = [
  360 + 'time'=>date('H:i',$data[$i]),
  361 + 'status' => 'will'
  362 + ];
  363 + }else{
  364 + $data[$i] = [
  365 + 'time'=>date('H:i',$data[$i]),
  366 + 'status' => 'not'
  367 + ];
  368 + }
  369 + if ($count-$j == 1){
  370 + $data[$j] = [
  371 + 'time'=>date('H:i',$data[$j]),
  372 + 'status' => $data[$j] > $time ? 'not':'begin'
  373 + ];
  374 + }
  375 + }
  376 + var_dump($data);exit();
  377 + return array_values($data);
  378 + }
327 } 379 }
@@ -43,4 +43,6 @@ return array ( @@ -43,4 +43,6 @@ return array (
43 ), 43 ),
44 'user_agreement' => '<p>64645646564公开警告</p><p>;回来了框架</p>', 44 'user_agreement' => '<p>64645646564公开警告</p><p>;回来了框架</p>',
45 'privacy_agreement' => '<p>45315448</p><p>他房间后</p>', 45 'privacy_agreement' => '<p>45315448</p><p>他房间后</p>',
  46 + 'notice' => '阿达萨达萨达撒旦撒旦',
  47 + 'advert' => '/assets/img/qrcode.png',
46 ); 48 );
  1 +define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function ($, undefined, Backend, Table, Form, Template) {
  2 +
  3 + var Controller = {
  4 + index: function () {
  5 + // 初始化表格参数配置
  6 + Table.api.init({
  7 + extend: {
  8 + index_url: 'command/index',
  9 + add_url: 'command/add',
  10 + edit_url: '',
  11 + del_url: 'command/del',
  12 + multi_url: 'command/multi',
  13 + table: 'command',
  14 + }
  15 + });
  16 +
  17 + var table = $("#table");
  18 +
  19 + // 初始化表格
  20 + table.bootstrapTable({
  21 + url: $.fn.bootstrapTable.defaults.extend.index_url,
  22 + pk: 'id',
  23 + sortName: 'id',
  24 + columns: [
  25 + [
  26 + {checkbox: true},
  27 + {field: 'id', title: __('Id')},
  28 + {field: 'type', title: __('Type'), formatter: Table.api.formatter.search},
  29 + {field: 'type_text', title: __('Type')},
  30 + {
  31 + field: 'command', title: __('Command'), formatter: function (value, row, index) {
  32 + return '<input type="text" class="form-control" value="' + value + '">';
  33 + }
  34 + },
  35 + {
  36 + field: 'executetime',
  37 + title: __('Executetime'),
  38 + operate: 'RANGE',
  39 + addclass: 'datetimerange',
  40 + formatter: Table.api.formatter.datetime
  41 + },
  42 + {
  43 + field: 'createtime',
  44 + title: __('Createtime'),
  45 + operate: 'RANGE',
  46 + addclass: 'datetimerange',
  47 + formatter: Table.api.formatter.datetime
  48 + },
  49 + {
  50 + field: 'updatetime',
  51 + title: __('Updatetime'),
  52 + operate: 'RANGE',
  53 + addclass: 'datetimerange',
  54 + formatter: Table.api.formatter.datetime
  55 + },
  56 + {
  57 + field: 'status',
  58 + title: __('Status'),
  59 + table: table,
  60 + custom: {"successed": 'success', "failured": 'danger'},
  61 + searchList: {"successed": __('Successed'), "failured": __('Failured')},
  62 + formatter: Table.api.formatter.status
  63 + },
  64 + {
  65 + field: 'operate',
  66 + title: __('Operate'),
  67 + buttons: [
  68 + {
  69 + name: 'execute',
  70 + title: __('Execute again'),
  71 + text: __('Execute again'),
  72 + url: 'command/execute',
  73 + icon: 'fa fa-repeat',
  74 + classname: 'btn btn-success btn-xs btn-execute btn-ajax',
  75 + success: function (data) {
  76 + Layer.alert("<textarea class='form-control' cols='60' rows='5'>" + data.result + "</textarea>", {
  77 + title: __("执行结果"),
  78 + shadeClose: true
  79 + });
  80 + table.bootstrapTable('refresh');
  81 + return false;
  82 + }
  83 + },
  84 + {
  85 + name: 'execute',
  86 + title: __('Detail'),
  87 + text: __('Detail'),
  88 + url: 'command/detail',
  89 + icon: 'fa fa-list',
  90 + classname: 'btn btn-info btn-xs btn-execute btn-dialog'
  91 + }
  92 + ],
  93 + table: table,
  94 + events: Table.api.events.operate,
  95 + formatter: Table.api.formatter.operate
  96 + }
  97 + ]
  98 + ]
  99 + });
  100 +
  101 + // 为表格绑定事件
  102 + Table.api.bindevent(table);
  103 + },
  104 + add: function () {
  105 + require(['bootstrap-select', 'bootstrap-select-lang']);
  106 + var mainfields = [];
  107 + var relationfields = {};
  108 + var maintable = [];
  109 + var relationtable = [];
  110 + var relationmode = ["belongsto", "hasone"];
  111 +
  112 + var renderselect = function (select, data) {
  113 + var html = [];
  114 + for (var i = 0; i < data.length; i++) {
  115 + html.push("<option value='" + data[i] + "'>" + data[i] + "</option>");
  116 + }
  117 + $(select).html(html.join(""));
  118 + select.trigger("change");
  119 + if (select.data("selectpicker")) {
  120 + select.selectpicker('refresh');
  121 + }
  122 + return select;
  123 + };
  124 +
  125 + $("select[name=table] option").each(function () {
  126 + maintable.push($(this).val());
  127 + });
  128 + $(document).on('change', "input[name='isrelation']", function () {
  129 + $("#relation-zone").toggleClass("hide", !$(this).prop("checked"));
  130 + });
  131 + $(document).on('change', "select[name='table']", function () {
  132 + var that = this;
  133 + Fast.api.ajax({
  134 + url: "command/get_field_list",
  135 + data: {table: $(that).val()},
  136 + }, function (data, ret) {
  137 + mainfields = data.fieldlist;
  138 + $("#relation-zone .relation-item").remove();
  139 + renderselect($("#fields"), mainfields);
  140 + return false;
  141 + });
  142 + return false;
  143 + });
  144 + $(document).on('click', "a.btn-newrelation", function () {
  145 + var that = this;
  146 + var index = parseInt($(that).data("index")) + 1;
  147 + var content = Template("relationtpl", {index: index});
  148 + content = $(content.replace(/\[index\]/, index));
  149 + $(this).data("index", index);
  150 + $(content).insertBefore($(that).closest(".row"));
  151 + $('select', content).selectpicker();
  152 + var exists = [$("select[name='table']").val()];
  153 + $("select.relationtable").each(function () {
  154 + exists.push($(this).val());
  155 + });
  156 + relationtable = [];
  157 + $.each(maintable, function (i, j) {
  158 + if ($.inArray(j, exists) < 0) {
  159 + relationtable.push(j);
  160 + }
  161 + });
  162 + renderselect($("select.relationtable", content), relationtable);
  163 + $("select.relationtable", content).trigger("change");
  164 + });
  165 + $(document).on('click', "a.btn-removerelation", function () {
  166 + $(this).closest(".row").remove();
  167 + });
  168 + $(document).on('change', "#relation-zone select.relationmode", function () {
  169 + var table = $("select.relationtable", $(this).closest(".row")).val();
  170 + var that = this;
  171 + Fast.api.ajax({
  172 + url: "command/get_field_list",
  173 + data: {table: table},
  174 + }, function (data, ret) {
  175 + renderselect($(that).closest(".row").find("select.relationprimarykey"), $(that).val() == 'belongsto' ? data.fieldlist : mainfields);
  176 + renderselect($(that).closest(".row").find("select.relationforeignkey"), $(that).val() == 'hasone' ? data.fieldlist : mainfields);
  177 + return false;
  178 + });
  179 + });
  180 + $(document).on('change', "#relation-zone select.relationtable", function () {
  181 + var that = this;
  182 + Fast.api.ajax({
  183 + url: "command/get_field_list",
  184 + data: {table: $(that).val()},
  185 + }, function (data, ret) {
  186 + renderselect($(that).closest(".row").find("select.relationmode"), relationmode);
  187 + renderselect($(that).closest(".row").find("select.relationfields"), mainfields)
  188 + renderselect($(that).closest(".row").find("select.relationforeignkey"), data.fieldlist)
  189 + renderselect($(that).closest(".row").find("select.relationfields"), data.fieldlist)
  190 + return false;
  191 + });
  192 + });
  193 + $(document).on('click', ".btn-command", function () {
  194 + var form = $(this).closest("form");
  195 + var textarea = $("textarea[rel=command]", form);
  196 + textarea.val('');
  197 + Fast.api.ajax({
  198 + url: "command/command/action/command",
  199 + data: form.serialize(),
  200 + }, function (data, ret) {
  201 + textarea.val(data.command);
  202 + return false;
  203 + });
  204 + });
  205 + $(document).on('click', ".btn-execute", function () {
  206 + var form = $(this).closest("form");
  207 + var textarea = $("textarea[rel=result]", form);
  208 + textarea.val('');
  209 + Fast.api.ajax({
  210 + url: "command/command/action/execute",
  211 + data: form.serialize(),
  212 + }, function (data, ret) {
  213 + textarea.val(data.result);
  214 + window.parent.$(".toolbar .btn-refresh").trigger('click');
  215 + top.window.Fast.api.refreshmenu();
  216 + return false;
  217 + }, function () {
  218 + window.parent.$(".toolbar .btn-refresh").trigger('click');
  219 + });
  220 + });
  221 + $("select[name='table']").trigger("change");
  222 + Controller.api.bindevent();
  223 + },
  224 + edit: function () {
  225 + Controller.api.bindevent();
  226 + },
  227 + api: {
  228 + bindevent: function () {
  229 + Form.api.bindevent($("form[role=form]"));
  230 + }
  231 + }
  232 + };
  233 + return Controller;
  234 +});
  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: 'timeslot/index' + location.search,
  9 + add_url: 'timeslot/add',
  10 + edit_url: 'timeslot/edit',
  11 + // del_url: 'timeslot/del',
  12 + multi_url: 'timeslot/multi',
  13 + import_url: 'timeslot/import',
  14 + table: 'timeslot',
  15 + }
  16 + });
  17 +
  18 + var table = $("#table");
  19 +
  20 + // 初始化表格
  21 + table.bootstrapTable({
  22 + url: $.fn.bootstrapTable.defaults.extend.index_url,
  23 + pk: 'id',
  24 + sortName: 'id',
  25 + search:false,
  26 + showSearch:false,
  27 + showExport:false,
  28 + columns: [
  29 + [
  30 + // {checkbox: true},
  31 + // {field: 'id', title: __('Id')},
  32 + {field: 'time', title: __('Time'), operate: 'LIKE'},
  33 + {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
  34 + ]
  35 + ]
  36 + });
  37 +
  38 + // 为表格绑定事件
  39 + Table.api.bindevent(table);
  40 + },
  41 + add: function () {
  42 + Controller.api.bindevent();
  43 + },
  44 + edit: function () {
  45 + Controller.api.bindevent();
  46 + },
  47 + api: {
  48 + bindevent: function () {
  49 + Form.api.bindevent($("form[role=form]"));
  50 + }
  51 + }
  52 + };
  53 + return Controller;
  54 +});