diff --git a/addons/command/.addonrc b/addons/command/.addonrc new file mode 100644 index 0000000..426decf --- /dev/null +++ b/addons/command/.addonrc @@ -0,0 +1 @@ +{"files":["application\/admin\/validate\/Command.php","application\/admin\/controller\/Command.php","application\/admin\/lang\/zh-cn\/command.php","application\/admin\/model\/Command.php","application\/admin\/view\/command\/index.html","application\/admin\/view\/command\/add.html","application\/admin\/view\/command\/detail.html","public\/assets\/js\/backend\/command.js"],"license":"regular","licenseto":"98870","licensekey":"z9dMrLGQoCK7qN0T mJHxiy1bfG0ZfYKrR3mi7w==","domains":["0.1"],"licensecodes":[],"validations":["cbeddc9996d1ba6c230fc0319ab4d521"],"menus":["command","command\/index","command\/add","command\/detail","command\/command","command\/execute","command\/del","command\/multi"]} \ No newline at end of file diff --git a/addons/command/Command.php b/addons/command/Command.php new file mode 100755 index 0000000..1bbb1e2 --- /dev/null +++ b/addons/command/Command.php @@ -0,0 +1,70 @@ + 'command', + 'title' => '在线命令管理', + 'icon' => 'fa fa-terminal', + 'sublist' => [ + ['name' => 'command/index', 'title' => '查看'], + ['name' => 'command/add', 'title' => '添加'], + ['name' => 'command/detail', 'title' => '详情'], + ['name' => 'command/command', 'title' => '生成并执行命令'], + ['name' => 'command/execute', 'title' => '再次执行命令'], + ['name' => 'command/del', 'title' => '删除'], + ['name' => 'command/multi', 'title' => '批量更新'], + ] + ] + ]; + Menu::create($menu); + return true; + } + + /** + * 插件卸载方法 + * @return bool + */ + public function uninstall() + { + Menu::delete('command'); + return true; + } + + /** + * 插件启用方法 + * @return bool + */ + public function enable() + { + Menu::enable('command'); + return true; + } + + /** + * 插件禁用方法 + * @return bool + */ + public function disable() + { + Menu::disable('command'); + return true; + } + +} diff --git a/addons/command/config.php b/addons/command/config.php new file mode 100755 index 0000000..b625128 --- /dev/null +++ b/addons/command/config.php @@ -0,0 +1,4 @@ +error("当前插件暂无前台页面"); + } + +} diff --git a/addons/command/info.ini b/addons/command/info.ini new file mode 100644 index 0000000..65cf366 --- /dev/null +++ b/addons/command/info.ini @@ -0,0 +1,10 @@ +name = command +title = 在线命令 +intro = 可在线执行一键生成CRUD、一键生成菜单等相关命令 +author = FastAdmin +website = https://www.fastadmin.net +version = 1.1.2 +state = 1 +url = http://127.0.0.1:8088/addons/command +license = regular +licenseto = 98870 diff --git a/addons/command/install.sql b/addons/command/install.sql new file mode 100755 index 0000000..c584dbc --- /dev/null +++ b/addons/command/install.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS `__PREFIX__command` ( + `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID', + `type` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '类型', + `params` varchar(1500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '参数', + `command` varchar(1500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '命令', + `content` text COMMENT '返回结果', + `executetime` bigint(16) UNSIGNED DEFAULT NULL COMMENT '执行时间', + `createtime` bigint(16) UNSIGNED DEFAULT NULL COMMENT '创建时间', + `updatetime` bigint(16) UNSIGNED DEFAULT NULL COMMENT '更新时间', + `status` enum('successed','failured') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'failured' COMMENT '状态', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '在线命令表'; diff --git a/addons/command/library/Output.php b/addons/command/library/Output.php new file mode 100755 index 0000000..aba7982 --- /dev/null +++ b/addons/command/library/Output.php @@ -0,0 +1,28 @@ +message[] = $message; + } + + public function getMessage() + { + return $this->message; + } + +} diff --git a/application/admin/controller/Command.php b/application/admin/controller/Command.php new file mode 100644 index 0000000..9c4cf45 --- /dev/null +++ b/application/admin/controller/Command.php @@ -0,0 +1,248 @@ +model = new \app\admin\model\Command; + $this->view->assign("statusList", $this->model->getStatusList()); + } + + /** + * 添加 + */ + public function add() + { + + $tableList = []; + $list = \think\Db::query("SHOW TABLES"); + foreach ($list as $key => $row) { + $tableList[reset($row)] = reset($row); + } + + $this->view->assign("tableList", $tableList); + return $this->view->fetch(); + } + + /** + * 获取字段列表 + * @internal + */ + public function get_field_list() + { + $dbname = Config::get('database.database'); + $prefix = Config::get('database.prefix'); + $table = $this->request->request('table'); + //从数据库中获取表字段信息 + $sql = "SELECT * FROM `information_schema`.`columns` " + . "WHERE TABLE_SCHEMA = ? AND table_name = ? " + . "ORDER BY ORDINAL_POSITION"; + //加载主表的列 + $columnList = Db::query($sql, [$dbname, $table]); + $fieldlist = []; + foreach ($columnList as $index => $item) { + $fieldlist[] = $item['COLUMN_NAME']; + } + $this->success("", null, ['fieldlist' => $fieldlist]); + } + + /** + * 获取控制器列表 + * @internal + */ + public function get_controller_list() + { + //搜索关键词,客户端输入以空格分开,这里接收为数组 + $word = (array)$this->request->request("q_word/a"); + $word = implode('', $word); + + $adminPath = dirname(__DIR__) . DS; + $controllerDir = $adminPath . 'controller' . DS; + $files = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($controllerDir), \RecursiveIteratorIterator::LEAVES_ONLY + ); + $list = []; + foreach ($files as $name => $file) { + if (!$file->isDir()) { + $filePath = $file->getRealPath(); + $name = str_replace($controllerDir, '', $filePath); + $name = str_replace(DS, "/", $name); + if (!preg_match("/(.*)\.php\$/", $name)) { + continue; + } + if (!$word || stripos($name, $word) !== false) { + $list[] = ['id' => $name, 'name' => $name]; + } + } + } + $pageNumber = $this->request->request("pageNumber"); + $pageSize = $this->request->request("pageSize"); + return json(['list' => array_slice($list, ($pageNumber - 1) * $pageSize, $pageSize), 'total' => count($list)]); + } + + /** + * 详情 + */ + public function detail($ids) + { + $row = $this->model->get($ids); + if (!$row) { + $this->error(__('No Results were found')); + } + $this->view->assign("row", $row); + return $this->view->fetch(); + } + + /** + * 执行 + */ + public function execute($ids) + { + $row = $this->model->get($ids); + if (!$row) { + $this->error(__('No Results were found')); + } + $result = $this->doexecute($row['type'], json_decode($row['params'], true)); + $this->success("", null, ['result' => $result]); + } + + /** + * 生成命令 + */ + public function command($action = '') + { + $commandtype = $this->request->request("commandtype"); + $params = $this->request->request(); + $allowfields = [ + 'crud' => 'table,controller,model,fields,force,local,delete,menu', + 'menu' => 'controller,delete,force', + 'min' => 'module,resource,optimize', + 'api' => 'url,module,output,template,force,title,author,class,language,addon', + ]; + $argv = []; + $allowfields = isset($allowfields[$commandtype]) ? explode(',', $allowfields[$commandtype]) : []; + $allowfields = array_filter(array_intersect_key($params, array_flip($allowfields))); + if (isset($params['local']) && !$params['local']) { + $allowfields['local'] = $params['local']; + } else { + unset($allowfields['local']); + } + foreach ($allowfields as $key => $param) { + $argv[] = "--{$key}=" . (is_array($param) ? implode(',', $param) : $param); + } + if ($commandtype == 'crud') { + $extend = 'setcheckboxsuffix,enumradiosuffix,imagefield,filefield,intdatesuffix,switchsuffix,citysuffix,selectpagesuffix,selectpagessuffix,ignorefields,sortfield,editorsuffix,headingfilterfield,tagsuffix,jsonsuffix,fixedcolumns'; + $extendArr = explode(',', $extend); + foreach ($params as $index => $item) { + if (in_array($index, $extendArr)) { + foreach (explode(',', $item) as $key => $value) { + if ($value) { + $argv[] = "--{$index}={$value}"; + } + } + } + } + $isrelation = (int)$this->request->request('isrelation'); + if ($isrelation && isset($params['relation'])) { + foreach ($params['relation'] as $index => $relation) { + foreach ($relation as $key => $value) { + $argv[] = "--{$key}=" . (is_array($value) ? implode(',', $value) : $value); + } + } + } + } else { + if ($commandtype == 'menu') { + if (isset($params['allcontroller']) && $params['allcontroller']) { + $argv[] = "--controller=all-controller"; + } else { + foreach (explode(',', $params['controllerfile']) as $index => $param) { + if ($param) { + $argv[] = "--controller=" . substr($param, 0, -4); + } + } + } + } else { + if ($commandtype == 'min') { + + } else { + if ($commandtype == 'api') { + + } else { + + } + } + } + } + if ($action == 'execute') { + if (stripos(implode(' ', $argv), '--controller=all-controller') !== false) { + $this->error("只允许在命令行执行该命令,执行前请做好菜单规则备份!!!"); + } + if (config('app_debug')) { + $result = $this->doexecute($commandtype, $argv); + $this->success("", null, ['result' => $result]); + } else { + $this->error("只允许在开发环境下执行命令"); + } + } else { + $this->success("", null, ['command' => "php think {$commandtype} " . implode(' ', $argv)]); + } + + return; + } + + protected function doexecute($commandtype, $argv) + { + if (!config('app_debug')) { + $this->error("只允许在开发环境下执行命令"); + } + if (preg_match("/([;\|&]+)/", implode(' ', $argv))) { + $this->error("不支持的命令参数"); + } + $commandName = "\\app\\admin\\command\\" . ucfirst($commandtype); + $input = new Input($argv); + $output = new \addons\command\library\Output(); + $command = new $commandName($commandtype); + $data = [ + 'type' => $commandtype, + 'params' => json_encode($argv), + 'command' => "php think {$commandtype} " . implode(' ', $argv), + 'executetime' => time(), + ]; + $this->model->save($data); + try { + $command->run($input, $output); + $result = implode("\n", $output->getMessage()); + $this->model->status = 'successed'; + } catch (Exception $e) { + $result = implode("\n", $output->getMessage()) . "\n"; + $result .= $e->getMessage(); + $this->model->status = 'failured'; + } + $result = trim($result); + $this->model->content = $result; + $this->model->save(); + return $result; + } + +} diff --git a/application/admin/controller/Order.php b/application/admin/controller/Order.php new file mode 100644 index 0000000..94d7899 --- /dev/null +++ b/application/admin/controller/Order.php @@ -0,0 +1,97 @@ +model = new \app\admin\model\Order; + $this->view->assign("statusList", $this->model->getStatusList()); + $this->view->assign("collectList", $this->model->getCollectList()); + $this->view->assign("dispatchTypeList", $this->model->getDispatchTypeList()); + } + + + + /** + * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 + * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 + * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 + */ + + + + public function index() + { + $this->request->filter(['strip_tags', 'trim']); + if (false === $this->request->isAjax()) { + return $this->view->fetch(); + } + //如果发送的来源是 Selectpage,则转发到 Selectpage + if ($this->request->request('keyField')) { + return $this->selectpage(); + } + [$where, $sort, $order, $offset, $limit] = $this->buildparams(); + $list = $this->model + ->where($where) + ->order($sort, $order) + ->paginate($limit); + $result = ['total' => $list->total(), 'rows' => $list->items()]; + return json($result); + } + + public function add() + { + if (false === $this->request->isPost()) { + return $this->view->fetch(); + } + $params = $this->request->post('row/a'); + if (empty($params)) { + $this->error(__('Parameter %s can not be empty', '')); + } + $params = $this->preExcludeFields($params); + + if ($this->dataLimit && $this->dataLimitFieldAutoFill) { + $params[$this->dataLimitField] = $this->auth->id; + } + dd($params); + $result = false; + Db::startTrans(); + try { + //是否采用模型验证 + if ($this->modelValidate) { + $name = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate; + $this->model->validateFailException()->validate($validate); + } + $result = $this->model->allowField(true)->save($params); + Db::commit(); + } catch (ValidateException|PDOException|Exception $e) { + Db::rollback(); + $this->error($e->getMessage()); + } + if ($result === false) { + $this->error(__('No rows were inserted')); + } + $this->success(); + } +} diff --git a/application/admin/lang/zh-cn/command.php b/application/admin/lang/zh-cn/command.php new file mode 100644 index 0000000..b010250 --- /dev/null +++ b/application/admin/lang/zh-cn/command.php @@ -0,0 +1,16 @@ + 'ID', + 'Type' => '类型', + 'Params' => '参数', + 'Command' => '命令', + 'Content' => '返回结果', + 'Executetime' => '执行时间', + 'Createtime' => '创建时间', + 'Updatetime' => '更新时间', + 'Execute again' => '再次执行', + 'Successed' => '成功', + 'Failured' => '失败', + 'Status' => '状态' +]; diff --git a/application/admin/lang/zh-cn/order.php b/application/admin/lang/zh-cn/order.php new file mode 100644 index 0000000..0b1eaaf --- /dev/null +++ b/application/admin/lang/zh-cn/order.php @@ -0,0 +1,61 @@ + 'ID', + 'Order_no' => '订单号', + 'Customer' => '客户姓名', + 'Tel' => '客户电话', + 'Status' => '订单状态', + 'Status 10' => '未派单', + 'Set status to 10' => '设为未派单', + 'Status 20' => '已派单', + 'Set status to 20' => '设为已派单', + 'Status 30' => '已接单', + 'Set status to 30' => '设为已接单', + 'Status 40' => '处理中', + 'Set status to 40' => '设为处理中', + 'Status 50' => '已完成', + 'Set status to 50' => '设为已完成', + 'Status -10' => '取消', + 'Set status to -10' => '设为取消', + 'Status -20' => '作废', + 'Set status to -20' => '设为作废', + 'Status -30' => '已拒接', + 'Set status to -30' => '设为已拒接', + 'Area_id' => '地域', + 'Address' => '详细地址', + 'Work_tel_id' => '工作机', + 'Worker_id' => '师傅ID', + 'Source' => '订单来源', + 'Source_uid' => '来源UID', + 'Service_id' => '服务ID', + 'Service_title' => '服务名称', + 'Detail' => '订单详情', + 'Remark' => '订单备注', + 'Images' => '图片', + 'Collect' => '是否收藏', + 'Collect 0' => '否', + 'Collect 1' => '是', + 'Collect_remark' => '收藏备注', + 'Enter_admin_id' => '录单员ID', + 'Dispatch_admin_id' => '派单员ID', + 'Dispatch_type' => '派单方式', + 'Dispatch_type 10' => '线上手动', + 'Dispatch_type 11' => '线上自动', + 'Dispatch_type 20' => '线下', + 'Total' => '总收款', + 'Cost' => '成本', + 'Performance' => '绩效', + 'Sb_amount' => '垫付', + 'Real_amount' => '实付', + 'Cancel_reason_id' => '取消原因', + 'Cancel_detail' => '取消详情', + 'Abolish_reason_id' => '作废原因', + 'Abolish_detail' => '作废详情', + 'Create_time' => '录单时间', + 'Update_time' => '更新时间', + 'Payment_time' => '付款时间', + 'Finishe_time' => '完成时间', + 'Dispatch_time' => '派单时间', + 'Delete_time' => '删除时间' +]; diff --git a/application/admin/model/Command.php b/application/admin/model/Command.php new file mode 100644 index 0000000..adede4d --- /dev/null +++ b/application/admin/model/Command.php @@ -0,0 +1,59 @@ + __('Successed'), 'failured' => __('Failured')]; + } + + + public function getExecutetimeTextAttr($value, $data) + { + $value = $value ? $value : $data['executetime']; + return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value; + } + + public function getTypeTextAttr($value, $data) + { + $value = $value ? $value : $data['type']; + $list = ['crud' => '一键生成CRUD', 'menu' => '一键生成菜单', 'min' => '一键压缩打包', 'api' => '一键生成文档']; + return $list[$value] ?? ''; + } + + public function getStatusTextAttr($value, $data) + { + $value = $value ? $value : $data['status']; + $list = $this->getStatusList(); + return $list[$value] ?? ''; + } + + protected function setExecutetimeAttr($value) + { + return $value && !is_numeric($value) ? strtotime($value) : $value; + } + + +} diff --git a/application/admin/model/Order.php b/application/admin/model/Order.php new file mode 100644 index 0000000..dca32ee --- /dev/null +++ b/application/admin/model/Order.php @@ -0,0 +1,77 @@ + __('Status 10'), '20' => __('Status 20'), '30' => __('Status 30'), '40' => __('Status 40'), '50' => __('Status 50'), '-10' => __('Status -10'), '-20' => __('Status -20'), '-30' => __('Status -30')]; + } + + public function getCollectList() + { + return ['0' => __('Collect 0'), '1' => __('Collect 1')]; + } + + public function getDispatchTypeList() + { + return ['10' => __('Dispatch_type 10'), '11' => __('Dispatch_type 11'), '20' => __('Dispatch_type 20')]; + } + + + public function getStatusTextAttr($value, $data) + { + $value = $value ?: ($data['status'] ?? ''); + $list = $this->getStatusList(); + return $list[$value] ?? ''; + } + + + public function getCollectTextAttr($value, $data) + { + $value = $value ?: ($data['collect'] ?? ''); + $list = $this->getCollectList(); + return $list[$value] ?? ''; + } + + + public function getDispatchTypeTextAttr($value, $data) + { + $value = $value ?: ($data['dispatch_type'] ?? ''); + $list = $this->getDispatchTypeList(); + return $list[$value] ?? ''; + } + + + + +} diff --git a/application/admin/validate/Command.php b/application/admin/validate/Command.php new file mode 100644 index 0000000..9da8fa6 --- /dev/null +++ b/application/admin/validate/Command.php @@ -0,0 +1,27 @@ + [], + 'edit' => [], + ]; + +} diff --git a/application/admin/validate/Order.php b/application/admin/validate/Order.php new file mode 100644 index 0000000..e0565c2 --- /dev/null +++ b/application/admin/validate/Order.php @@ -0,0 +1,27 @@ + [], + 'edit' => [], + ]; + +} diff --git a/application/admin/view/command/add.html b/application/admin/view/command/add.html new file mode 100644 index 0000000..9374529 --- /dev/null +++ b/application/admin/view/command/add.html @@ -0,0 +1,420 @@ + +
| {:__('Title')} | +{:__('Content')} | +
|---|---|
| {:__('Type')} | +{$row.type}({$row.type_text}) | +
| {:__('Params')} | +{$row.params|htmlentities} | +
| {:__('Command')} | +{$row.command|htmlentities} | +
| {:__('Content')} | ++ + | +
| {:__('Executetime')} | +{$row.executetime|datetime} | +
| {:__('Status')} | +{$row.status_text} | +